Skip to content

Instantly share code, notes, and snippets.

@agarwal
Last active October 2, 2015 21:29
Show Gist options
  • Save agarwal/c75e56b200050343fdbb to your computer and use it in GitHub Desktop.
Save agarwal/c75e56b200050343fdbb to your computer and use it in GitHub Desktop.
OMake function to build an OCaml library.
# 2015-Oct-2: Update: You should disregard the below. A more up
# to date version of this file is maintained at
# https://github.com/biocaml/biocaml/blob/master/etc/OCaml.om. Note
# that file is still not very good (we're just hacking and hoping
# to avoid OMake at some point), so the caveats below do still
# hold.
# This is a very rough implementation of an OMake function to compile
# a library. It isn't good OMake code and definitely not usable
# out-of-the-box. It is only useful for you to read and learn a little
# about OMake. The benefit is you have full control over your build,
# which also means you have to understand all of OCaml's compiler
# options yourself. I'm not recommending OMake; it has many
# annoyances. But I've been using it for a while, and at least
# eventually I can get the job done. I make the following assumptions,
# but the point is you should be able to easily change to suit your
# needs:
# - Each library is in a sub-directory named lib/libx.
# - Each library is compiled using OCaml's -pack option.
open build/Common
PROJECT=foo
.PHONY: clean
clean:
rm -rf _build
rm -rf OMakeroot.omc .omakedb .omakedb.lock .merlin $(PROJECT).install
OCAMLFLAGS = -bin-annot -annot -w A-4-33-41-42-44-45-48 \
-thread -short-paths -safe-string -g
BYTE_ENABLED = true
NATIVE_ENABLED = true
################################################################################
# Parameters
VERSION = dev
if $(test -e .git)
GIT_COMMIT = 'Some "$(shell git rev-parse HEAD)"'
export
else
GIT_COMMIT = 'None'
export
# The packages each library x depends on.
PACKAGES(x) =
switch $(x)
case liba
return $(EMPTY)
case libb
return $(EMPTY)
case libc
return core_kernel sexplib.syntax xmlm yojson
default
eprintln(PACKAGES undefined for $(x).)
exit(1)
# Whether or not library x requires camlp4o. Ideally this could be
# inferred from the PACKAGES, but I don't know how.
USE_CAMLP4O(x) =
switch $(x)
case liba
return false
case libb
return false
case libc
return true
default
eprintln(USE_CAMLP4O undefined for $(x).)
exit(1)
# The internal libraries that each library depends on. In this
# example, we have libc depending on both of the other libraries.
LIB_DEPS(x) =
switch $(x)
case liba
return $(EMPTY)
case libb
return $(EMPTY)
case libc
return liba libb
default
eprintln(LIB_DEPS undefined for $(x).)
exit(1)
################################################################################
# Function to build a library
OCamlLibrary(lib) =
mkdir -p _build/lib/$(lib)
vmount(-c, lib/$(lib)/, _build/lib/$(lib)/)
PACKAGES = $(PACKAGES $(lib))
LIB_DEPS = $(LIB_DEPS $(lib))
OCAMLC = ocamlfind ocamlc \
-package $(concat \,, $(PACKAGES)) \
$(foreach $(fun x => $(array -I ../$(x))), $(LIB_DEPS))
OCAMLOPT = ocamlfind ocamlopt \
-package $(concat \,, $(PACKAGES)) \
$(foreach $(fun x => $(array -I ../$(x))), $(LIB_DEPS))
OCAMLDEP = ocamlfind ocamldep \
-one-line \
-package $(concat \,, $(PACKAGES))
if $(USE_CAMLP4O $(lib))
OCAMLC += -syntax camlp4o
export OCAMLC
OCAMLOPT += -syntax camlp4o
export OCAMLOPT
OCAMLDEP += -syntax camlp4o
export OCAMLDEP
M4_FILES = $(basename $(glob -i, $(ROOT)/lib/$(lib)/*.ml.m4))
ML_FILES[] =
$(removesuffix $(M4_FILES))
$(basename $(shell $(OCAMLDEP) -sort $(glob -i, $(ROOT)/lib/$(lib)/*.ml)))
MLI_FILES = $(basename $(glob -i, $(ROOT)/lib/$(lib)/*.mli))
M4_BASES = $(removesuffix $(M4_FILES))
ML_BASES = $(removesuffix $(ML_FILES))
MLI_BASES = $(removesuffix $(MLI_FILES))
ML_MLI_BASES = $(intersection $(ML_BASES), $(MLI_BASES))
ML_NO_MLI_BASES = $(set-diff $(ML_BASES), $(MLI_BASES))
CMA_DEPS = $(foreach $(fun x => ../$(x)/$(x).cma), $(LIB_DEPS))
CMXA_DEPS = $(foreach $(fun x => ../$(x)/$(x).cmxa), $(LIB_DEPS))
PACK_NAME = $(lib)
.SUBDIRS: _build/lib/$(lib)
.INCLUDE: .depend: $(ML_FILES) $(MLI_FILES)
rm -f $@
$(OCAMLDEP) $+ > $@
%.ml: %.ml.m4 :value: $(VERSION) :value: $(GIT_COMMIT)
m4 -D VERSION=$(VERSION) -D GIT_COMMIT=$(GIT_COMMIT) $< > $@
if $(BYTE_ENABLED)
foreach(x => ..., $(ML_MLI_BASES))
$(x).cmi: $(x).mli $(CMA_DEPS)
$(OCAMLC) -c $<
$(x).cmo: $(x).ml $(x).cmi
$(OCAMLC) -c $<
foreach(x => ..., $(ML_NO_MLI_BASES))
$(x).cmo: $(x).ml $(CMA_DEPS)
$(OCAMLC) -c $<
$(PACK_NAME).cmo: $(replacesuffixes .ml, .cmo, $(ML_FILES))
$(OCAMLC) -pack -o $@ $+
$(lib).cma: $(PACK_NAME).cmo
$(OCAMLC) -a -o $@ $<
.DEFAULT: $(lib).cma
if $(NATIVE_ENABLED)
foreach(x => ..., $(ML_MLI_BASES))
$(x).cmi: $(x).mli $(CMXA_DEPS)
$(OCAMLOPT) -c $<
$(x).cmx: $(x).ml $(x).cmi
$(OCAMLOPT) -for-pack $(capitalize $(PACK_NAME)) -c $<
foreach(x => ..., $(ML_NO_MLI_BASES))
$(x).cmx: $(x).ml $(CMXA_DEPS)
$(OCAMLOPT) -for-pack $(capitalize $(PACK_NAME)) -c $<
$(PACK_NAME).cmx: $(replacesuffixes .ml, .cmx, $(ML_FILES))
$(OCAMLOPT) -pack -o $@ $+
$(lib).cmxa: $(PACK_NAME).cmx
$(OCAMLOPT) -a -o $@ $<
.DEFAULT: $(lib).cmxa
.SUBDIRS: .
foreach(x => ..., $(basename $(subdirs -P, lib)))
OCamlLibrary($(x))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment