Change your Makefile

Here is a commented version of a Makefile that may be used to compile and link a package. It describes the frequent case that the package simply consists of a bundle of modules that are dependent on other packages.

First, some general definitions. NAME is the name of the package. The OBJECTS variable enumerates the bytecode objects, whereas XOBJECTS names the native objects. The same naming convention is used for ARCHIVE and XARCHIVE, specifying the resulting bytecode, resp. native archive file. The REQUIRES variable lists the names of the packages that are needed for this package. If you need additional predicates, put them into the PREDICATES variable.

NAME     = p

OCAMLC   = ocamlfind ocamlc
OCAMLOPT = ocamlfind ocamlopt
OCAMLDEP = ocamldep

OBJECTS  = p1.cmo p2.cmo
XOBJECTS = p1.cmx p2.cmx

ARCHIVE  = $(NAME).cma
XARCHIVE = $(NAME).cmxa

REQUIRES = unix str q r s
PREDICATES =

The default goal is "all", causing the bytecode archive to be created. In order to get a native archive, choose "opt" as second goal. (The ".PHONY" line is a declaration meaningful for GNU-make; "all" and "opt" are only virtual goals as there no files "all", or "opt" which is indicated by making them dependents of ".PHONY".)

.PHONY: all opt
all: $(ARCHIVE)
opt: $(XARCHIVE)

The following two rules create the bytecode resp. native archive from the objects.

$(ARCHIVE): $(OBJECTS)
        $(OCAMLC) -a -o $(ARCHIVE) -package "$(REQUIRES)" -linkpkg \
	          -predicates "$(PREDICATES)" $(OBJECTS)
$(XARCHIVE): $(XOBJECTS)
        $(OCAMLOPT) -a -o $(XARCHIVE) -package "$(REQUIRES)" -linkpkg \
	          -predicates "$(PREDICATES)" $(XOBJECTS)

These rules compile the modules independently. The lines similar to ".ml.cmo" must be read: "How to transform files with suffix .ml into files with suffix .cmo". The corresponding command can refer to the input file as "$<" and to the output file(s) as "$@".

.SUFFIXES: .cmo .cmi .cmx .ml .mli

.ml.cmo:
        $(OCAMLC) -package "$(REQUIRES)" -predicates "$(PREDICATES)" \
                  -c $<
.mli.cmi:
        $(OCAMLC) -package "$(REQUIRES)" -predicates "$(PREDICATES)" \
                  -c $<
.ml.cmx:
        $(OCAMLOPT) -package "$(REQUIRES)" -predicates "$(PREDICATES)" \
                  -c $<

The "depend" goal is the file describing the dependencies within the package; it is created by ocamldep.

depend: *.ml *.mli
         $(OCAMLDEP) *.ml *.mli >depend
include depend

The "install" rule is a bit tricky. First it is tested if there is a native archive to install, and if so, the variable "extra" contains the corresponding files. The "ocamlfind install" command creates a new package directory and puts the given files into it.

.PHONY: install uninstall
install: all
         { test ! -f $(XARCHIVE) || extra="$(XARCHIVE) "`basename $(XARCHIVE) .cmxa`.a }; \
	 ocamlfind install $(NAME) *.mli *.cmi $(ARCHIVE) META $$extra

uninstall:
         ocamlfind remove $(NAME)

Last but not least a cleanup rule:

.PHONY: clean
         rm -f *.cmi *.cmo *.cmx *.cma *.cmxa *.a