| ##===- tools/ml/Makefile -----------------------------------*- Makefile -*-===## |
| # |
| # The LLVM Compiler Infrastructure |
| # |
| # This file is distributed under the University of Illinois Open Source |
| # License. See LICENSE.TXT for details. |
| # |
| ##===----------------------------------------------------------------------===## |
| # |
| # An ocaml library is a unique project type in the context of LLVM, so rules are |
| # here rather than in Makefile.rules. |
| # |
| # Reference materials on installing ocaml libraries: |
| # |
| # https://fedoraproject.org/wiki/Packaging/OCaml |
| # http://pkg-ocaml-maint.alioth.debian.org/ocaml_packaging_policy.txt |
| # |
| ##===----------------------------------------------------------------------===## |
| |
| include $(LEVEL)/Makefile.config |
| |
| # CFLAGS needs to be set before Makefile.rules is included. |
| CXX.Flags += -I"$(shell $(OCAMLC) -where)" |
| C.Flags += -I"$(shell $(OCAMLC) -where)" |
| |
| include $(LEVEL)/Makefile.common |
| |
| # Intentionally ignore PROJ_prefix here. We want the ocaml stdlib. However, the |
| # user can override this with OCAML_LIBDIR or configure --with-ocaml-libdir=. |
| PROJ_libocamldir := $(DESTDIR)$(OCAML_LIBDIR) |
| OcamlDir := $(LibDir)/ocaml |
| |
| # Info from llvm-config and similar |
| ifndef IS_CLEANING_TARGET |
| ifdef UsedComponents |
| UsedLibs = $(shell $(LLVM_CONFIG) --libs $(UsedComponents)) |
| UsedLibNames = $(shell $(LLVM_CONFIG) --libnames $(UsedComponents)) |
| endif |
| endif |
| |
| # Tools |
| OCAMLCFLAGS += -I $(ObjDir) -I $(OcamlDir) |
| ifndef IS_CLEANING_TARGET |
| ifneq ($(ObjectsO),) |
| OCAMLAFLAGS += $(patsubst %,-cclib %, \ |
| $(filter-out -L$(LibDir),-l$(LIBRARYNAME) \ |
| $(shell $(LLVM_CONFIG) --ldflags)) \ |
| $(UsedLibs)) |
| else |
| OCAMLAFLAGS += $(patsubst %,-cclib %, \ |
| $(filter-out -L$(LibDir),$(shell $(LLVM_CONFIG) --ldflags)) \ |
| $(UsedLibs)) |
| endif |
| endif |
| |
| # -g was introduced in 3.10.0. |
| #ifneq ($(ENABLE_OPTIMIZED),1) |
| # OCAMLDEBUGFLAG := -g |
| #endif |
| |
| Compile.CMI := $(strip $(OCAMLC) -c $(OCAMLCFLAGS) $(OCAMLDEBUGFLAG) -o) |
| Compile.CMO := $(strip $(OCAMLC) -c $(OCAMLCFLAGS) $(OCAMLDEBUGFLAG) -o) |
| Archive.CMA := $(strip $(OCAMLC) -a -custom $(OCAMLAFLAGS) $(OCAMLDEBUGFLAG) \ |
| -o) |
| |
| Compile.CMX := $(strip $(OCAMLOPT) -c $(OCAMLCFLAGS) $(OCAMLDEBUGFLAG) -o) |
| Archive.CMXA := $(strip $(OCAMLOPT) -a $(OCAMLAFLAGS) $(OCAMLDEBUGFLAG) -o) |
| |
| ifdef OCAMLOPT |
| Archive.EXE := $(strip $(OCAMLOPT) -cc $(CXX) $(OCAMLCFLAGS) $(UsedOcamLibs:%=%.cmxa) $(OCAMLDEBUGFLAG) -o) |
| else |
| Archive.EXE := $(strip $(OCAMLC) -cc $(CXX) $(OCAMLCFLAGS) $(OCAMLDEBUGFLAG:%=%.cma) -o) |
| endif |
| |
| # Source files |
| ifndef OcamlSources1 |
| OcamlSources1 := $(sort $(wildcard $(PROJ_SRC_DIR)/*.ml)) |
| endif |
| |
| ifndef OcamlHeaders1 |
| OcamlHeaders1 := $(sort $(wildcard $(PROJ_SRC_DIR)/*.mli)) |
| endif |
| |
| OcamlSources2 := $(filter-out $(ExcludeSources),$(OcamlSources1)) |
| OcamlHeaders2 := $(filter-out $(ExcludeHeaders),$(OcamlHeaders1)) |
| |
| OcamlSources := $(OcamlSources2:$(PROJ_SRC_DIR)/%=$(ObjDir)/%) |
| OcamlHeaders := $(OcamlHeaders2:$(PROJ_SRC_DIR)/%=$(ObjDir)/%) |
| |
| # Intermediate files |
| ObjectsCMI := $(OcamlSources:%.ml=%.cmi) |
| ObjectsCMO := $(OcamlSources:%.ml=%.cmo) |
| ObjectsCMX := $(OcamlSources:%.ml=%.cmx) |
| |
| ifdef LIBRARYNAME |
| LibraryCMA := $(ObjDir)/$(LIBRARYNAME).cma |
| LibraryCMXA := $(ObjDir)/$(LIBRARYNAME).cmxa |
| endif |
| |
| ifdef TOOLNAME |
| ToolEXE := $(ObjDir)/$(TOOLNAME)$(EXEEXT) |
| endif |
| |
| # Output files |
| # The .cmo files are the only intermediates; all others are to be installed. |
| OutputsCMI := $(ObjectsCMI:$(ObjDir)/%.cmi=$(OcamlDir)/%.cmi) |
| OutputsCMX := $(ObjectsCMX:$(ObjDir)/%.cmx=$(OcamlDir)/%.cmx) |
| OutputLibs := $(UsedLibNames:%=$(OcamlDir)/%) |
| |
| ifdef LIBRARYNAME |
| LibraryA := $(OcamlDir)/lib$(LIBRARYNAME).a |
| OutputCMA := $(LibraryCMA:$(ObjDir)/%.cma=$(OcamlDir)/%.cma) |
| OutputCMXA := $(LibraryCMXA:$(ObjDir)/%.cmxa=$(OcamlDir)/%.cmxa) |
| endif |
| |
| ifdef TOOLNAME |
| ifdef EXAMPLE_TOOL |
| OutputEXE := $(ExmplDir)/$(strip $(TOOLNAME))$(EXEEXT) |
| else |
| OutputEXE := $(ToolDir)/$(strip $(TOOLNAME))$(EXEEXT) |
| endif |
| endif |
| |
| # Installation targets |
| DestLibs := $(UsedLibNames:%=$(PROJ_libocamldir)/%) |
| |
| ifdef LIBRARYNAME |
| DestA := $(PROJ_libocamldir)/lib$(LIBRARYNAME).a |
| DestCMA := $(PROJ_libocamldir)/$(LIBRARYNAME).cma |
| DestCMXA := $(PROJ_libocamldir)/$(LIBRARYNAME).cmxa |
| endif |
| |
| ##===- Dependencies -------------------------------------------------------===## |
| # Copy the sources into the intermediate directory because older ocamlc doesn't |
| # support -o except when linking (outputs are placed next to inputs). |
| |
| $(ObjDir)/%.mli: $(PROJ_SRC_DIR)/%.mli $(ObjDir)/.dir |
| $(Verb) $(CP) -f $< $@ |
| |
| $(ObjDir)/%.ml: $(PROJ_SRC_DIR)/%.ml $(ObjDir)/.dir |
| $(Verb) $(CP) -f $< $@ |
| |
| $(ObjectsCMI): $(UsedOcamlInterfaces:%=$(OcamlDir)/%.cmi) |
| |
| ifdef LIBRARYNAME |
| $(ObjDir)/$(LIBRARYNAME).ocamldep: $(OcamlSources) $(OcamlHeaders) \ |
| $(OcamlDir)/.dir $(ObjDir)/.dir |
| $(Verb) $(OCAMLDEP) $(OCAMLCFLAGS) $(OcamlSources) $(OcamlHeaders) > $@ |
| |
| -include $(ObjDir)/$(LIBRARYNAME).ocamldep |
| endif |
| |
| ifdef TOOLNAME |
| $(ObjDir)/$(TOOLNAME).ocamldep: $(OcamlSources) $(OcamlHeaders) \ |
| $(OcamlDir)/.dir $(ObjDir)/.dir |
| $(Verb) $(OCAMLDEP) $(OCAMLCFLAGS) $(OcamlSources) $(OcamlHeaders) > $@ |
| |
| -include $(ObjDir)/$(TOOLNAME).ocamldep |
| endif |
| |
| ##===- Build static library from C sources --------------------------------===## |
| |
| ifdef LibraryA |
| all-local:: $(LibraryA) |
| clean-local:: clean-a |
| install-local:: install-a |
| uninstall-local:: uninstall-a |
| |
| $(LibraryA): $(ObjectsO) $(OcamlDir)/.dir |
| $(Echo) "Building $(BuildMode) $(notdir $@)" |
| -$(Verb) $(RM) -f $@ |
| $(Verb) $(Archive) $@ $(ObjectsO) |
| $(Verb) $(Ranlib) $@ |
| |
| clean-a:: |
| -$(Verb) $(RM) -f $(LibraryA) |
| |
| install-a:: $(LibraryA) |
| $(Echo) "Installing $(BuildMode) $(DestA)" |
| $(Verb) $(MKDIR) $(PROJ_libocamldir) |
| $(Verb) $(INSTALL) $(LibraryA) $(DestA) |
| $(Verb) |
| |
| uninstall-a:: |
| $(Echo) "Uninstalling $(DestA)" |
| -$(Verb) $(RM) -f $(DestA) |
| endif |
| |
| |
| ##===- Deposit dependent libraries adjacent to Ocaml libs -----------------===## |
| |
| all-local:: build-deplibs |
| clean-local:: clean-deplibs |
| install-local:: install-deplibs |
| uninstall-local:: uninstall-deplibs |
| |
| build-deplibs: $(OutputLibs) |
| |
| $(OcamlDir)/%.a: $(LibDir)/%.a |
| $(Verb) ln -sf $< $@ |
| |
| $(OcamlDir)/%.o: $(LibDir)/%.o |
| $(Verb) ln -sf $< $@ |
| |
| clean-deplibs: |
| $(Verb) $(RM) -f $(OutputLibs) |
| |
| install-deplibs: |
| $(Verb) $(MKDIR) $(PROJ_libocamldir) |
| $(Verb) for i in $(DestLibs:$(PROJ_libocamldir)/%=%); do \ |
| ln -sf "$(PROJ_libdir)/$$i" "$(PROJ_libocamldir)/$$i"; \ |
| done |
| |
| uninstall-deplibs: |
| $(Verb) $(RM) -f $(DestLibs) |
| |
| |
| ##===- Build ocaml interfaces (.mli's -> .cmi's) --------------------------===## |
| |
| ifneq ($(OcamlHeaders),) |
| all-local:: build-cmis |
| clean-local:: clean-cmis |
| install-local:: install-cmis |
| uninstall-local:: uninstall-cmis |
| |
| build-cmis: $(OutputsCMI) |
| |
| $(OcamlDir)/%.cmi: $(ObjDir)/%.cmi $(OcamlDir)/.dir |
| $(Verb) $(CP) -f $< $@ |
| |
| $(ObjDir)/%.cmi: $(ObjDir)/%.mli $(ObjDir)/.dir |
| $(Echo) "Compiling $(notdir $<) for $(BuildMode) build" |
| $(Verb) $(Compile.CMI) $@ $< |
| |
| clean-cmis:: |
| -$(Verb) $(RM) -f $(OutputsCMI) |
| |
| # Also install the .mli's (headers) as documentation. |
| install-cmis: $(OutputsCMI) $(OcamlHeaders) |
| $(Verb) $(MKDIR) $(PROJ_libocamldir) |
| $(Verb) for i in $(OcamlHeaders:$(ObjDir)/%=%); do \ |
| $(EchoCmd) "Installing $(BuildMode) $(PROJ_libocamldir)/$$i"; \ |
| $(DataInstall) $(ObjDir)/$$i "$(PROJ_libocamldir)/$$i"; \ |
| done |
| $(Verb) for i in $(OutputsCMI:$(OcamlDir)/%=%); do \ |
| $(EchoCmd) "Installing $(BuildMode) $(PROJ_libocamldir)/$$i"; \ |
| $(DataInstall) $(OcamlDir)/$$i "$(PROJ_libocamldir)/$$i"; \ |
| done |
| |
| uninstall-cmis:: |
| $(Verb) for i in $(OutputsCMI:$(OcamlDir)/%=%); do \ |
| $(EchoCmd) "Uninstalling $(PROJ_libocamldir)/$$i"; \ |
| $(RM) -f "$(PROJ_libocamldir)/$$i"; \ |
| done |
| $(Verb) for i in $(OcamlHeaders:$(ObjDir)/%=%); do \ |
| $(EchoCmd) "Uninstalling $(PROJ_libocamldir)/$$i"; \ |
| $(RM) -f "$(PROJ_libocamldir)/$$i"; \ |
| done |
| endif |
| |
| |
| ##===- Build ocaml bytecode archive (.ml's -> .cmo's -> .cma) -------------===## |
| |
| $(ObjDir)/%.cmo: $(ObjDir)/%.ml |
| $(Echo) "Compiling $(notdir $<) for $(BuildMode) build" |
| $(Verb) $(Compile.CMO) $@ $< |
| |
| ifdef LIBRARYNAME |
| all-local:: $(OutputCMA) |
| clean-local:: clean-cma |
| install-local:: install-cma |
| uninstall-local:: uninstall-cma |
| |
| $(OutputCMA): $(LibraryCMA) $(OcamlDir)/.dir |
| $(Verb) $(CP) -f $< $@ |
| |
| $(LibraryCMA): $(ObjectsCMO) $(OcamlDir)/.dir |
| $(Echo) "Archiving $(notdir $@) for $(BuildMode) build" |
| $(Verb) $(Archive.CMA) $@ $(ObjectsCMO) |
| |
| clean-cma:: |
| $(Verb) $(RM) -f $(OutputCMA) $(UsedLibNames:%=$(OcamlDir)/%) |
| |
| install-cma:: $(OutputCMA) |
| $(Echo) "Installing $(BuildMode) $(DestCMA)" |
| $(Verb) $(MKDIR) $(PROJ_libocamldir) |
| $(Verb) $(DataInstall) $(OutputCMA) "$(DestCMA)" |
| |
| uninstall-cma:: |
| $(Echo) "Uninstalling $(DestCMA)" |
| -$(Verb) $(RM) -f $(DestCMA) |
| endif |
| |
| ##===- Build optimized ocaml archive (.ml's -> .cmx's -> .cmxa, .a) -------===## |
| |
| # The ocamlopt compiler is supported on a set of targets disjoint from LLVM's. |
| # If unavailable, 'configure' will not define OCAMLOPT in Makefile.config. |
| ifdef OCAMLOPT |
| |
| $(OcamlDir)/%.cmx: $(ObjDir)/%.cmx |
| $(Verb) $(CP) -f $< $@ |
| |
| $(ObjDir)/%.cmx: $(ObjDir)/%.ml |
| $(Echo) "Compiling optimized $(notdir $<) for $(BuildMode) build" |
| $(Verb) $(Compile.CMX) $@ $< |
| |
| ifdef LIBRARYNAME |
| all-local:: $(OutputCMXA) $(OutputsCMX) |
| clean-local:: clean-cmxa |
| install-local:: install-cmxa |
| uninstall-local:: uninstall-cmxa |
| |
| $(OutputCMXA): $(LibraryCMXA) |
| $(Verb) $(CP) -f $< $@ |
| $(Verb) $(CP) -f $(<:.cmxa=.a) $(@:.cmxa=.a) |
| |
| $(LibraryCMXA): $(ObjectsCMX) |
| $(Echo) "Archiving $(notdir $@) for $(BuildMode) build" |
| $(Verb) $(Archive.CMXA) $@ $(ObjectsCMX) |
| $(Verb) $(RM) -f $(@:.cmxa=.o) |
| |
| clean-cmxa:: |
| $(Verb) $(RM) -f $(OutputCMXA) $(OutputCMXA:.cmxa=.a) $(OutputsCMX) |
| |
| install-cmxa:: $(OutputCMXA) $(OutputsCMX) |
| $(Verb) $(MKDIR) $(PROJ_libocamldir) |
| $(Echo) "Installing $(BuildMode) $(DestCMXA)" |
| $(Verb) $(DataInstall) $(OutputCMXA) $(DestCMXA) |
| $(Echo) "Installing $(BuildMode) $(DestCMXA:.cmxa=.a)" |
| $(Verb) $(DataInstall) $(OutputCMXA:.cmxa=.a) $(DestCMXA:.cmxa=.a) |
| $(Verb) for i in $(OutputsCMX:$(OcamlDir)/%=%); do \ |
| $(EchoCmd) "Installing $(BuildMode) $(PROJ_libocamldir)/$$i"; \ |
| $(DataInstall) $(OcamlDir)/$$i "$(PROJ_libocamldir)/$$i"; \ |
| done |
| |
| uninstall-cmxa:: |
| $(Echo) "Uninstalling $(DestCMXA)" |
| $(Verb) $(RM) -f $(DestCMXA) |
| $(Echo) "Uninstalling $(DestCMXA:.cmxa=.a)" |
| $(Verb) $(RM) -f $(DestCMXA:.cmxa=.a) |
| $(Verb) for i in $(OutputsCMX:$(OcamlDir)/%=%); do \ |
| $(EchoCmd) "Uninstalling $(PROJ_libocamldir)/$$i"; \ |
| $(RM) -f $(PROJ_libocamldir)/$$i; \ |
| done |
| endif |
| endif |
| |
| ##===- Build executables --------------------------------------------------===## |
| |
| ifdef TOOLNAME |
| all-local:: $(OutputEXE) |
| clean-local:: clean-exe |
| |
| $(OutputEXE): $(ToolEXE) $(OcamlDir)/.dir |
| $(Verb) $(CP) -f $< $@ |
| |
| ifndef OCAMLOPT |
| $(ToolEXE): $(ObjectsCMO) $(OcamlDir)/.dir |
| $(Echo) "Archiving $(notdir $@) for $(BuildMode) build" |
| $(Verb) $(Archive.EXE) $@ $(ObjectsCMO) |
| else |
| $(ToolEXE): $(ObjectsCMX) $(OcamlDir)/.dir |
| $(Echo) "Archiving $(notdir $@) for $(BuildMode) build" |
| $(Verb) $(Archive.EXE) $@ $(ObjectsCMX) |
| endif |
| endif |
| |
| ##===- Generate documentation ---------------------------------------------===## |
| |
| $(ObjDir)/$(LIBRARYNAME).odoc: $(ObjectsCMI) |
| $(Echo) "Documenting $(notdir $@)" |
| $(Verb) $(OCAMLDOC) -I $(ObjDir) -I $(OcamlDir) -dump $@ $(OcamlHeaders) |
| |
| ocamldoc: $(ObjDir)/$(LIBRARYNAME).odoc |
| |
| ##===- Debugging gunk -----------------------------------------------------===## |
| printvars:: printcamlvars |
| |
| printcamlvars:: |
| $(Echo) "LLVM_CONFIG : " '$(LLVM_CONFIG)' |
| $(Echo) "OCAMLCFLAGS : " '$(OCAMLCFLAGS)' |
| $(Echo) "OCAMLAFLAGS : " '$(OCAMLAFLAGS)' |
| $(Echo) "OCAMLC : " '$(OCAMLC)' |
| $(Echo) "OCAMLOPT : " '$(OCAMLOPT)' |
| $(Echo) "OCAMLDEP : " '$(OCAMLDEP)' |
| $(Echo) "Compile.CMI : " '$(Compile.CMI)' |
| $(Echo) "Compile.CMO : " '$(Compile.CMO)' |
| $(Echo) "Archive.CMA : " '$(Archive.CMA)' |
| $(Echo) "Compile.CMX : " '$(Compile.CMX)' |
| $(Echo) "Archive.CMXA : " '$(Archive.CMXA)' |
| $(Echo) "CAML_LIBDIR : " '$(CAML_LIBDIR)' |
| $(Echo) "LibraryCMA : " '$(LibraryCMA)' |
| $(Echo) "LibraryCMXA : " '$(LibraryCMXA)' |
| $(Echo) "OcamlSources1: " '$(OcamlSources1)' |
| $(Echo) "OcamlSources2: " '$(OcamlSources2)' |
| $(Echo) "OcamlSources : " '$(OcamlSources)' |
| $(Echo) "OcamlHeaders1: " '$(OcamlHeaders1)' |
| $(Echo) "OcamlHeaders2: " '$(OcamlHeaders2)' |
| $(Echo) "OcamlHeaders : " '$(OcamlHeaders)' |
| $(Echo) "ObjectsCMI : " '$(ObjectsCMI)' |
| $(Echo) "ObjectsCMO : " '$(ObjectsCMO)' |
| $(Echo) "ObjectsCMX : " '$(ObjectsCMX)' |
| $(Echo) "OCAML_LIBDIR : " '$(OCAML_LIBDIR)' |
| $(Echo) "DestA : " '$(DestA)' |
| $(Echo) "DestCMA : " '$(DestCMA)' |
| $(Echo) "DestCMXA : " '$(DestCMXA)' |
| $(Echo) "UsedLibs : " '$(UsedLibs)' |
| $(Echo) "UsedLibNames : " '$(UsedLibNames)' |
| |
| .PHONY: printcamlvars build-cmis \ |
| clean-a clean-cmis clean-cma clean-cmxa \ |
| install-a install-cmis install-cma install-cmxa \ |
| install-exe \ |
| uninstall-a uninstall-cmis uninstall-cma uninstall-cmxa \ |
| uninstall-exe |