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 SARCHIVE = $(NAME).cmxs 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) $(SARCHIVE)
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) $(SARCHIVE): $(XARCHIVE) $(OCAMLOPT) -shared -o $(SARCHIVE) $(XARCHIVE) || true
Note that the cmxs archive is optional: we just ignore the error when it cannot be built.
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 ocamlfind install $(NAME) *.mli *.cmi $(ARCHIVE) META \ -optional $(XARCHIVE) $(SARCHIVE) uninstall: ocamlfind remove $(NAME)
Last but not least a cleanup rule:
.PHONY: clean rm -f *.cmi *.cmo *.cmx *.cma *.cmxa *.a