[1/3] Restructure LIBDIR: Move Dynlink, Str and Unix to sub-directories#11198
[1/3] Restructure LIBDIR: Move Dynlink, Str and Unix to sub-directories#11198dra27 merged 4 commits intoocaml:trunkfrom
Conversation
…rt part of ocaml/PR11198) (#1094) Port part of ocaml/ocaml#11198
…rt part of ocaml/PR11198) (#1094) Port part of ocaml/ocaml#11198
…b-directories (port part of ocaml/PR11198) (#1094) Port part of ocaml/ocaml#11198
|
I just observed the following interaction in the OCaml toplevel which I think is a bit confusing for non-experts. $ ocaml
OCaml version 5.0.0
Enter #help;; for help.
# Unix.sleep 1;;
Alert ocaml_deprecated_auto_include:
OCaml's lib directory layout changed in 5.0. The unix subdirectory has been
automatically added to the search path, but you should add -I +unix to the
command-line to silence this alert (e.g. by adding unix to the list of
libraries in your dune file, or adding use_unix to your _tags file for
ocamlbuild, or using -package unix for ocamlfind).
Error: Reference to undefined global `Unix'Is there something easy we can do to give better advice here? Note: I you start with |
|
The easy way in the toplevel is rather |
|
I'm not sure we should have the compiler recommend a command which requires findlib, though? In this particular case, I think what might be wanted is not to display the alert? |
|
I've not double-checked, but I think we'd be able to defer displaying the alert for long enough in the toplevel that we'd have the undefined global case already. The alert does want to be displayed if you do something like |
|
I think that having an alert in itself is fine? The toplevel user that uses low-level (aka not-library-aware) commands ought to first add the |
|
My thinking is that the code is already an error in 4.x, the alert is meant to warn that accidental use of the types might become an error in future? |
|
i.e. that the alert is displayed only in cases where OCaml 4.x would not have displayed anything, because it silently worked (because |
|
I think that having a strange and unexplained difference between |
|
Oops, yes, I follow your point now. It feels bad to me for us to recommend a directive when it isn't present (I'm sure there are still plenty of first-time users who run the |
|
As we see sometimes trying to be smart makes things more confusing. Why not simply let it go without crazy special casing ? There's release notes to document these changes. |
Just my 2c: personally I am also of the opinion that the "automatic" include logic is not worth the hassle. |
|
That's be the target, yes - but I'm not sure we can get away with completing a deprecation made in 5.0 in 5.1? I was intending - as with all new deprecations - to check when 5.1 is branched how many packages would still fail if this were made a hard error (and do another round of PRs, like the list above). |
|
My thinking:
|
|
It was able to do that for 5.0 because it's not used for executing scripts in the same way as |
This sounds like a good idea to me. |
This PR is the first and main PR of a brave (in the Apple sense) series of changes which seek to separate the components in OCaml's
$LIBDIR. This PR specifically moves the Dynlink, Str and Unix libraries into sub-directories of$LIBDIR. The idea of the change was provisionally agreed at the last developers' meeting.The motivation for this change is hygiene in build systems: at present, it is very difficult to impossible for Dune (for example) to ensure that a library specifies its dependency on the Unix library.
The change itself is quite simple, and in the first commit. A small tweak to two
Makefiles ensures the libraries are installed to their new locations. Any previous artefacts are removed (cf. #1724, #1728 and #10301, noting that the removal of artefacts is "precise" w.r.t. basenames).That change on its own is very breaking, of course.
The rest of the commits relate to backwards compatibility. The compilers, toplevel and debugger will all automatically add the required include path to the load path, but display an alert for each directory as this happens. For example:
or similarly with:
In implementing this alert, I've attempted to avoid penalising code which has specified the appropriate include directories, especially as we know that the load path is a relatively "hot" part of the build for some users. The mechanism I've gone for is to add an extra attempt around
Load_path.findandLoad_path.find_uncapfor the case when there is an actual miss on the load path. In almost all cases, a miss on the load path is fatal. The exceptions are#remove_directoryin the toplevel and gaining inlining information from.cmxfiles when linking inocamlopt, so at less critical stages. The toplevel, compilers and debugger add"+dynlink","+str"and"+unix"to a "secondary" load path which is lazily scanned on the first miss on the normal load path. If the file being searched (sayunix.cmaandunix.cmi) is found, then that directory's entries are promoted to the main load path, and the fact that this took place is recorded. From the user's perspective in, say, the toplevel what happens at#load "unix.cma"is as if the user issued#directory "+unix"and then tried the#loadagain.Load_pathis very low-down the dependency graph of compiler-libs, so rather than displaying alerts itself, it simply maintains a list of directories which have been automatically added. This list is queried by functions added with the other alert functions in, ahem,Location.The initialisation code is a duplicated between the debugger, driver and toplevel. It's not huge, but I'm not sure exactly where to put a function to do that - how averse are we to adding modules to ocamlcommon?
Another option might be to install the files in both places, but this isn't a silver bullet either - including the new directory can cause warnings in some tools (
ocamlfinddoesn't like finding.cmifiles in multiple directories, for one) and it seems to be harder to record the need to display an alert without altering main load path data structure, which is a much more intimidating prospect than altering an error path.Very similar work was previously attempted and abandoned in #1569. This work differs both in implementation and timing in a few ways which hopefully means we can reach a consensus on merging it this time. The key differences:
I have tested this change quite extensively on 4.14 - in many cases, the packages affected are already lying to their build systems. Dune and ocamlbuild users, for example, should not use
Unixwithout havingunixin theirlibrariesstanza oruse_unixin their_tagsfile. Even packages building directly withocamlfindshould include-package unixin the command-line. These packages can be fixed regardless of whether this PR is merged. Given a flurry of PRs now with this change (these packages can merge these updates regardless of whether this PR is accepted), I imagine that by OCaml 5.2, the number of packages still displaying this alert will be close to zero and the entire mechanism can then be reverted - at which point this change lives entirely in the build system.There are other packages which contain commands of the form
ocaml unix.cmawhich want to becomeocaml -I +unix unix.cma- PRs are opened for these as well.There are three possible pieces of future work which I haven't done yet, mainly because they are more philosophical (separating the otherlibs out mitigates actual issues):
$LIBDIR(this is already the case for systhreads, so this is partially done to stay consistent). This could be trivially fixed for all these, but it could be viewed as separate. Note that at present we're saying that-L /usr/lib/ocamlis all you need to give to link in C. I can't remember the reference, but there's at least one application in the wild which links manually with our C stub libraries, because I remember dealing with a bug report relating to it...std_exit.cmoandstd_exit.cmxremain, despite the fact these are really part of the compiler, and not the Standard Library. The compilers impose a requirement that a standard library replacement implements a function called do_at_exit, but the actual implementation of std_exit is part of the compiler, not the stdlib. Indeed, in many ways there's no need for a module calledStd_exitat all, we could generate a temporary file.+runtimeor the stdlib in+stdlib. FWIW, I would advocate the latter -lib/ocamlnow reflects the files of the OCaml runtime and compiler with the sub-directories all being libraries. But that can readily be for another day and another release...