From 6d0ad49d5e3415de45a6ccdf1ec6de55e1e8384f Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 15 Sep 2017 11:38:33 +0100 Subject: [PATCH] build: Add missing pattern rule to build *.cmi from *.ml. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- subdir-rules.mk | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/subdir-rules.mk b/subdir-rules.mk index 61ab0d87c..857afa0ab 100644 --- a/subdir-rules.mk +++ b/subdir-rules.mk @@ -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