SoftTimur
SoftTimur

Reputation: 5540

Make inconsistent assumptions over interface

I want to optimise the compilation time of my makefile. One problem that waists my time is, after modifying one single file, make returns for instance,

File "frontend/parser_e.ml", line 1:
Error: The files expression/rc.cmi and frontend/gen/lexer_ref.cmi
       make inconsistent assumptions over interface Utility
make: *** [frontend/parser_e.cmx] Error 2
rm frontend/parser_name.ml

Note that the files in trouble may change, but it happens quite often. What I have to do is make clean and then make, as a consequence it is not an incremental build and takes time.

So does anyone know what I should check in my makefile to reduce the chance of having this kind of error?

Edit 1:

Actually, all my ml-related files are in depth 1, except frontend/gen/*, which are in depth 2. Following the answer of @camlspotter, I modified a little bit the ocamldep part of my makefile. Now it looks like follows:

DIRS= -I frontend -I frontend/gen -I lib ...

depend: $(AUTOGEN)
        # ocamldep -native $(DIRS) */*.ml */*.mli > depend # this is what was written before, I don't hink it is correct
        ocamldep -native $(DIRS) *.ml *.mli > depend

As a consequence, make following another make gives immediately an inconsistence error.

One remark is I don't have AUTOGEN, is it normal?

Another remark is that make depend generates a depend that has 0 character, is it normal?

Edit 2:

I modified depend: by following Makefile of OCaml source code:

beforedepend:: */*.ml

depend: beforedepend
    (for d in \
    frontend frontend/gen lib ... ; \
    do ocamldep $(DIRS) $$d/*.mli $$d/*.ml; \
    done) > depend

I have actually around 20 folders, each has 1-5 ml files. This time, make rangs over for d in ..., and does not want to stop. But if I remove 3-4 folders, it succeeds to create a depend after several seconds.

Upvotes: 1

Views: 1596

Answers (1)

camlspotter
camlspotter

Reputation: 9040

Your Makefile does not cover all the necessary dependencies between modules.

The meaning of

File "frontend/parser_e.ml", line 1:
Error: The files expression/rc.cmi and frontend/gen/lexer_ref.cmi
       make inconsistent assumptions over interface Utility

is:

  • frontend/parser_e.ml depends on expression/rc.ml and frontend/gen/lexer_ref.ml
  • Both expression/rc.ml and frontend/gen/lexer_ref.ml use module named Utility
  • expression/rc.ml and frontend/gen/lexer_ref.ml must agree with the type (interface) of Utility, but did not.

I think of two possibilities to cause this state:

  • There may be two different utility.ml, for example dir_a/utility.ml and dir_b/utility.ml. OCaml does not allow linking modules with the same name. You can workaround this using packed modules (see -pack compiler option). Your case is not this.
  • The both modules use the same utility.ml but the dependencies may not be perfectly known to your Makefile. This is your case.

A possible scenario of the second case is:

  • You have modified utility.ml or utility.mli and its interface (.cmi file) has been changed.
  • One of expression/rc.ml and frontend/gen/lexer_ref.ml is recompiled against this new interface of Utility, but the other IS NOT, since the dependency is not known.
  • The compiler has found the inconsistency between the two modules when they are used together in frontend/parser_e.ml.

For fix, you have to run ocamldep to capture all the necessary module dependencies and inform it to make. Note that:

  • Give proper options and arguments. Since you work with nested directories, you need -I option several times.
  • Make sure that the auto-generated .ml and .mli files are really generated before ocamldep runs. Since you seem to have .mly and .mll files and you have the issue around them, I suspect you miss something around here.

A good example of the dependency analysis of OCaml modules is found at OCaml compiler source code itself. It is good to check around its lines with beforedepend, depend and include .depend.


General hints:

  • Add include .depend to your Makefile and capture all the module dependencies into this .depend file, using ocamldep
  • Note that all the .ml and .mli files of your project must be scanned by ocamldep. Do not forget to add -I options properly or it misses some dependencies.
  • Before running ocamldep, make sure auto-generated .ml and .mli files such as the output of .mly and .mll are generated. Or it misses some dependencies.

Typical Makefile looks like:

beforedepend:: x.ml

x.ml: x.mly
  ocamlyacc x.mly

beforedepend:: y.ml

y.ml: y.mll
  ocamllex y.mll

depend: beforedepend
  ocamldep -I <dir1> -I <dir2> <all the ml and mli paths> > .depend

include .depend

Upvotes: 2

Related Questions