I have a package named sundialsml, in which I want to load a slightly different .cm(x)a file depending on whether a subpackage named no_sens is loaded. Promisingly enough, the findlib 1.6.2 reference manual describes a "package predicate" feature:
[...] there are package predicates for every package that is finally selected. [They] have the form "pkg_" plus the name of the package (fully qualified).
So I wrote up this META file, where archive
branches on the package predicate for the subpackage:
version = "2.6.2"
description = "OCaml interface to Sundials"
requires = "bigarray"
archive(byte) = "sundials.cma"
archive(byte,pkg_sundialsml.no_sens) = "sundials_no_sens.cma"
archive(native) = "sundials.cmxa"
archive(native,pkg_sundialsml.no_sens) = "sundials_no_sens.cmxa"
package "no_sens" (
version = "2.6.2"
description = "Sundials/ML without sensitivity analysis (CVODE, IDA, KINSOL)"
requires = "sundialsml"
)
But findlib loads sundials.cma regardless of whether the subpackage no_sens is loaded, e.g.:
# #use "topfind";;
- : unit = ()
Findlib has been successfully loaded. Additional directives:
#require "package";; to load a package
#list;; to list the available packages
#camlp4o;; to load camlp4 (standard syntax)
#camlp4r;; to load camlp4 (revised syntax)
#predicates "p,q,...";; to set these predicates
Topfind.reset();; to force that packages will be reloaded
#thread;; to enable threads
- : unit = ()
# #require "sundialsml.no_sens";;
/home/jun/.opam/4.01.0/lib/ocaml/unix.cma: loaded
/home/jun/.opam/4.01.0/lib/ocaml/bigarray.cma: loaded
/home/jun/.opam/4.01.0/lib/sundialsml: added to search path
/home/jun/.opam/4.01.0/lib/sundialsml/sundials.cma: loaded
Same happens if I try branching on a top-level package, like ao
. In fact, far as I can tell, predicates of the form pkg_foo
are never defined (unless we say #predicates "pkg_foo";;
of course).
Am I using package predicates incorrectly? Or are they not really implemented? If so, is there any other way to select different archives based on the presence/absence of subpackages?
Please note the point here is to compute the archive from the set of subpackages the user selected. So "why don't you use #predicates" is not the solution I'm looking for.
It looks like that the pkg_
predicates are not implemented for the #require
directive at all. Of course, I may be wrong, since I inferred this by just greping the code and experimenting. In fact, it is only implemented in the frontend, so it is also not available if someone is using the library interface (so it will not work out of box for ocamlbuild
). Also, the pkg_
predicate is set only for selected packages, not for installed one. Where selected means, that the package is in the set of dependencies.
Here is an example. We define package ttt
with the following META
:
archive(byte,pkg_ttt.foo) = "foo.cma"
archive(byte,pkg_ttt.bar) = "bar.cma"
package "foo" (
requires = "ttt"
)
package "bar" (
requires = "ttt"
)
Now we can verify, that it works:
$ ocamlfind c -only-show -linkpkg -package "ttt.bar" main.ml
ocamlc.opt -I opam/lib/ttt opam/lib/ttt/bar.cma main.ml
Note: I've used opam
instead of a real path to my ocaml installation to shorten the output for readability.
$ ocamlfind c -only-show -linkpkg -package "ttt.foo" main.ml
ocamlc.opt -I opam/lib/ttt opam/lib/ttt/foo.cma main.ml
So, everything works, when we use the frontend. But if we will try from the toplevel:
# #require "ttt.foo";;
opam/lib/ttt: added to search path
Then nothing is loaded at all.
We can also try to use ocamlbuild
:
$ ocamlbuild -classic-display -package ttt.foo main.byte
opam/bin/ocamldep.opt -modules main.ml > main.ml.depends
opam/bin/ocamlc.opt -c -I opam/lib/ttt -o main.cmo main.ml
opam/bin/ocamlc.opt -I opam/lib/ttt main.cmo -o main.byte
So nothing is linked, it doesn't work. But if you will use -use-ocamlfind
option, it will work, since this option prescribes ocamlbuild
to use ocamlfind
fronted.
$ ocamlbuild -use-ocamlfind -classic-display -package ttt.foo main.byte
ocamlfind ocamldep -package ttt.foo -modules main.ml > main.ml.depends
ocamlfind ocamlc -c -package ttt.foo -o main.cmo main.ml
ocamlfind ocamlc -linkpkg -package ttt.foo main.cmo -o main.byte
So, to conclude, the idea was nice, and can work theoretically, but it is better not to use it, since the implementation is not complete.