Last active
October 2, 2015 21:29
-
-
Save agarwal/c75e56b200050343fdbb to your computer and use it in GitHub Desktop.
OMake function to build an OCaml library.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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