Quick tip: the ocamlbuild -documentation option
- February 20, 2013
A quick and dirty blog post about the -documentation
option of ocamlbuild
, how to use and understand its
output.
I’ve been overloaded since returning from POPL, and all the nice and interesting blog posts I planned to polish and publish are still in the drawers. In the meantime, I’m recycling emails that may be of interest to some of our beloved readers.
This post comes from a conversation with Cedric Cellier, which was
wondering how to tell ocamlbuild to use the -custom
option
to (bytecode) compile his OCaml program.
The ocamlbuild
-documentation
option
The command ocamlbuild ... -documentation
explains the
set of rules and tags understood by this particular ocamlbuild
invocation (which can depend on the plugin, other options passed to
ocamlbuild
, etc..). It returns a very long output, that
contains information about both all rules known by ocamlbuild
(which tells him how to dynamically look for the dependencies of a given
target) and all tags (which add flags to the compilation
command for a given target). Some representative examples on my
system:
...
rule
"ocaml: cmx* & o* -> native"
~deps:[ %.cmx; %.o ]
~prods:[ %.native ]
<fun>
rule
"ocaml: mllib & d.cmo* -> d.cma"
~deps:[ %.mllib ]
~prods:[ %.d.cma ]
<fun>
...
flag {. byte, debug, link, ocaml, program .} "-g"
flag {. byte, compile, debug, ocaml .} "-g"
flag {. link, native, ocaml, use_camlp4_bin .} "+camlp4/Camlp4Bin.cmx"
flag {. byte, link, ocaml, use_camlp4_bin .} "+camlp4/Camlp4Bin.cmo"
flag {. compile, ocaml, use_camlp4_full .}
"-I +camlp4/Camlp4Parsers -I +camlp4/Camlp4Printers -I +camlp4/Camlp4Filters"
While it won’t tell you everything (you don’t know which
<fun>
is hiding under the .d.cma
rule
above, so you’ll need to look at the manual or try it to what this
extension means), grepping this output is a good way to find about
ocamlbuild tags you didn’t know about, and look for specific features.
So for our -custom
question:
$ ocamlbuild -documentation | grep custom
flag {. byte, custom, library, link, ocaml .} "-custom"
flag {. byte, custom, link, ocaml, program .} "-custom"
This tells us that -custom
will be added to the
compilation command when either one of this list of flags is present for
the target being compiled – this is similar to the predicate system of
ocamlfind
.
Knowing
which flags are present: that’s what _build/_log
is
for
In this simple case it’s enough to just try to add the
custom
tag to your ocamlbuild invocation (either in the
_tags
or on the command line directly) and check that it
works. But in general you may want to know about precisely which of
those flags are already present under your current compilation settings,
and which should be added. For that, the log is your friend.
$ cd /tmp
$ mkdir ocamlbuild-test; cd ocamlbuild-test
$ touch test.ml
$ ocamlbuild test.byte
Finished, 3 targets (0 cached) in 00:00:00.
$ cat _build/_log
### Starting build.
# Target: test.ml.depends, tags: { extension:ml, file:test.ml, ocaml, ocamldep, quiet }
.../bin/ocamldep.opt -modules test.ml > test.ml.depends
# Target: test.cmo, tags: { byte, compile, extension:cmo, extension:ml, file:test.cmo, file:test.ml, implem, ocaml, quiet }
.../bin/ocamlc.opt -c -o test.cmo test.ml
# Target: test.byte, tags: { byte, dont_link_with, extension:byte, file:test.byte, link, ocaml, program, quiet }
.../bin/ocamlc.opt test.cmo -o test.byte
# Compilation successful.
There you are: ocamlbuild called ocamldep
to look for
dependencies, then compiled the module, then linked it. And you have the
list of all flag presents at each step in the process. You can check
that besides custom
, the necessary
byte, link, ocaml, program
are all present during the
linking phase.
$ ocamlbuild -tag custom test.byte
Finished, 3 targets (2 cached) in 00:00:00.
scherer@jurancon:/tmp/ocamlbuild-test $ cat _build/_log
### Starting build.
# Target: test.ml.depends, tags: { custom, extension:ml, file:test.ml, ocaml, ocamldep, quiet }
.../bin/ocamldep.opt -modules test.ml > test.ml.depends # cached
# Target: test.cmo, tags: { byte, compile, custom, extension:cmo, extension:ml, file:test.cmo, file:test.ml, implem, ocaml, quiet }
.../bin/ocamlc.opt -c -o test.cmo test.ml # cached
# Target: test.byte, tags: { byte, custom, dont_link_with, extension:byte, file:test.byte, link, ocaml, program, quiet }
.../bin/ocamlc.opt -custom test.cmo -o test.byte
# Compilation successful.
The custom
tag was added to all compilation phases (we
may have been more precise by adding it in _tags
as a tag
on test.byte
only, so that it gets added only during the
linking step), and resulted to the addition of the -custom
flag. Job done. Notice that ocamlbuild only runs the linking command
again, as the output of the others are already cached.