# -*- Mode: makefile -*- # Copyright (c) 2001-2002, # George C. Necula # Scott McPeak # Wes Weimer # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # 3. The names of the contributors may not be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A # PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER # OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Generic Makefile for Ocaml projects # Written by necula@cs.berkeley.edu # # Features: # - keeps byproducts of building in a separate directory # - handles dependencies automatically # - user specifies just what modules go into a project and # everything else is done automatically # - you can use one Makefile for several Ocaml projects # # You must include this file in your Makefile. Before the include point # you must defined the following variables (which are glob al for all Ocaml # projects specified in one Makefile): # # CAMLDIR - the directory where to get the ocaml executables from. # Must be empty (defaul) or end with a / # OBJDIR - the directory where to put all object files. This directory # must exist (default obj) # DEPENDDIR - the directory where to put dependency files. This directory # must exist. (default obj/.depend) # NATIVECAML - if set then will use the native compiler # UNSAFE - if set then will turn off safety checks (only with NATIVECAML) # CAML_NOOPT - if set then it will not optimizer (default is to optimize when # NATIVECAML is used, and not optimize in bytecode mode) # PROFILE - if set then it will compile and link with "gprof" profiling # support (NATIVECAML mode only) # ASSEMBLY - if set then it will keep assembly files # STATIC - if set then it will compile and link statically # (NATIVECAML mode only) # PREPROC - the preprocessor command # WIN32 - means that we are using the Windows native tools # MODULES - a list of all modules for all projects defined in the # Makefile. Give only the basenames (no directory, # no extension). This is used to create the dependencies. # SOURCEDIRS - a list of all directories containing sources for all # projects defined in a Makefile. This is used to set vpath. # MLLS - a list of all .mll (ocamllex input) files for all # projects defined in the Makefile. # MLYS - a list of all .mly (ocamlyacc input) files for all # projects defined in the Makefile. # CP4S - a list of all .p4 (ocamlp4 input) files for all # projects defined in the Makefile. # ECHO - if specifically set to nothing then it will print # all of the commands issued. Set this in the command line # if you want to see what is going on. # # COMPILEFLAGS - if defined, then it is passed as argument to ocamlc # and ocamlopt # LINKFLAGS - if defined, then it is passed as argument to # ocamlc and ocamlopt, when linking (at start of # command line) # # CAML_CFLAGS - flags used only for the compilation of C files. # e.g. '-ccopt ' # # BEFOREDEPS - must list the ML files that must be created before computing # dependencies. If you do not do this, then ocamldep will not # record a dependency on the missing ML files. # The files obtained from MLYS and MLLS are # handled automatically. This must be set before including this # Makefile.ocaml # # After you set all of the above you must do the following for EACH separate # executable that you want to build. # # Define the following: # PROJECT_EXECUTABLE - the name of the executable you want to build. To take # advantage of the naming scheme that separates the # bytecode version and the native version, use the # $(EXE) variable which is defined to either .byte.exe # or .asm.exe. I typically put the executable in # $(OBJDIR) as well. # PROJECT_MODULES - the base names of the modules that make this # executable in the order in which they must be # passed to the linker. Make sure that all of # the names mentioned here are also mentioned in # MODULES. # PROJECT_CMODULES - same as modules but for the C modules. These # do not need to be mentioned in MODULES. There must be # no name clashes with MODULES # PROJECT_LIBS - the base names of the libraries that you # want to link in the executable. # # # After defining these variables, put the following code in your # Makefile to generate a customized rule for making your executable: # # $(PROJECT_EXECUTABLE) : $(PROJECT_MODULES:%=$(OBJDIR)/%.$(CMO)) \ # $(PROJECT_CMODULES:%=$(OBJDIR)/%.$(CMC)) # @$(NARRATIVE) "Linking $(COMPILETOWHAT) $@ $(LINKMSG)" # $(AT)$(CAMLLINK) -verbose -o $@ \ # $(PROJECT_LIBS:%=%.$(CMXA)) \ # $(PROJECT_LIBS:%=-cclib -l%) \ # $^ # # # Example: # # OBJDIR = obj # DEPENDDIR = obj/.depend # SOURCEDIRS = src src/special # MLLS = mylex # MLYS = myparse # # MODULES = mod11 mod12 mod21 modcommon # # # Rules for project 1 # PROJECT_EXECUTABLE = $(OBJDIR)/proj1$(EXE) # PROJECT_MODULES = mod11 mod12 modcommon # PROJECT_CMODULES = # PROJEC_LIBS = unix # #Standard boilerplate for the executable # $(PROJECT_EXECUTABLE) : $(PROJECT_MODULES:%=$(OBJDIR)/%.$(CMO)) \ # $(PROJECT_CMODULES:%=$(OBJDIR)/%.$(CMC)) # @$(NARRATIVE) "Linking $(COMPILETOWHAT) $@ $(LINKMSG)" # $(AT)$(CAMLLINK) -verbose -o $@ \ # $(PROJECT_LIBS:%=%.$(CMXA)) \ # $(PROJECT_LIBS:%=-cclib -l%) \ # $^ # # # # Rules for project 2 # PROJECT_EXECUTABLE = $(OBJDIR)/proj2$(EXE) # PROJECT_MODULES = mod21 modcommon # PROJECT_CMODULES = # PROJEC_LIBS = unix str # #Standard boilerplate for the executable # $(PROJECT_EXECUTABLE) : $(PROJECT_MODULES:%=$(OBJDIR)/%.$(CMO)) \ # $(PROJECT_CMODULES:%=$(OBJDIR)/%.$(CMC)) # @$(NARRATIVE) "Linking $(COMPILETOWHAT) $@ $(LINKMSG)" # $(AT)$(CAMLLINK) -verbose -o $@ \ # $(PROJECT_LIBS:%=%.$(CMXA)) \ # $(PROJECT_LIBS:%=-cclib -l%) \ # $^ # CAMLLEX = ocamllex CAMLYACC= ocamlyacc -v CAMLDEP = ocamldep CAMLP4 = camlp4 pa_o.cmo pa_op.cmo pr_o.cmo # Internal versions of COMPILEFLAGS and LINKFLAGS. We'll add additional flags # to these. COMPILE_FLAGS := $(COMPILEFLAGS) LINK_FLAGS := $(LINKFLAGS) COMPILE_FLAGS += -I $(OBJDIR) # sm: two styles for echoing compilation progress: # style 1, by George: # - print English descriptions of what's happening # - set ECHO to "" to see *everything* # style 2, by Scott: # - do not print English descriptions # - print every shell command that is executed which has a side effect, # so that they could be pasted into a shell to reproduce manually # - omit some of the details of dependency generation # # to be able to choose which style, several variables are used: # @$(NARRATIVE) - put this before English descriptions for style 1 # @$(COMMAND) - put this before shell commands which are to be # printed for style 2; the command is *not* executed # $(AT) - put this before shell commands which are to be executed, # and also printed in style 2 # $(ECHO) - use in place of '@' for things not printed in either style ifdef ECHOSTYLE_SCOTT # 'true' silently consumes its arguments, whereas 'echo' prints them NARRATIVE := true COMMAND := echo AT := ECHO := @ else NARRATIVE := echo COMMAND := true # change these next two definitions to to echo everything, # or leave as @ to suppress echoing AT := @ ECHO := @ endif ifdef PREPROC COMPILE_FLAGS += -pp "$(PREPROC)" DEPFLAGS += -pp "$(PREPROC)" endif COMPILEMSG= LINKMSG= ifdef WIN32 OBJ = obj else OBJ = o endif EXE = $(EXEEXT).exe export EXE ifdef NATIVECAML ifdef PROFILE COMPILE_FLAGS += -p LINK_FLAGS += -p COMPILEMSG += (profile) LINKMSG += (profile) endif ifdef ASSEMBLY COMPILE_FLAGS += -S endif ifdef STATIC COMPILE_FLAGS += -ccopt -static LINK_FLAGS += -ccopt -static endif #foo := $(shell echo "I am in NATIVECAML mode" >&2; echo whatever) CAMLC = $(CAMLDIR)ocamlopt $(COMPILE_FLAGS) CAMLLINK = $(CAMLDIR)ocamlopt $(LINK_FLAGS) CMO = cmx CMC = opt.$(OBJ) # compiled (and optimized) C CMXA = cmxa EXEEXT = .asm MOVEAFTERCAMLC = cmi cmx $(OBJ) COMPILETOWHAT = native code # sm: by adding -native in native mode, we prevent spurious # dependencies on .cmo files which were causing lots of # extra recompilation CAMLDEP = $(CAMLDIR)ocamldep -native # CAML_NOOPT maintains its value on entry (default, missing) else # Bytecode mode CMO = cmo CMXA = cma CMC = $(OBJ) EXEEXT = .byte MOVEAFTERCAMLC = cmi cmo COMPILETOWHAT = bytecode CAMLC = $(CAMLDIR)ocamlc $(COMPILE_FLAGS) CAMLLINK = $(CAMLDIR)ocamlc -custom $(LINK_FLAGS) CAML_NOOPT = 1 endif ifdef UNSAFE CAMLC := $(CAMLC) -unsafe -noassert endif ifdef CAML_NOOPT ifdef WIN32 COMPILE_FLAGS += -ccopt /Zi -ccopt /Od LINK_FLAGS += -ccopt /Zi -ccopt /Od else COMPILE_FLAGS += -g -ccopt -g LINK_FLAGS += -g -ccopt -g endif else ifdef WIN32 COMPILE_FLAGS += -ccopt /Ox else COMPILE_FLAGS += -ccopt -O3 endif endif # Allow searching for .ml and .mli vpath %.mll $(SOURCEDIRS) vpath %.mly $(SOURCEDIRS) vpath %.ml $(SOURCEDIRS) $(OBJDIR) vpath %.mli $(SOURCEDIRS) $(OBJDIR) vpath %.c $(SOURCEDIRS) vpath %.p4 $(SOURCEDIRS) # Secondaries are intermediates that we don't want make to delete # By giving the right names to secondary files we tell make where to make # them if they are not already made. VERY USEFUL!! MLL_LYS:= $(MLLS:%.mll=$(OBJDIR)/%.ml) \ $(MLYS:%.mly=$(OBJDIR)/%.ml) $(MLYS:%.mly=$(OBJDIR)/%.mli) \ $(CP4S:%.p4=$(OBJDIR)/%.ml) .SECONDARY : $(MLL_LYS) # Run the lexer generator # Move the result to the OBJDIR directory # If there is a .mli file in the same directory with .mll then # copy it to OBJDIR (where the .ml) file will live. $(OBJDIR)/%.ml: %.mll $(CAMLLEX) $< $(AT)mv -f $(basename $<).ml $(OBJDIR)/ $(ECHO)if test -f $(basename $<).mli ;then \ $(COMMAND) cp -f $(basename $<).mli $(OBJDIR)/; \ cp -f $(basename $<).mli $(OBJDIR)/ \ ;fi # Run the parser generator # Move the result to the $(OBJDIR) directory. $(OBJDIR)/%.ml $(OBJDIR)/%.mli: %.mly $(CAMLYACC) $(CAMLYACCFLAGS) $< $(AT)mv -f $(basename $<).ml $(basename $<).mli $(OBJDIR)/ $(OBJDIR)/%.ml: %.p4 $(CAMLP4) -impl $< > $@ $(ECHO)if test -f $(basename $<).mli ;then \ $(COMMAND) cp -f $(basename $<).mli $(OBJDIR); \ cp -f $(basename $<).mli $(OBJDIR) \ ;fi # Compile an MLI file. After compilation move the result to OBJDIR $(OBJDIR)/%.cmi: %.mli @$(NARRATIVE) Compiling interface $< $(AT)$(CAMLC) -c $< $(ECHO)if test $(OBJDIR) != $() { s%[^/\\ :]*/% %g; s%[^/\\ :]+\\% %g; s%([-a-zA-Z0-9+-.:/\/_]+)%\$$(OBJDIR)/$$1%g; print $$_;}' # FIXDEPEND:=cat DEPINCLUDES= -I $(OBJDIR) $(SOURCEDIRS:%=-I %) $(DEPENDDIR)/%.d: %.ml $(BEFOREDEPS) @$(NARRATIVE) "Generating dependency information for $<" $(ECHO)if ! [ -d $(DEPENDDIR) ]; then mkdir -p $(DEPENDDIR) ; fi @$(COMMAND) $(CAMLDEP) $(DEPFLAGS) $(DEPINCLUDES) $< $(ECHO)$(CAMLDEP) $(DEPFLAGS) $(DEPINCLUDES) $< | $(FIXDEPEND) > $@ $(DEPENDDIR)/%.di: %.mli $(BEFOREDEPS) @$(NARRATIVE) "Generating dependency information for $<" $(ECHO)if ! [ -d $(DEPENDDIR) ]; then mkdir -p $(DEPENDDIR) ; fi @$(COMMAND) $(CAMLDEP) $(DEPFLAGS) $(DEPINCLUDES) $< $(ECHO)$(CAMLDEP) $(DEPFLAGS) $(DEPINCLUDES) $< | $(FIXDEPEND) > $@ # sm: it turns out there's a variable which lists all the goals # specified on the command line; I'll use this to set CLEANING # (which is not set anywhere else, currently) ifeq ($(MAKECMDGOALS),clean) #$(warning "Skipping dependency rules because we're cleaning") CLEANING := 1 endif ifndef CLEANING -include $(MODULES:%=$(DEPENDDIR)/%.d) -include $(MODULES:%=$(DEPENDDIR)/%.di) endif listmodules: @echo $(MODULES)