caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: "François Bobot" <francois.bobot@cea.fr>
To: Gerd Stolpmann <info@gerd-stolpmann.de>
Cc: OCaml Mailing List <caml-list@inria.fr>
Subject: Re: [Caml-list] Dependencies between plugins
Date: Wed, 04 Mar 2015 10:58:09 +0100	[thread overview]
Message-ID: <54F6D731.3090004@cea.fr> (raw)
In-Reply-To: <1425394551.4056.1.camel@thinkpad.lan.sumadev.de>

[-- Attachment #1: Type: text/plain, Size: 3269 bytes --]

On 03/03/2015 15:55, Gerd Stolpmann wrote:
> Am Dienstag, den 03.03.2015, 14:15 +0100 schrieb François Bobot:
>> Gerd, do you think that something that does that could be added to ocamlfind? One tricky thing is to
>> know the library statically linked (ie. `Ocsigen_config.builtin_packages`), perhaps ocamlfind can
>> during linking add this information.
>
> I think so. For toploops, there is already code that tracks libraries
> already linked into the executable (i.e. if you ocamlmktop your
> toploop).

All was already in place indeed! It was easy to add. I kept caml-list in CC for discussing the big 
picture in order to get comments from people. Is mail still your preferred way of receiving patch?

I kept it simple, no hack (no automatic: cmxa -> cmxs) because I prefer problems in library META to 
be found than to be paper over.

The first patch adds:
- A library `findlib.dynlink` that depends on `findlib` and `dynlink`
- During linking (using `ocamlfind ocaml*`) if `-package findlib.dynlink` and `-linkpkg` are used 
then a module `Findlib_initl...` is linked after all packages and it stores the names of packages 
linked in `Findlib.linked_packages`.
- In the main program `Fl_dynlink.load_packages ["yojson"]` can be used to dynlink packages

The second patch forbids to run `Fl_dynlink.load_packages` during the initialization of packages 
(statically or dynamically linked), because `Findlib_initl...` is not yet run and because if you 
want to load a package that depend on a statically linked package not yet initialized, there is no 
sane semantic.

Problems:
- The package is named `findlib.dynlink`, the archive `findlib_dynlink.cm*` and the module 
`Fl_dynlink` ...
- If you don't use `-linkall` static packages could only be partially linked, and you can't link the 
remaining part later. So perhaps `-linkall` must be automatically added if `findlib.dynlink` is used.
- If you define `archive(native)` and not `archive(native,plugin)` the error is not nice (in 
Dynlink.Error). Perhaps I should add a `Package_not_dynamically_loadable of string` error, that 
should catch the loading of something else than `*.cmxs`.
- Often you link your binary with your own library without using `-package` (the library is not yet 
installed), and plugins for your tools depend on your library. Currently you should do before any 
`Fl_dynlink.load_packages`: `Findlib.linked_packages := "mylib"::Findlib.linked_packages`. For 
simplicity, I don't know if I should add a function `Fl_dynlink.add_linked_packages`, or an option 
to ocamlfind `-additional-package-statically-linked `.
- During the initialization of your own library (linked without -package) you should not use 
`Fl_dynlink.load_packages`, but the library doesn't protect you against this error.

Choices:
- If you don't link with `findlib.dynlink` or use `create_toploop`, the variables 
`Findlib.linked_packages` and `Findlib.linked_predicates` are empty because I don't wanted to add 
backward change by adding `Findlib_initl...` when `findlib` is linked.


Remains to do:
- Fix problems
- Documentations (add `plugin` in the list of standard predicates, ...)


Gerg, what do you think of this first version of the patch? Of the way to fix the problems?

Thanks,

Regards,

-- 
François

[-- Attachment #2: 0001-Dynlink-add-utilities-for-dynamic-linking-packages.patch --]
[-- Type: text/x-diff, Size: 7795 bytes --]

From ce9c7aab9b883a7130ce1b350583c79365e82423 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois.bobot@cea.fr>
Date: Tue, 3 Mar 2015 23:50:00 +0100
Subject: [PATCH 1/2] [Dynlink] add utilities for dynamic linking packages

---
 src/findlib/META.in        | 10 ++++++++++
 src/findlib/Makefile       | 19 ++++++++++++++++---
 src/findlib/findlib.ml     |  4 ++++
 src/findlib/findlib.mli    |  7 +++++++
 src/findlib/fl_dynlink.ml  | 25 +++++++++++++++++++++++++
 src/findlib/fl_dynlink.mli |  9 +++++++++
 src/findlib/frontend.ml    | 13 ++++++++-----
 7 files changed, 79 insertions(+), 8 deletions(-)
 create mode 100644 src/findlib/fl_dynlink.ml
 create mode 100644 src/findlib/fl_dynlink.mli

diff --git a/src/findlib/META.in b/src/findlib/META.in
index e19bcad..859bcc7 100644
--- a/src/findlib/META.in
+++ b/src/findlib/META.in
@@ -6,3 +6,13 @@ archive(byte) = "findlib.cma"
 archive(byte,toploop) = "findlib.cma findlib_top.cma"
 archive(byte,create_toploop) = "findlib.cma findlib_top.cma"
 archive(native) = "findlib.cmxa"
+
+package "dynlink" (
+  description = "Package manager dynamic linker"
+  requires = "findlib dynlink"
+  archive(byte) = "findlib_dynlink.cma"
+  archive(native) = "findlib_dynlink.cmxa"
+#Even if it strange and discouraged to dynlink this package
+  archive(byte,plugin) = "findlib_dynlink.cma"
+  archive(native,plugin) = "findlib_dynlink.cmxs"
+)
\ No newline at end of file
diff --git a/src/findlib/Makefile b/src/findlib/Makefile
index bdd7f14..cbfec7b 100644
--- a/src/findlib/Makefile
+++ b/src/findlib/Makefile
@@ -28,14 +28,18 @@ TOBJECTS       = topfind.cmo
 
 XOBJECTS       = $(OBJECTS:.cmo=.cmx)
 
+OBJECTS_DYNLINK  = fl_dynlink.cmo
+XOBJECTS_DYNLINK = $(OBJECTS_DYNLINK:.cmo=.cmx)
+
 OCAMLFIND_OBJECTS = ocaml_args.cmo frontend.cmo
 OCAMLFIND_XOBJECTS = ocaml_args.cmx frontend.cmx
 
 NUMTOP_OBJECTS = num_top_printers.cmo num_top.cmo
 
-all: ocamlfind$(EXEC_SUFFIX) findlib.cma findlib_top.cma topfind num_top.cma
+all: ocamlfind$(EXEC_SUFFIX) findlib.cma findlib_top.cma topfind num_top.cma \
+     findlib_dynlink.cma
 
-opt: ocamlfind_opt$(EXEC_SUFFIX) findlib.cmxa topfind
+opt: ocamlfind_opt$(EXEC_SUFFIX) findlib.cmxa findlib_dynlink.cmxa topfind
 
 ocamlfind$(EXEC_SUFFIX): findlib.cma $(OCAMLFIND_OBJECTS)
 	$(OCAMLC) $(CUSTOM) -o ocamlfind$(EXEC_SUFFIX) -g findlib.cma unix.cma \
@@ -60,6 +64,15 @@ findlib.cmxa: $(XOBJECTS)
 	    $(OCAMLOPT) -shared -o findlib.cmxs $(XOBJECTS); \
 	fi
 
+findlib_dynlink.cma: $(OBJECTS_DYNLINK)
+	$(OCAMLC) -a -o $@ $(OBJECTS_DYNLINK)
+
+findlib_dynlink.cmxa: $(XOBJECTS_DYNLINK)
+	$(OCAMLOPT) -a -o $@ $(XOBJECTS_DYNLINK)
+	if [ $(HAVE_NATDYNLINK) -gt 0 ]; then \
+	    $(OCAMLOPT) -shared -o findlib_dynlink.cmxs $(XOBJECTS_DYNLINK); \
+	fi
+
 findlib_config.ml: findlib_config.mlp $(TOP)/Makefile.config
 	USE_CYGPATH="$(USE_CYGPATH)"; \
 	export USE_CYGPATH; \
@@ -100,7 +113,7 @@ install: all
 	mkdir -p "$(prefix)$(OCAML_SITELIB)/$(NAME)"
 	mkdir -p "$(prefix)$(OCAMLFIND_BIN)"
 	test $(INSTALL_TOPFIND) -eq 0 || cp topfind "$(prefix)$(OCAML_CORE_STDLIB)"
-	files=`$(TOP)/tools/collect_files $(TOP)/Makefile.config findlib.cmi findlib.mli findlib.cma topfind.cmi topfind.mli fl_package_base.mli fl_package_base.cmi fl_metascanner.mli fl_metascanner.cmi fl_metatoken.cmi findlib_top.cma findlib.cmxa findlib.a findlib.cmxs META` && \
+	files=`$(TOP)/tools/collect_files $(TOP)/Makefile.config findlib.cmi findlib.mli findlib.cma topfind.cmi topfind.mli fl_package_base.mli fl_package_base.cmi fl_metascanner.mli fl_metascanner.cmi fl_metatoken.cmi findlib_top.cma findlib.cmxa findlib.a findlib.cmxs findlib_dynlink.cma findlib_dynlink.cmxa findlib_dynlink.a findlib_dynlink.cmxs fl_dynlink.mli fl_dynlink.cmi META` && \
 	cp $$files "$(prefix)$(OCAML_SITELIB)/$(NAME)"
 	f="ocamlfind$(EXEC_SUFFIX)"; { test -f ocamlfind_opt$(EXEC_SUFFIX) && f="ocamlfind_opt$(EXEC_SUFFIX)"; }; \
 	cp $$f "$(prefix)$(OCAMLFIND_BIN)/ocamlfind$(EXEC_SUFFIX)"
diff --git a/src/findlib/findlib.ml b/src/findlib/findlib.ml
index 2b1aa2c..75e2ae1 100644
--- a/src/findlib/findlib.ml
+++ b/src/findlib/findlib.ml
@@ -427,3 +427,7 @@ let list_packages ?(tab = 20) ?(descr = false) ch =
     )
     packages_sorted
 ;;
+
+
+let linked_packages = ref []
+let linked_predicates = ref []
diff --git a/src/findlib/findlib.mli b/src/findlib/findlib.mli
index d435a84..6ef5cc9 100644
--- a/src/findlib/findlib.mli
+++ b/src/findlib/findlib.mli
@@ -193,3 +193,10 @@ val list_packages : ?tab:int -> ?descr:bool -> out_channel -> unit
    * @param tab The tabulator width, by default 20
    * @param descr Whether package descriptions are printed. Default: false
    *)
+
+val linked_packages : string list ref
+ (** The list of currently linked packages.
+     The packages can be absent of the database *)
+
+val linked_predicates : string list ref
+(** The list of predicates used during linking (eg. native, byte, mt, ...) *)
diff --git a/src/findlib/fl_dynlink.ml b/src/findlib/fl_dynlink.ml
new file mode 100644
index 0000000..b64b617
--- /dev/null
+++ b/src/findlib/fl_dynlink.ml
@@ -0,0 +1,25 @@
+
+(** Utilities for loading dynamically packages *)
+
+let load_pkg pkg =
+  if not (List.mem pkg !Findlib.linked_packages) then
+    (* Determine the package directory: *)
+    let d = Findlib.package_directory pkg in
+    (* Determine the 'archive(plugin,...)' property: *)
+    let archive =
+      try
+        Findlib.package_property ("plugin"::!Findlib.linked_predicates) pkg "archive"
+      with Not_found -> "" in
+    (* Split the 'archive' property and resolve the files: *)
+    let files = Fl_split.in_words archive in
+    List.iter (fun file ->
+        let file = Findlib.resolve_path ~base:d file in
+        Dynlink.loadfile file
+      ) files;
+    Findlib.linked_packages := pkg::!Findlib.linked_packages
+
+let load_packages pkgs =
+  let eff_pkglist =
+    Findlib.package_deep_ancestors !Findlib.linked_predicates pkgs in
+  List.iter load_pkg eff_pkglist
+
diff --git a/src/findlib/fl_dynlink.mli b/src/findlib/fl_dynlink.mli
new file mode 100644
index 0000000..1109442
--- /dev/null
+++ b/src/findlib/fl_dynlink.mli
@@ -0,0 +1,9 @@
+(* $Id$
+ * ----------------------------------------------------------------------
+ *
+ *)
+
+(** Utilities for loading dynamically packages *)
+
+val load_packages : string list -> unit
+(** Dynlink the given packages and all their dependencies *)
diff --git a/src/findlib/frontend.ml b/src/findlib/frontend.ml
index 2e00ccd..82b95b6 100644
--- a/src/findlib/frontend.ml
+++ b/src/findlib/frontend.ml
@@ -1148,8 +1148,11 @@ let ocamlc which () =
   let threads_dir = Filename.concat stdlibdir "threads" in
   let vmthreads_dir = Filename.concat stdlibdir "vmthreads" in
 
-  let initl_file_needed =
+  let create_toploop =
     List.mem "create_toploop" !predicates && List.mem "findlib" eff_link in
+  let initl_file_needed =
+    create_toploop || List.mem "findlib.dynlink" eff_link
+  in
 
   let initl_file_name =
     if initl_file_needed then
@@ -1170,19 +1173,19 @@ let ocamlc which () =
 		  initl_file_name in
     try
       output_string initl
-	("Topfind.don't_load [" ^
+	("Findlib.linked_packages := [" ^
 	 String.concat ";"
 	   (List.map
 	      (fun pkg -> "\"" ^ String.escaped pkg ^ "\"")
 	      eff_link) ^
 	 "];;\n");
+      let predicates = List.filter (fun p -> p <> "create_toploop") !predicates in
       output_string initl
-	("Topfind.predicates := [" ^
+	("Findlib.linked_predicates := [" ^
 	 String.concat ";"
 	   (List.map
 	      (fun pred -> "\"" ^ String.escaped pred ^ "\"")
-	      ("toploop" :: 
-		 (List.filter (fun p -> p <> "create_toploop") !predicates))) ^
+	      (if create_toploop then "toploop" :: predicates else predicates)) ^
 	 "];;\n");
       close_out initl;
     with
-- 
2.1.4


[-- Attachment #3: 0002-Dynlink-forbid-package-loading-when-we-are-currently.patch --]
[-- Type: text/x-diff, Size: 2868 bytes --]

From 5015566e762420fb4bfcdce1ba22f1bbbaff4212 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Bobot?= <francois.bobot@cea.fr>
Date: Wed, 4 Mar 2015 09:49:11 +0100
Subject: [PATCH 2/2] [Dynlink] forbid package loading when we are currently   
        initializing a package

---
 src/findlib/fl_dynlink.ml  | 28 ++++++++++++++++++++++++----
 src/findlib/fl_dynlink.mli | 13 ++++++++++++-
 2 files changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/findlib/fl_dynlink.ml b/src/findlib/fl_dynlink.ml
index b64b617..78c688c 100644
--- a/src/findlib/fl_dynlink.ml
+++ b/src/findlib/fl_dynlink.ml
@@ -1,6 +1,15 @@
 
 (** Utilities for loading dynamically packages *)
 
+exception Package_loading
+
+let package_loading = ref false
+let is_package_loading () =
+  (** At least "findlib.dynlink" should be in the list if Findlib_initl has
+      been run. Otherwise we are running statically linked package  *)
+  !Findlib.linked_packages = []
+  || !package_loading
+
 let load_pkg pkg =
   if not (List.mem pkg !Findlib.linked_packages) then
     (* Determine the package directory: *)
@@ -8,7 +17,8 @@ let load_pkg pkg =
     (* Determine the 'archive(plugin,...)' property: *)
     let archive =
       try
-        Findlib.package_property ("plugin"::!Findlib.linked_predicates) pkg "archive"
+        Findlib.package_property
+          ("plugin"::!Findlib.linked_predicates) pkg "archive"
       with Not_found -> "" in
     (* Split the 'archive' property and resolve the files: *)
     let files = Fl_split.in_words archive in
@@ -19,7 +29,17 @@ let load_pkg pkg =
     Findlib.linked_packages := pkg::!Findlib.linked_packages
 
 let load_packages pkgs =
-  let eff_pkglist =
-    Findlib.package_deep_ancestors !Findlib.linked_predicates pkgs in
-  List.iter load_pkg eff_pkglist
+  if is_package_loading () then
+    raise Package_loading
+  else begin
+    package_loading := true;
+    try
+      let eff_pkglist =
+        Findlib.package_deep_ancestors !Findlib.linked_predicates pkgs in
+      List.iter load_pkg eff_pkglist ;
+      package_loading := false;
+    with exn ->
+      package_loading := false;
+      raise exn
+  end
 
diff --git a/src/findlib/fl_dynlink.mli b/src/findlib/fl_dynlink.mli
index 1109442..a615486 100644
--- a/src/findlib/fl_dynlink.mli
+++ b/src/findlib/fl_dynlink.mli
@@ -5,5 +5,16 @@
 
 (** Utilities for loading dynamically packages *)
 
+exception Package_loading
+(** Indicate that during the loading of a package the loading of another
+    package have been requested *)
+
 val load_packages : string list -> unit
-(** Dynlink the given packages and all their dependencies *)
+(** Dynlink the given packages and all their dependencies;
+    Call can't be nested.
+    @raise Package_loading
+*)
+
+
+val is_package_loading: unit -> bool
+(** Indicate if we are currently loading a package *)
-- 
2.1.4


  reply	other threads:[~2015-03-04  9:58 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-03 13:15 François Bobot
2015-03-03 13:40 ` Gabriel Scherer
2015-03-03 14:23   ` François Bobot
2015-03-03 14:31     ` Maxence Guesdon
2015-03-03 14:32     ` Ivan Gotovchits
2015-03-03 14:42       ` Sebastien Mondet
2015-03-03 15:02         ` François Bobot
2015-03-03 15:24           ` Sebastien Mondet
2015-03-03 14:51       ` François Bobot
2015-03-03 14:55 ` Gerd Stolpmann
2015-03-04  9:58   ` François Bobot [this message]
2015-04-13 19:27     ` Ivan Gotovchits
2015-04-13 19:29       ` Gerd Stolpmann
2015-04-14  8:59         ` François Bobot
2015-04-14  9:47           ` Stéphane Glondu
2015-04-14 12:45             ` François Bobot
2015-04-27  9:51               ` Gerd Stolpmann
2015-04-27 10:16                 ` Gabriel Scherer
2015-04-27 12:16                   ` François Bobot
2015-04-27 12:32                     ` Daniel Bünzli
2015-04-29 12:00                   ` Gerd Stolpmann
2015-04-27 11:55                 ` François Bobot
     [not found]   ` <1735_1425463114_54F6D748_1735_16789_8_54F6D731.3090004@cea.fr>
2015-03-06 11:45     ` François Bobot
2015-04-14 12:21 ` Gabriel Kerneis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=54F6D731.3090004@cea.fr \
    --to=francois.bobot@cea.fr \
    --cc=caml-list@inria.fr \
    --cc=info@gerd-stolpmann.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).