Skip to content

Commit

Permalink
build: Add missing pattern rule to build *.cmi from *.ml.
Browse files Browse the repository at this point in the history
In the case where we have a module.ml without a corresponding
module.mli file, ocamldep generates (correct) dependencies:

  module.cmx module.cmi : module.ml

but we had no rule telling make how to generate the module.cmi
file from module.ml.

This didn't matter very much because when make came to build
module.cmx, the module.cmi file is generated as a side-effect.

However for highly parallel builds, the build ordering was still
incorrect.  Any other module that depends on module.cmi could be built
in parallel.  You would very occasionally see errors like this one:

  File "_none_", line 1:
  Error: Files index.cmx and utils.cmx
         make inconsistent assumptions over interface Utils

Fixing this involves adding a ‘%.cmi: %.ml’ rule.  However we have to
be careful that make doesn't run this rule instead of the ‘%.cmi: %.mli’
rule (if module.mli did exist).  It turns out that GNU make says we
can depend on rule ordering in the Makefile for this.

I found that this only works correctly if we use "%"-style pattern
rules (not the ‘.ml.cmi:’ old-style rules).

This is *still* not a complete fix.  Make still doesn't know that the
rules ‘%.cmo: %.ml’ and ‘%.cmx: %.ml’ also build the .cmi file as a
side-effect, so you can still occasionally see build failures.
However I could not work out how to add the extra information to the
dependencies without causing make itself to go into an infinite loop.
It may be that in the end we will have to get rid of pattern rules
completely and generate the complete OCaml rule set.
  • Loading branch information
rwmjones committed Sep 15, 2017
1 parent 81419c4 commit 6d0ad49
Showing 1 changed file with 10 additions and 3 deletions.
13 changes: 10 additions & 3 deletions subdir-rules.mk
Expand Up @@ -79,12 +79,19 @@ guestfs_am_v_jar = $(guestfs_am_v_jar_@AM_V@)
guestfs_am_v_jar_ = $(guestfs_am_v_jar_@AM_DEFAULT_V@)
guestfs_am_v_jar_0 = @echo " JAR " $@;

.mli.cmi:
# We must always choose the .mli.cmi rule over the .ml.cmi rule if the
# .mli file exists. The .mli.cmi rule is listed first because:
# "If more than one pattern rule has the shortest stem, make will
# choose the first one found in the makefile."
# (https://www.gnu.org/software/make/manual/make.html#Pattern-Match)
%.cmi: %.mli
$(guestfs_am_v_ocamlcmi)$(OCAMLFIND) ocamlc $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
.ml.cmo:
%.cmi: %.ml
$(guestfs_am_v_ocamlcmi)$(OCAMLFIND) ocamlc $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
%.cmo: %.ml
$(guestfs_am_v_ocamlc)$(OCAMLFIND) ocamlc $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
if HAVE_OCAMLOPT
.ml.cmx:
%.cmx: %.ml
$(guestfs_am_v_ocamlopt)$(OCAMLFIND) ocamlopt $(OCAMLFLAGS) $(OCAMLPACKAGES) -c $< -o $@
endif

Expand Down

0 comments on commit 6d0ad49

Please sign in to comment.