*> Drup[1] *commented 5 days ago[2] 
> I created an empty switch last and installed ocaml in it manually. It seems
> ocaml-version is not udpated. % opam install merlin utop tuareg
> [ERROR] utop has unmet availability conditions: ocaml-version >= "4.01"
> [ERROR] merlin has unmet availability conditions: ocaml-version >= "4.00.0"
> % opam switch show
> last
> % opam list -i
> base-bigarray base   Bigarray library distributed with the OCaml compiler
> base-threads  base   Threads library distributed with the OCaml compiler
> base-unix     base   Unix library distributed with the OCaml compiler
> ocaml         4.03.0 Official 4.03.0 release

Ah, this part is lacking documentation, and there may be some rough edges yet 
to polish, so let 
me explain how it works at the moment (on next). And thanks again for testing ☺ 
*How it works* 
So, compilers now being in packages, compiler-specific variables (like 
typically ocaml-version) 
can not generally be defined at switch creation time anymore. However, packages 
have been 
able to export opam variables since opam 1.0 by providing a <pkgname>.config 
file at their root 
(similar to .install; but although this is an older feature it probably lacks 
documentation too). 
These variables, however, are scoped with the package name to avoid clashes: if 
you have foo 
installed, you can always access foo:lib to get its lib directory 
(<prefix>/lib/foo normally), but 
also foo:bar if foo defined bar in its configuration file. 
The idea, then, to keep compatibility with the previously global ocaml-* 
variables, is that /for 
packages installed as compilers/ (/i.e./ "base packages" having the compiler 
flag set), the 
variables they define are re-exported in the global scope of the switch. So the 
ocaml package 
just has to define an ocaml-version variable through its .config file. 
It could be much simpler to define these values in the compiler's opam file, 
but that would be 
assuming they can be statically defined. In particular, in the case of the 
system compiler, the 
package build is simply a polling script that will generate the configuration, 
and we don't know 
the OCaml version in advance (so ocaml-version and ocaml:version can be 
different, with the 
latter being system in this case). Even for compiled OCamls, we might not know 
in advance 
whether native-dynlink is available. 
In your case, ocaml was installed as a "normal" package, so its variables 
weren't re-exported: 
look at files in <switch-prefix>/.opam-switch/config, global-config.config is 
where global 
variables are defined, the other files are per-package. Like we have opam 
install --[un]set-root, 
we probably need expert commands that allow adjusting the defined compiler in 
the current 
switch (you can edit <prefix>/.opam-switch/switch-state easily, but that won't 
do the variable 
export part, and is no excuse for not having it in the CLI anyway). 
*Now let's get to the funny details...* 
The reason to re-export in the global scope rather than use the variable 
directly (after all, we 
could replace uses of ocaml-native-tools with a scoped variable 
ocaml:native-tools, and even 
ocaml-version with ocaml:real-version or something like that) is that there is 
a difference 
between the two: 
     *  package variables are only available in scripts, i.e. for actions 
happening /after/ the solver 
solved
     *  global variables can be used anywhere, and, most importantly, in the 
available: field, 
which is used to filter the packages /before/ solving, and therefore shouldn't 
depend on what 
packages are installed. 
Obviously, ocaml-version is a variable we absolutely want accessible in the 
available: field... so 
we needed to have it in the global scope. 
What this implies, however, is that it's inconsistent to change your compiler 
/and/ non-compiler 
packages in the same set of actions: ocaml-version may be defined incorrectly. 
Currently, we 
do /not/ handle this correctly, however it could happen on:1. upgrade of the 
system compiler2. 
manual change of the switch's compiler (e.g. through pinning) 
I have a plan to solve this situation, which requires solving once, limiting 
the actions to the 
removals and compiler change, processing them, then re-running the solver in 
the new 
environment to complete the expected actions. It's a bit complex to my taste, 
however, and 
means that, by design, the user must validate (and start removing packages) 
before being able 
to know what the expected end state will be. May be acceptable for a compiler 
change, though, 
in 1.2.2, case 1. required a manual, full switch reinstall (that could fail due 
to broken 
constraints, I think), and case 2. was impossible altogether. 
In the current state, the reinstallation of packages following the switch 
change could be tried 
on package unavailable for the new version and fail, and the user will need to 
re-run opam with 
a proper request to get a correct solution and retry to install them. 
*Another solution (or not)* 
Now, if you expected something simpler, you can skip this. More elegant, maybe, 
but not 
simpler. Also (spoiler), this doesn't actually solve the problem of dynamic 
system packages. 
Generally speaking, it would be nicer to be able to write, instead of

available: ocaml-version >= "4.01"
depends: [ "ocaml" >= "4.01" ] 
This allows to pass all the details to the solver, and gets rid of these 
annoying package/global 
variables needed for available:. One issue is that currently, we have a 
mismatch between 
OCaml versions, and the ocaml package versions, which also encode information 
on the variant 
(4.01.0+BER, system). 
The idea here is to rely on the provides: feature, which allows a package to be 
available under 
different names besides its own. This brings a whole lot of difficulties on its 
own, but that will 
be for another time -- I have lots on notes on this too. For the time being, 
let's assume it just 
works. 
Using this, we could have the variants defined in different packages (e.g. 
ocaml+BER), and 
"providing" the ocaml feature with version 4.01.0.This also works for other 
compiler features: 
we currently use two mechanisms, base- packages (e.g. base-threads) that we 
depend on, and 
ocaml- variables (e.g. ocaml-native-dynlink) that we use in scripts (and 
possibly, the available: 
field). Here a given compiler could "provide" native-dynlink and threads as 
packages, and other 
packages directly depend on that. It also seems much more appropriate on a 
package metadata 
point of view, a given compiler implementation /providing/ a set of features. 
What this doesn't solve at all, however, is the system compiler issue, since 
these provides: 
must be defined statically 
*Dynamic packages* 
We've drifted a bit, but the bulk of the issue actually boils down to this: 
dynamic packages, and 
in particular, definition of the system compiler. 
     *  in 1.2.2, polling and generation of a compiler description, as well as 
further polling to 
detect changes, were hard-coded in opam
     *  in 2.0~alpha, there is no OCaml specific code in opam, the polling is 
done by the package 
itself, and the compiler-package-variable-made-global feature bridges the gap 
to the package 
selection 
There may be middle-grounds or alternate solutions: 
     *  somehow allow the definition of dynamic packages in the repository 
(seems complex, 
costly, and most importantly very difficult to do without compromising security 
-- any dynamic 
package would need to do its polling before it was selected by the user in any 
way)
     *  keep the hard-coded generation, but put it in an ocaml plugin added to 
the ocaml-agnostic 
opam. 
Note that having the system package in the repository has some benefits; for 
example, in 1.2.2, 
it is impossible to change its set of base packages, which raised some 
difficulties when base-
ocamlbuild started being needed. 
_______________________________________________
opam-devel mailing list
opam-devel@lists.ocaml.org
http://lists.ocaml.org/listinfo/opam-devel

Reply via email to