Using OCaml packages with ocamlbuild can raise different error messages that are difficult to trace; there is a documentation ( http://brion.inria.fr/gallium/index.php/Ocamlbuild_and_module_packs ) that helps, but does not provide a step-by-step guide with common pitfalls, so here is one.
First create a project with the following files:
File: plu/bla.ml
let bla = 3;;
File: plu/bli.ml
let bli = Bla.bla;;
File: plu.mlpack
plu/Bla plu/Bli
File: use.ml
Plu.Bli.bli
Note: all the files do not have to be in a directory named plu/; this is just my convention.
Try to compile:
ocamlbuild use.byte /usr/bin/ocamlc -c -o use.cmo use.ml + /usr/bin/ocamlc -c -o use.cmo use.ml File "use.ml", line 1, characters 0-11: Error: Unbound module Plu Command exited with code 2.
Compilation will not work, probably because by default Ocamlbuild does
not traverse directories. It will work if you use the -r
option to
ocamlbuild, or create a (even empty) _tags
file at the root of the
project, that will allow ocamlbuild to traverse the directories:
ocamlbuild use.byte /usr/bin/ocamldep -modules plu/bla.ml > plu/bla.ml.depends /usr/bin/ocamldep -modules plu/bli.ml > plu/bli.ml.depends /usr/bin/ocamlc -c -I plu -o plu/bla.cmo plu/bla.ml /usr/bin/ocamlc -c -I plu -o plu/bli.cmo plu/bli.ml /usr/bin/ocamlc -pack plu/bla.cmo plu/bli.cmo -o plu.cmo /usr/bin/ocamlc -c -o use.cmo use.ml /usr/bin/ocamlc plu.cmo use.cmo -o use.byte
Notice that ocamlbuild has added -I plu
when compiling modules of
the Plu
package; so for instance, Bli
can access Bla
.
This odd behaviour can be the cause of many headaches, so I prefer to document it here (and I filed a bug report about this issue here).
Also note that if you make a mistake in the plu.mlpack
file, for
instance an error in the name of the directory or in that of the
module, ocamlbuild will fail without much warning. It will fail with a
compile error, as before; it may also fail at the linking step, if you
make a mistake in the plu.mlpack
file, but you had successfully
compiled a previous version. This problem can also be painful to
track, so I hope this help someone.
ocamlbuild use.byte /usr/bin/ocamlc use.cmo -o use.byte + /usr/bin/ocamlc use.cmo -o use.byte File "_none_", line 1, characters 0-1: Error: Error while linking use.cmo: Reference to undefined global `Plu' Command exited with code 2.
You cannot pack a set of .cmx
files (resulting from compilation of a
file) if you did not specified that the .cmx
can be packed when you
compile the file. Failure to do that result in an error like this:
ocamlbuild use.native /usr/bin/ocamldep -modules use.ml > use.ml.depends /usr/bin/ocamldep -modules plu/bla.ml > plu/bla.ml.depends /usr/bin/ocamldep -modules plu/bli.ml > plu/bli.ml.depends /usr/bin/ocamlc -c -I plu -o plu/bla.cmo plu/bla.ml /usr/bin/ocamlc -c -I plu -o plu/bli.cmo plu/bli.ml /usr/bin/ocamlc -pack plu/bla.cmo plu/bli.cmo -o plu.cmo /usr/bin/ocamlc -c -o use.cmo use.ml /usr/bin/ocamlopt -c -I plu -o plu/bla.cmx plu/bla.ml /usr/bin/ocamlopt -c -I plu -o plu/bli.cmx plu/bli.ml touch plu.mli ;\ if /usr/bin/ocamlopt -pack -I plu plu/bla.cmx plu/bli.cmx -o plu.cmx ;\ then rm -f plu.mli ; else rm -f plu.mli ; exit 1; fi + touch plu.mli ;\ if /usr/bin/ocamlopt -pack -I plu plu/bla.cmx plu/bli.cmx -o plu.cmx ;\ then rm -f plu.mli ; else rm -f plu.mli ; exit 1; fi File "plu.cmx", line 1, characters 0-1: Error: File plu/bla.cmx was not compiled with the `-for-pack Plu' option Command exited with code 1.
The lines:
/usr/bin/ocamlopt -c -I plu -o plu/bla.cmx plu/bla.ml /usr/bin/ocamlopt -c -I plu -o plu/bli.cmx plu/bli.ml
Need to be compiled with the -for-pack Plu
option. This is achieved
by a simple change in the _tags
file: just fill it with
<plu/*.cmx>: for-pack(Plu)
And now everything works:
ocamlbuild use.native /usr/bin/ocamldep -modules use.ml > use.ml.depends /usr/bin/ocamldep -modules plu/bla.ml > plu/bla.ml.depends /usr/bin/ocamldep -modules plu/bli.ml > plu/bli.ml.depends /usr/bin/ocamlc -c -I plu -o plu/bla.cmo plu/bla.ml /usr/bin/ocamlc -c -I plu -o plu/bli.cmo plu/bli.ml /usr/bin/ocamlc -pack plu/bla.cmo plu/bli.cmo -o plu.cmo /usr/bin/ocamlc -c -o use.cmo use.ml /usr/bin/ocamlopt -c -for-pack Plu -I plu -o plu/bla.cmx plu/bla.ml /usr/bin/ocamlopt -c -for-pack Plu -I plu -o plu/bli.cmx plu/bli.ml touch plu.mli ;\ if /usr/bin/ocamlopt -pack -I plu plu/bla.cmx plu/bli.cmx -o plu.cmx ;\ then rm -f plu.mli ; else rm -f plu.mli ; exit 1; fi /usr/bin/ocamlopt -c -o use.cmx use.ml /usr/bin/ocamlopt plu.cmx use.cmx -o use.native
I will update this post if/when I find more weird error messages using packages with ocamlbuild; or if you find such error, just tell me!
I discovered a new problem with ocamlbuild. The problems occur when you put code in a library which is included, and referenced only inside of a package; in that case ocamlbuild forgets to link with the library. The problem is well described in this mail. The author of that mail also provides a ocamlbuild plugin that works around the problem.
This seems to be a classical bug, and there is a pending bug report for it here.