I’ve just released opam-0install 0.1, a faster solver for opam dependencies.
Opam’s default solver is designed to maintain a set of packages over time, minimising disruption when installing new programs and finding a compromise solution across all packages (e.g. avoiding upgrading some library to prevent uninstalling another program).
In many situations (e.g. a CI system building in a clean environment, a project-local opam root, or a duniverse build) this is not necessary, and we can get a solution much faster by using a different algorithm.
opam-0install does that by using 0install’s (pure OCaml) solver with opam packages. It is currently being used in several places:
- I’m using it in ocaml-ci to find package combinations to test.
- @kit-ty-kate is using it in http://check.ocamllabs.io/, replacing the z3 solver.
- @avsm is using it in duniverse.
make test runs some solves using the default opam solver and the new 0install one, and compares the results. On my machine, I get:
I’ve only shown the first few tests, which are somewhat cherry-picked. After that, it starts picking packages at random, and the results aren’t quite so biased
When 0install and opam find different solutions, it should always be the case that 0install’s solution is better for at least one component (but it could be worse for several). Surprisingly, it seems that the reverse is not true. In the screenshot above, opam’s solution for irmin.0.10.0 appears to be strictly worse than 0install’s choice.
The most common reason for finding different solutions is to do with jbuilder. The “best” version of jbuilder is
jbuilder.transition, which depends on dune 1 (and conflicts with dune 2). 0install will often pick this “best” version of jbuilder, which then forces dune < 2 and older versions of other packages. You can avoid this in your own packages by listing your dune dependency before whatever depends on jbuilder, since 0install optimises components in order. Of course, if you require a package that needs dune 2 then that will also force the issue.
It’s also possible that I’m not using the opam API quite correctly in the tests. When I use a version of opam-repository since OCaml 4.10.0 release, opam likes to choose
ocaml-system.4.08.1, a package that isn’t even available. I guess I’m missing a call to some init function somewhere.