Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop calling ocamlfind to determine the library search/installation directory #4281

Merged
2 commits merged into from Feb 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
------------------

Expand Down
3 changes: 1 addition & 2 deletions bin/install_uninstall.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
29 changes: 18 additions & 11 deletions doc/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
34 changes: 7 additions & 27 deletions src/dune_rules/context.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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" ])
Expand Down Expand Up @@ -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
Expand Down
115 changes: 57 additions & 58 deletions test/blackbox-tests/test-cases/install-libdir.t/run.t
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -151,26 +150,26 @@ 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
Removing (if it exists) /OPAM_PREFIX/man/man3/another-man-page.3
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:
Expand Down