Makefile.shared 8.67 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
# 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