Module: separate compilation of non-local interfaces


#1

I am using Ocaml in the Bachelor introduction to programming class at ENS Rennes. I am encouraging my students to use an Abstract Data Types (ADT) approach with compiled modules and opaque data-types.

Each module is thus made of two parts: a signature adt.mli part and an implementation part adt.ml. The documentation at https://caml.inria.fr/pub/docs/manual-ocaml/moduleexamples.html is quite clear when those two files are located in the same directory.

However, they are now working on a project with several modules, respectively developed by separate groups. The groups share the interfaces adt.mli in a Interfaces repository, but not the implementation codes.

The question is then the procedure for one group to make adt.cma. I first instructed them to do

$ ocamlc -c ../Interfaces/adt.mli
$ ocamlc -c adt.ml

Unfortunately, it does not work, as the adt.cmi file is left in the Interfaces repository, and it is not found on compiling adt.ml. Instead, the default adt.cmi file is rebuilt in the current directory.

I then tried

$ ocamlc -c ../Interfaces/adt.mli adt.ml

Surprisingly enough, it works!

Could somebody provide me with an explanation, so that I can tell my students?

Also, is it possible to tell ocamlc -c adt.ml to look for the adt.cmi file in another directory instead of rebuilding a local one?

Regards,

Luc.


#2

I think you want to use -I:

ocamlc -c -I ../Interfaces adt.ml

Detailed information from the man page :

-I directory

Add the given directory to the list of directories searched for compiled interface files (.cmi), compiled object code files (.cmo), libraries (.cma), and C libraries specified with -cclib -l xxx . By default, the current directory is searched first, then the standard library directory. Directories added with -I are searched after the current directory, in the order in which they were given on the command line, but before the standard library directory. See also option -nostdlib .

If the given directory starts with + , it is taken relative to the standard library directory. For instance, -I +compiler-libs adds the subdirectory compiler-libs of the standard library to the search path.


#3

I am not sure to understand your answer. Let me introduce the following example.

  • Directory Interface: file test.mli declares function f and not function g.
  • Directory Test: file test.ml defines f and g

Experiment

$ more ../Interfaces/test.mli
val f : unit -> int

$ more test.ml
let f() = 0;;
let g() = 1;;

$ cd Interfaces/
$ ocamlc -c test.mli -o test.cmi

$ cd ../Test/
$ rm *.cm*
$ ocamlc -c -I ../Interfaces test.ml 

$ ocaml -I ../Interfaces/ test.cmo
        OCaml version 4.07.1
# Test.f();;
- : int = 0
# Test.g();;
- : int = 1

g is defined, whereas it should not!

Did I miss something? Why is file ../Interfaces/test.cmi missed by the compiler?