From e634bdd7038fdef25473b0dabc7d3fd985c3fe21 Mon Sep 17 00:00:00 2001 From: Jeremie Dimino Date: Wed, 24 Feb 2021 17:58:43 +0000 Subject: [PATCH 1/2] Stop calling ocamlfind Signed-off-by: Jeremie Dimino --- CHANGES.md | 4 + bin/install_uninstall.ml | 3 +- doc/usage.rst | 31 +++-- src/dune_rules/context.ml | 34 ++---- .../test-cases/install-libdir.t/run.t | 115 +++++++++--------- 5 files changed, 88 insertions(+), 99 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b988b71ef85..57f659789aa 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -65,6 +65,10 @@ Unreleased - Enable cram tests by default (#4262, @rgrinberg) +- Stop calling `ocamlfind` to determine the library search path or + library installation directory. This makes the behavior of Dune + simpler and more reproducible (#...., @jeremiedimino) + 2.8.2 (21/01/2021) ------------------ diff --git a/bin/install_uninstall.ml b/bin/install_uninstall.ml index 14de4cf0ee0..fd3618b271f 100644 --- a/bin/install_uninstall.ml +++ b/bin/install_uninstall.ml @@ -19,12 +19,11 @@ let get_dirs context ~prefix_from_command_line ~libdir_from_command_line = | None -> let open Fiber.O in let* prefix = Context.install_prefix context in - let libdir = + let+ libdir = match libdir_from_command_line with | None -> Memo.Build.run (Context.install_ocaml_libdir context) | Some l -> Fiber.return (Some (Path.relative prefix l)) in - let+ libdir = libdir in (prefix, libdir) let resolve_package_install setup pkg = diff --git a/doc/usage.rst b/doc/usage.rst index 11f63ef5077..9a3bb84630f 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -1,4 +1,4 @@ -********************** + ********************** Command-line interface ********************** @@ -302,17 +302,24 @@ Finding external libraries When a library is not available in the workspace, dune will look it up in the installed world, and expect it to be already compiled. -It looks up external libraries using a specific list of search paths. A -list of search paths is specific to a given build context and is -determined as follows: - -#. if the ``ocamlfind`` is present in the ``PATH`` of the context, use each line - in the output of ``ocamlfind printconf path`` as a search path -#. otherwise, if ``opam`` is present in the ``PATH``, use the output of ``opam - config var lib`` -#. otherwise, take the directory where ``ocamlc`` was found, and append - ``../lib`` to it. For instance if ``ocamlc`` is found in ``/usr/bin``, use - ``/usr/lib`` +It looks up external libraries using a specific list of search paths +and each build context has a specific list of search paths. + +When running inside an opam environment, Dune will look for installed +libraries in ``$OPAM_SWITCH_PREFIX/lib``. This includes both opam +build context configured via the ``dune-workspace`` file and the +default build context when the variable ``$OPAM_SWITCH_PREFIX`` is +set. + +Otherwise, Dune takes the directory where ``ocamlc`` was found, and +append `../lib`` to it. For instance if ``ocamlc`` is found in +``/usr/bin``, Dune looks for installed libraries in ``/usr/lib``. + +In addition to the two above rules, Dune always inspect the +``OCAMLPATH`` environment variable and use the paths defined in this +variable. ``OCAMLPATH`` always has precedence and can have different +value in different build contexts. For instance, you can set it +manually in a specific build context via the ``dune-workspace`` file. .. _running-tests: diff --git a/src/dune_rules/context.ml b/src/dune_rules/context.ml index a83a807ea68..b56f7eb4b33 100644 --- a/src/dune_rules/context.ml +++ b/src/dune_rules/context.ml @@ -467,7 +467,7 @@ let create ~(kind : Kind.t) ~path ~env ~env_nodes ~name ~merlin ~targets | None -> [] | Some s -> Bin.parse_path s ~sep:ocamlpath_sep in - let default_findlib_paths () = + let default_library_search_path () = match Build_environment_kind.query ~kind ~findlib_toolchain ~env with | Cross_compilation_using_findlib_toolchain toolchain -> let ocamlfind = which_exn "ocamlfind" in @@ -480,13 +480,8 @@ let create ~(kind : Kind.t) ~path ~env ~env_nodes ~name ~merlin ~targets let p = Path.of_filename_relative_to_initial_cwd opam_prefix in let p = Path.relative p "lib" in Memo.Build.return [ p ] - | Unknown -> ( - match which "ocamlfind" with - | Some ocamlfind -> - let env = Env.remove env ~var:"OCAMLPATH" in - ocamlfind_printconf_path ~env ~ocamlfind ~toolchain:None - | None -> - Memo.Build.return [ Path.relative (Path.parent_exn dir) "lib" ] ) + | Unknown -> + Memo.Build.return [ Path.relative (Path.parent_exn dir) "lib" ] in let ocaml_config_ok_exn = function | Ok x -> x @@ -500,7 +495,7 @@ let create ~(kind : Kind.t) ~path ~env ~env_nodes ~name ~merlin ~targets User_error.raise ~loc:(Loc.in_file file) [ Pp.text msg ] in let* default_ocamlpath, (ocaml_config_vars, ocfg) = - Memo.Build.fork_and_join default_findlib_paths (fun () -> + Memo.Build.fork_and_join default_library_search_path (fun () -> let+ lines = Memo.Build.of_fiber (Process.run_capture_lines ~env Strict ocamlc [ "-config" ]) @@ -885,25 +880,10 @@ module DB = struct end let install_ocaml_libdir t = - match (t.kind, t.findlib_toolchain, Setup.library_destdir) with - | Default, None, Some d -> + match (t.kind, Setup.library_destdir) with + | Default, Some d -> Memo.Build.return (Some (Path.of_filename_relative_to_initial_cwd d)) - | _ -> ( - (* If ocamlfind is present, it has precedence over everything else. *) - match t.which "ocamlfind" with - | Some fn -> - let+ s = - Memo.Build.of_fiber - (Process.run_capture_line ~env:t.env Strict fn - [ "printconf"; "destdir" ]) - in - let s = String.trim s in - if String.is_empty s then - (* This case happens if ocamlfind doesn't find its configuration file *) - None - else - Some (Path.of_filename_relative_to_initial_cwd s) - | None -> Memo.Build.return None ) + | _ -> Memo.Build.return None let compiler t (mode : Mode.t) = match mode with diff --git a/test/blackbox-tests/test-cases/install-libdir.t/run.t b/test/blackbox-tests/test-cases/install-libdir.t/run.t index 2c511b66a22..d035db7d98e 100644 --- a/test/blackbox-tests/test-cases/install-libdir.t/run.t +++ b/test/blackbox-tests/test-cases/install-libdir.t/run.t @@ -85,56 +85,55 @@ If prefix is passed, the default for libdir is `$prefix/lib`: Creating directory install/man/man3 Copying _build/install/default/man/man3/another-man-page.3 to install/man/man3/another-man-page.3 (executable: false) -If prefix is not passed, libdir defaults to the output of `ocamlfind printconf -destdir`: +If prefix is not passed, libdir defaults to the opam-prefix/lib directory: $ (export OCAMLFIND_DESTDIR=/OCAMLFIND_DESTDIR > dune install --dry-run 2>&1 | dune_cmd sanitize > dune uninstall --dry-run 2>&1 | dune_cmd sanitize) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/META - Installing /OCAMLFIND_DESTDIR/foo/META - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/META to /OCAMLFIND_DESTDIR/foo/META (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/dune-package - Installing /OCAMLFIND_DESTDIR/foo/dune-package - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/dune-package to /OCAMLFIND_DESTDIR/foo/dune-package (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo$ext_lib - Installing /OCAMLFIND_DESTDIR/foo/foo$ext_lib - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo$ext_lib to /OCAMLFIND_DESTDIR/foo/foo$ext_lib (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cma - Installing /OCAMLFIND_DESTDIR/foo/foo.cma - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo.cma to /OCAMLFIND_DESTDIR/foo/foo.cma (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmi - Installing /OCAMLFIND_DESTDIR/foo/foo.cmi - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo.cmi to /OCAMLFIND_DESTDIR/foo/foo.cmi (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmt - Installing /OCAMLFIND_DESTDIR/foo/foo.cmt - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo.cmt to /OCAMLFIND_DESTDIR/foo/foo.cmt (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmx - Installing /OCAMLFIND_DESTDIR/foo/foo.cmx - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo.cmx to /OCAMLFIND_DESTDIR/foo/foo.cmx (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmxa - Installing /OCAMLFIND_DESTDIR/foo/foo.cmxa - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo.cmxa to /OCAMLFIND_DESTDIR/foo/foo.cmxa (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.ml - Installing /OCAMLFIND_DESTDIR/foo/foo.ml - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo.ml to /OCAMLFIND_DESTDIR/foo/foo.ml (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/opam - Installing /OCAMLFIND_DESTDIR/foo/opam - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/opam to /OCAMLFIND_DESTDIR/foo/opam (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmxs - Installing /OCAMLFIND_DESTDIR/foo/foo.cmxs - Creating directory /OCAMLFIND_DESTDIR/foo - Copying _build/install/default/lib/foo/foo.cmxs to /OCAMLFIND_DESTDIR/foo/foo.cmxs (executable: true) + Removing (if it exists) /OPAM_PREFIX/lib/foo/META + Installing /OPAM_PREFIX/lib/foo/META + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/META to /OPAM_PREFIX/lib/foo/META (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/dune-package + Installing /OPAM_PREFIX/lib/foo/dune-package + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/dune-package to /OPAM_PREFIX/lib/foo/dune-package (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo$ext_lib + Installing /OPAM_PREFIX/lib/foo/foo$ext_lib + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo$ext_lib to /OPAM_PREFIX/lib/foo/foo$ext_lib (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cma + Installing /OPAM_PREFIX/lib/foo/foo.cma + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo.cma to /OPAM_PREFIX/lib/foo/foo.cma (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmi + Installing /OPAM_PREFIX/lib/foo/foo.cmi + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo.cmi to /OPAM_PREFIX/lib/foo/foo.cmi (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmt + Installing /OPAM_PREFIX/lib/foo/foo.cmt + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo.cmt to /OPAM_PREFIX/lib/foo/foo.cmt (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmx + Installing /OPAM_PREFIX/lib/foo/foo.cmx + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo.cmx to /OPAM_PREFIX/lib/foo/foo.cmx (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmxa + Installing /OPAM_PREFIX/lib/foo/foo.cmxa + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo.cmxa to /OPAM_PREFIX/lib/foo/foo.cmxa (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.ml + Installing /OPAM_PREFIX/lib/foo/foo.ml + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo.ml to /OPAM_PREFIX/lib/foo/foo.ml (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/opam + Installing /OPAM_PREFIX/lib/foo/opam + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/opam to /OPAM_PREFIX/lib/foo/opam (executable: false) + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmxs + Installing /OPAM_PREFIX/lib/foo/foo.cmxs + Creating directory /OPAM_PREFIX/lib/foo + Copying _build/install/default/lib/foo/foo.cmxs to /OPAM_PREFIX/lib/foo/foo.cmxs (executable: true) Removing (if it exists) /OPAM_PREFIX/bin/exec Installing /OPAM_PREFIX/bin/exec Creating directory /OPAM_PREFIX/bin @@ -151,17 +150,17 @@ destdir`: Installing /OPAM_PREFIX/man/man3/another-man-page.3 Creating directory /OPAM_PREFIX/man/man3 Copying _build/install/default/man/man3/another-man-page.3 to /OPAM_PREFIX/man/man3/another-man-page.3 (executable: false) - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/META - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/dune-package - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo$ext_lib - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cma - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmi - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmt - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmx - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmxa - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.ml - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/opam - Removing (if it exists) /OCAMLFIND_DESTDIR/foo/foo.cmxs + Removing (if it exists) /OPAM_PREFIX/lib/foo/META + Removing (if it exists) /OPAM_PREFIX/lib/foo/dune-package + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo$ext_lib + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cma + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmi + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmt + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmx + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmxa + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.ml + Removing (if it exists) /OPAM_PREFIX/lib/foo/opam + Removing (if it exists) /OPAM_PREFIX/lib/foo/foo.cmxs Removing (if it exists) /OPAM_PREFIX/bin/exec Removing (if it exists) /OPAM_PREFIX/man/a-man-page-with-no-ext Removing (if it exists) /OPAM_PREFIX/man/man1/a-man-page.1 @@ -169,8 +168,8 @@ destdir`: Removing directory (if empty) /OPAM_PREFIX/man/man3 Removing directory (if empty) /OPAM_PREFIX/man/man1 Removing directory (if empty) /OPAM_PREFIX/man + Removing directory (if empty) /OPAM_PREFIX/lib/foo Removing directory (if empty) /OPAM_PREFIX/bin - Removing directory (if empty) /OCAMLFIND_DESTDIR/foo If only libdir is passed, binaries are installed under prefix/bin and libraries in libdir: From e8cb888b05d4a6396f416a1688e4102ee431c091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Dimino?= Date: Thu, 25 Feb 2021 09:02:27 +0000 Subject: [PATCH 2/2] Update doc/usage.rst --- doc/usage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/usage.rst b/doc/usage.rst index 9a3bb84630f..da372ae67cf 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -1,4 +1,4 @@ - ********************** +********************** Command-line interface **********************