I am new to Ocaml and trying to write some small example application. I am using ocamlc
version 3.11.2 under Linux Ubuntu 10.04. I want to compile two files:
a.ml
b.ml
File b.ml
uses definitions from a.ml
. As far as I understand, I can use ocamlc -c
to perform compilation only. I can call ocamlc
one final time when I have all the .cmo
files to link them to an executable. Also, when compiling a file that uses definitions from another file, I have to tell the compiler in which .cmi
file to find the external definitions.
So my idea was to use:
ocamlc -i -c a.ml > a.mli
ocamlc -c a.mli b.ml
ocamlc -o b a.cmo b.cmo
The first step works and produces files a.mli
and a.cmo
, but when running the second step I get
File "b.ml", line 1, characters 28-31:
Error: Unbound value foo
where foo
is a function that is defined in a.ml
and called in b.ml
.
So my question is: how can I compile each source file separately and specify the interfaces to be imported on the command line? I have been looking in the documentation and as far as I can understand I have to specify the .mli
files to be included, but I do not know how.
EDIT
Here some more details. File a.ml
contains the definition
let foo = 5;;
File b.ml
contains the expression
print_string (string_of_int foo) ^ "\n";;
The real example is bigger but with these files I already have the error I reported above.
EDIT 2
I have edited file b.ml
and replaced foo
with A.foo
and this works (foo is visible in b.ml
even though I have another compilation error which is not important for this question). I guess it is cleaner to write my own .mli
files explicitly, as suggested by
First fix the
unbound value
issue, as explained by Jeffrey's answer. This is a comment about the commands you're using.Decomposing compilation in several steps is a good way to understand what's going on. If you want to write your own
a.mli
, most likely to hide some values of the moduleA
, then your commandocaml -i -c a.ml > a.mli
is a good way to get a first version of the this file and then edit it. But if you're not touchinga.mli
, then you don't need to generate it: you can also directly enterwhich will produce
a.cmo
,b.cmo
and the exectuablefoo
.(It will also generate
a.cmi
, which is the compiled version ofa.mli
, that you get by issuingocamlc -c a.mli
. Likewise it will also generateb.cmi
).Note that order matters: you need to provide
a.ml
beforeb.ml
on the command line. This way, when compilingb.ml
, the compiler has already seena.ml
and knows where to find the moduleA
.Some more comments:
A
are available, but under the nameA.foo
. The contents ofa.ml
has not been copy-pasted intob.ml
, rather, values of the moduleA
, defined ina.ml
and it's compiled versiona.cmo
have been accessed.A
inb.ml
, you can pass any of the following on the command line beforeb.ml
:a.mli
, which will get compiled intoa.cmi
a.cmi
if you've already compileda.mli
intoa.cmi
a.ml
or its compiled versiona.cmo
if you don't need to write your owna.mli
, i.e. if the default interface of moduleA
suits you. (This interface is simply every value ofa.ml
).It would be clearer if you showed the code that's not working. As Kristopher points out, though, the most likely problem is that you're not specifyig which module
foo
is in. You can specify the module explicitly, asA.foo
. Or you canopen A
and just use the namefoo
.For a small example it doesn't matter, but for a big project you should be careful not to use
open
too freely. You want the freedom to use good names in your modules, and if you open too many of them, the good names can conflict with each other.