diff --git a/Changes b/Changes index aa496dbe..ee52fda5 100644 --- a/Changes +++ b/Changes @@ -94,6 +94,14 @@ detailed changelog below for details. - #202: install license, changes and readme in opam's docdir for `odig` (Gabriel Scherer, request and review by Daniel Bünzli) +* #240: new heuristic for handling the OCAMLLIB environment variable. + `ocamlbuild -where` will ignore OCAMLLIB completely if OCAMLBUILD_LIBDIR is + not a lexical subdirectory of OCAML_LIBDIR (i.e. an opam installation). + Otherwise, it now returns $OCAMLLIB with the difference between + OCAMLBUILD_LIBDIR and OCAML_LIBDIR appended (i.e. for a normal findlib + installation, it now returns $OCAMLLIB/site-lib/ocamlbuild) + (David Allsopp, review by Gabriel Schere) + - "noautolink" tag for ocaml{c,opt} (Gabriel Scherer) diff --git a/configure.make b/configure.make index f77a5885..53d387b7 100644 --- a/configure.make +++ b/configure.make @@ -94,6 +94,8 @@ src/ocamlbuild_config.ml: echo ;\ echo 'let bindir = "$(OCAMLBUILD_BINDIR)"'; \ echo 'let libdir = "$(OCAMLBUILD_LIBDIR)"'; \ + echo 'let ocaml_libdir = "$(abspath $(OCAML_LIBDIR))"'; \ + echo 'let libdir_abs = "$(abspath $(OCAMLBUILD_LIBDIR))"'; \ echo 'let supports_shared_libraries = $(SUPPORTS_SHARED_LIBRARIES)';\ echo 'let a = "$(A)"'; \ echo 'let o = "$(O)"'; \ diff --git a/src/ocamlbuild_where.ml b/src/ocamlbuild_where.ml index cb8b8462..8e151135 100644 --- a/src/ocamlbuild_where.ml +++ b/src/ocamlbuild_where.ml @@ -11,10 +11,40 @@ (* *) (***********************************************************************) -let bindir = ref Ocamlbuild_config.bindir;; +module O = Ocamlbuild_config;; + +let bindir = ref O.bindir;; let libdir = ref begin - Filename.concat - (try Sys.getenv "OCAMLLIB" - with Not_found -> Ocamlbuild_config.libdir) - "ocamlbuild" + let root, suffix = + let ocaml_lib_len = String.length O.ocaml_libdir + 1 in + let lib_len = String.length O.libdir_abs in + (* Windows note: O.ocaml_libdir and O.libdir_abs have both been passed + through GNU make's abspath function and will be forward-slash normalised. + Filename.dir_sep is therefore not appropriate here. *) + if lib_len < ocaml_lib_len + || String.sub O.libdir_abs 0 ocaml_lib_len <> O.ocaml_libdir ^ "/" then + O.libdir, "ocamlbuild" + else + (* https://github.com/ocaml/ocamlbuild/issues/69. Only use OCAMLLIB if + the configured LIBDIR is a subdirectory (lexically) of OCAML_LIBDIR. + If it is, append the difference between LIBDIR and OCAML_LIBDIR to + OCAMLLIB. This allows `OCAMLLIB=/foo ocamlbuild -where` to return + /foo/site-lib/ocamlbuild for a findlib-based installation and also + to ignore OCAMLLIB in an opam-based installation (where setting + OCAMLLIB is already a strange thing to have done). *) + try + let normalise_slashes = + if Sys.os_type = "Win32" then + String.map (function '/' -> '\\' | c -> c) + else + function s -> s + in + let subroot = + String.sub O.libdir_abs ocaml_lib_len (lib_len - ocaml_lib_len) + |> normalise_slashes + in + Sys.getenv "OCAMLLIB", Filename.concat subroot "ocamlbuild" + with Not_found -> O.libdir, "ocamlbuild" + in + Filename.concat root suffix end;;