Linking library without full path

It’s been a while since I used Ocaml and perhaps my setup is now incorrect but I can’t seem to use a standard opam-installed library without specifying the full path. I’ve done:

opam update -u; opam switch 5.0.0; eval opam config env; opam user-setup install

and using ocamlfind ocamlc -only-show tells me the correct compile command is

ocamlc.opt -o testprog.exe -I /home/toby/.opam/5.0.0/lib/zarith /home/toby/.opam/5.0.0/lib/zarith/zarith.cma

which works, but I have to include the full library path. The following commands

ocamlc.opt -o testprog.exe zarith.cma
ocamlc.opt -o testprog.exe /home/toby/.opam/5.0.0/lib/zarith/zarith.cma
ocamlc.opt -o testprog.exe -I +zarith zarith.cma

all give me the dreaded “Unbound module” error.

I have these set;

OPAM_SWITCH_PREFIX=‘/home/toby/.opam/5.0.0’; export OPAM_SWITCH_PREFIX;
CAML_LD_LIBRARY_PATH=‘/home/toby/.opam/5.0.0/lib/stublibs:/home/toby/.opam/5.0.0/lib/ocaml/stublibs:/home/toby/.opam/5.0.0/lib/ocaml’; export CAML_LD_LIBRARY_PATH;
OCAML_TOPLEVEL_PATH=‘/home/toby/.opam/5.0.0/lib/toplevel’; export OCAML_TOPLEVEL_PATH;

How can I compile and link with libraries such as zarith without having to specify full paths or use ocamlfind every time?

I guess the nowadays approach consists to have a dune-project and a dune files and lets dune search the library. When all is setup, a single dune exec ./testprog.exe compile the program if needed and launch it.

1 Like

OK I will look into that, but it is strange the compiler cant find the module interface or library using the environment variables when it is installed in a standard place. In particular I don’t know why ‘-I +zarith’ doesn’t work.

The + is only useful for the handful of libraries bundled with the compiler, which is not the case for zarith.

Ok, that’s not mentioned in the man page: “Add the given directory to the list of directories searched”

The OCaml compiler still operates on a model where it controls where its own libraries are installed, but not others. So -I +unix/ means that you expect the compiler to have installed unix in a subdirectory of its standard library location, and this works because unix is shipped by the compiler.
On the other hand, external libraries like zarith can be installed in arbitrary ways (through opam, your system package manager, or by hand), so you cannot rely on it being located close to the standard library.
(The compiler knows where it is going to be installed itself, so I guess we could add support for syntax like ~lib/zarith to point to the library folder of the installation target, but given that ocamlfind already does a very good job of dealing with these issues it is not a priority.)

You can use ocamlfind to either generate whole command-line, like you did, or just find the library for a specific package (ocamlfind query zarith). The second option would likely be useful if you want to integrate it in your own build system.

Finally, if you know your packages come from opam and are installed in predictable ways, you can also ask opam for the path to its installation library and use it to semi-hardcode paths: $(opam var lib)/zarith.

1 Like

I think the issue is that zarith used to (and maybe still does) install itself in the OCaml standard library directory if ocamlfind was not available. In that case, simply passing -I +zarith would work.


There’s nothing wrong with using ocamlfind “every time”, i.e. for all invocations of the OCaml compilers: it’s lightweight and handles library packages very well. Or, use Dune as a build manager, it will also handle library packages correctly.

The ZArith readme should be updated to not mention -I +zarith, which no longer works.

1 Like