# This Makefile is shared between all demos. It is our suggestion # of a canonical Makefile for projects that use Objective Caml, # ocamllex, and menhir. It requires a recent version of GNU make # (older versions do not correctly implement $(eval)). # ---------------------------------------------------------------- # This Makefile is meant to be included within a host Makefile # that defines the following variables: # # GENERATED : a list of the source (.ml and .mli) files # that should be generated by invoking ocamllex # or menhir # # MODULES : a list of the modules (without extension) # that should be linked into the executable # program. Order is significant. # # EXECUTABLE : the base name of the executables that should # be produced. Suffixes $(BSUFFIX) and $(OSUFFIX) # will be added to distinguish the bytecode and # native code versions. # ---------------------------------------------------------------- # The host Makefile can also override the following settings: # Menhir. ifndef MENHIR MENHIR := menhir endif # Parser generation flags. ifndef PGFLAGS PGFLAGS := --infer -v endif # Include directives for compilation and for linking. ifndef INCLUDE INCLUDE := endif # Bytecode compilation flags. ifndef BFLAGS BFLAGS := endif # Native code compilation flags. ifndef OFLAGS OFLAGS := endif # Menhir-suggested compilation flags. ifndef SUGG_FLAGS SUGG_FLAGS := $(shell $(MENHIR) $(PGFLAGS) --suggest-comp-flags 2>/dev/null) endif # Bytecode link-time flags. ifndef BLNKFLAGS BLNKFLAGS := endif # Menhir-suggested bytecode link-time flags. ifndef SUGG_BLNKFLAGS SUGG_BLNKFLAGS := $(shell $(MENHIR) $(PGFLAGS) --suggest-link-flags-byte 2>/dev/null) endif # Native code link-time flags. ifndef OLNKFLAGS OLNKFLAGS := endif # Menhir-suggested native code link-time flags. ifndef SUGG_OLNKFLAGS SUGG_OLNKFLAGS := $(shell $(MENHIR) $(PGFLAGS) --suggest-link-flags-opt 2>/dev/null) endif # Suffix appended to the name of the bytecode executable. ifndef BSUFFIX BSUFFIX := .byte endif # Suffix appended to the name of the native code executable. ifndef OSUFFIX OSUFFIX := endif # Access paths. ifndef OCAML OCAML := ocaml endif ifndef OCAMLC OCAMLC := $(shell if ocamlfind ocamlc -v >/dev/null 2>&1 ; \ then echo ocamlfind ocamlc ; \ elif ocamlc.opt -v >/dev/null 2>&1 ; \ then echo ocamlc.opt ; \ else echo ocamlc ; fi) endif ifndef OCAMLOPT OCAMLOPT := $(shell if ocamlfind ocamlopt -v >/dev/null 2>&1 ; \ then echo ocamlfind ocamlopt ; \ elif ocamlopt.opt -v >/dev/null 2>&1 ; \ then echo ocamlopt.opt ; \ else echo ocamlopt ; fi) endif ifndef OCAMLDEP OCAMLDEP := $(shell if ocamlfind ocamldep -version >/dev/null 2>&1 ; \ then echo ocamlfind ocamldep ; \ elif ocamldep.opt -version >/dev/null 2>&1 ; \ then echo ocamldep.opt ; \ else echo ocamldep ; fi) endif ifndef OCAMLDEPWRAPPER OCAMLDEPWRAPPER:= ./ocamldep.wrapper endif ifndef OCAMLLEX OCAMLLEX := ocamllex endif # A list of targets that do not require dependency analysis. # This variable should be set by the host before including # this Makefile. COLD += clean # ---------------------------------------------------------------- # Do not destroy the generated source files. .SECONDARY: $(GENERATED) # ---------------------------------------------------------------- # Linking. $(EXECUTABLE)$(OSUFFIX): $(MODULES:=.cmx) $(OCAMLOPT) -o $@ $(INCLUDE) $(OLNKFLAGS) $(SUGG_FLAGS) $(SUGG_OLNKFLAGS) $^ $(EXECUTABLE)$(BSUFFIX): $(MODULES:=.cmo) $(OCAMLC) -o $@ $(INCLUDE) $(BLNKFLAGS) $(SUGG_FLAGS) $(SUGG_BLNKFLAGS) $^ # ---------------------------------------------------------------- # Compiling. # We make the .ml and .mli files generated by ocamllex and menhir # unwritable, so as to prevent them from being edited by mistake. %.cmi: %.mli %.mli.d $(OCAMLC) $(INCLUDE) $(BFLAGS) $(SUGG_FLAGS) -c $< %.cmo: %.ml %.ml.d $(OCAMLC) $(INCLUDE) $(BFLAGS) $(SUGG_FLAGS) -c $< %.cmx %.o: %.ml %.ml.d $(OCAMLOPT) $(INCLUDE) $(OFLAGS) $(SUGG_FLAGS) -c $< %.ml: %.mll @if [ -f $@ ] ; then /bin/chmod +w $@ ; fi $(OCAMLLEX) $< @/bin/chmod -w $@ # ---------------------------------------------------------------- # Computing dependencies. # We associate a tiny Makefile, whose name ends in .d, with every # source file; it contains dependency information only. For an .ml or # .mli file, we create an .ml.d or .mli.d file by invoking ocamldep. # For an .mll file, we create an .ml.d file by invoking ocamllex first # (this is implicit), then ocamldep. # When it finds a reference to module M, ocamldep checks whether the # files m.ml and m.mli exist before deciding which dependency to # report. If m.ml and m.mli are generated from m.mll or m.mly, then # there is a potential problem: because ocamldep is invoked before # these files are created, it cannot see them. The standard solution # until now was to invoke ocamllex and ocamlyacc first to create all # generated files, and run ocamldep next. This approach does not work # with menhir when the --infer switch is on: menhir cannot be invoked # first because it needs type information found in .cmi (or .cmo or # .cmx) files. Our solution is to wrap ocamldep in a script that # creates fake generated files m.ml and m.mli to let ocamldep know that # these files are supposed to exist. This is somewhat tricky, but appears # to work. %.ml.d: %.ml $(OCAML) $(OCAMLDEPWRAPPER) $(GENERATED) - $(OCAMLDEP) $< > $@ %.mli.d: %.mli $(OCAML) $(OCAMLDEPWRAPPER) $(GENERATED) - $(OCAMLDEP) $< > $@ # All .d files are included within the present Makefile, so it they # do not exist, they are created first, and the dependencies that # they contain are then taken into account. # A .SECONDARY directive is used to ensure that the auxiliary # Makefiles are never removed. Otherwise, make could create # one, remove one, create one, remove one, ... (We have observed # this.) ifeq ($(findstring $(MAKECMDGOALS),$(COLD)),) ifneq ($(strip $(wildcard *.mli)),) .SECONDARY: $(patsubst %.mli,%.mli.d,$(wildcard *.mli)) -include $(patsubst %.mli,%.mli.d,$(wildcard *.mli)) endif ifneq ($(strip $(wildcard *.ml)),) .SECONDARY: $(patsubst %.ml,%.ml.d,$(wildcard *.ml)) -include $(patsubst %.ml,%.ml.d,$(wildcard *.ml)) endif ifneq ($(strip $(wildcard *.mll)),) .SECONDARY: $(patsubst %.mll,%.ml.d,$(wildcard *.mll)) -include $(patsubst %.mll,%.ml.d,$(wildcard *.mll)) endif endif # ---------------------------------------------------------------- # Support for menhir projects. # The macro menhir_multimodule defines support for multi-module grammar # specifications, that is, for producing parsers out of multiple # source files. The parameter $(1) is the name of the parser that # should be produced; the parameter $(2) is the list of .mly source # files; the parameter $(3) contains extra options to be passed to # menhir. # The dependency file is named $(1).d and created by invoking menhir # --depend. define menhir_multimodule $(1).ml $(1).mli: $(2) $(1).d @if [ -f $(1).ml ] ; then /bin/chmod +w $(1).ml ; fi @if [ -f $(1).mli ] ; then /bin/chmod +w $(1).mli ; fi $(MENHIR) --ocamlc "$(OCAMLC)" $(PGFLAGS) --base $(1) $(3) $(2) @/bin/chmod -w $(1).ml $(1).mli $(1).d: $(2) @if [ -f $(1).ml ] ; then /bin/chmod +w $(1).ml ; fi @if [ -f $(1).mli ] ; then /bin/chmod +w $(1).mli ; fi $(OCAML) $(OCAMLDEPWRAPPER) $(GENERATED) - \ $(MENHIR) --ocamldep "$(OCAMLDEP)" --depend --base $(1) $(3) $(2) > $$@ ifeq ($$(findstring $$(MAKECMDGOALS),$$(COLD)),) .SECONDARY: $(1).d -include $(1).d endif endef # The macro menhir_monomodule defines support for a mono-module grammar # specification. The parameter $(1) is the name of the parser that # should be produced; the source file is $(1).mly. The parameter $(2) # contains extra options to be passed to menhir. define menhir_monomodule $(eval $(call menhir_multimodule,$(1),$(1).mly,$(2))) endef # Neither of the two macros above is invoked by default, as it is not # known here which is appropriate. It is up to the client to invoke # these macros with suitable parameters. The auxiliary Makefile.auto # implements the common case where every .mly file is a mono-module # grammar. # ---------------------------------------------------------------- .PHONY: clean clean:: /bin/rm -f $(EXECUTABLE)$(BSUFFIX) $(EXECUTABLE)$(OSUFFIX) $(GENERATED) /bin/rm -f *.cmi *.cmx *.cmo *.o *~ .*~ *.automaton *.conflicts *.annot /bin/rm -f *.d