# This -*- makefile -*- is part of our build system for OCaml projects # Copyright (C) 2008, 2009 Luca Saiu # Copyright (C) 2008, 2010, 2016 Jean-Vincent Loddo # Copyright (C) 2008, 2009, 2010, 2016 Université Paris 13 # Updated in 2008 by Jonathan Roudiere # Thanks to JulioJu (https://github.com/JulioJu) for the patch # about prefix_install # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This is the revision of 2016-06-07. ###################################################################### # This make file is general-purpose: the actual project-dependant part # should be written for each specific project in a 'Makefile.local' # file. # # This contains some (simple) makefile magic which is only supported # by GNU Make. Don't even try to use other make implementations. ###################################################################### ###################################################################### # Implementation of targets. Note that the user is *not* supposed to # override these, but only to define the project-dependant '-local' # versions: # Makefiles (this one as those in other parts) use extensively the bash shell SHELL=/bin/bash OCAMLBUILD = $$( $(call OCAMLBUILD_COMMAND_LINE) ) LIBRARYPREFIX=$(shell $(call READ_CONFIG, libraryprefix); echo $$libraryprefix) OCAML_VERSION=$(shell $(call READ_CONFIG, ocaml_version); echo $$ocaml_version) OCAML_LIBRARYPREFIX=$(shell $(call READ_CONFIG, ocaml_libraryprefix); echo $$ocaml_libraryprefix) # The main target. Its implementation is entirely project-dependant: main: ocamlbuild-stuff manually_pre_actions main-local data libraries programs manually_post_actions @(echo "Success.") # Build C modules (no one, by default): c-modules: @(mkdir _build &> /dev/null || true) && \ for x in $(C_OBJECTS_TO_LINK); do \ make _build/$$x.o; \ done BUILD_FROM_STUFF = \ @( echo "Building $(1)..."; \ shopt -s execfail; set -e; \ for x in $(2); do \ echo "Building \"$$x\"..."; \ if $(MAKE) $$x; then \ echo "Ok, \"$$x\" was built with success."; \ else \ echo "FAILED when building \"$$x\"."; \ exit -1; \ fi; \ done; \ echo "Success: $(1) were built.") # Build only data: data: ocamlbuild-stuff data-local $(DATA) $(call BUILD_FROM_STUFF, data, $(DATA)) # Build only native libraries: native-libraries: ocamlbuild-stuff c-modules native-libraries-local $(NATIVE_LIBRARIES) $(call BUILD_FROM_STUFF, native-libraries, $(NATIVE_LIBRARIES)) # Build only bytecode libraries: byte-libraries: ocamlbuild-stuff c-modules byte-libraries-local $(BYTE_LIBRARIES) $(call BUILD_FROM_STUFF, byte-libraries, $(BYTE_LIBRARIES)) # Build libraries; bytecode, native, or both: libraries: c-modules libraries-local @($(call BUILD_NATIVE_ANDOR_BYTECODE,libraries) ) # Spaces are ok # Build programs; bytecode, native, or both: programs: c-modules programs-local @($(call BUILD_NATIVE_ANDOR_BYTECODE,programs) ) # Spaces are ok # Build the native and/or bytecode version of $(1). $(1) may be either # "libraries" or "programs". *Don't* put a space before the argument. BUILD_NATIVE_ANDOR_BYTECODE = \ (if [ "$$( $(call NATIVE) )" == 'native' ]; then \ echo "Building native $(1)..."; \ if $(MAKE) native-$(1); then \ echo "Success: native $(1) were built."; \ else \ echo "FAILURE: could not build native $(1)."; \ exit -1; \ fi; \ else \ echo "NOT building native $(1)..."; \ fi; \ if [ "$$( $(call BYTE) )" == 'byte' ]; then \ echo "Builing bytecode $(1)..."; \ if $(MAKE) byte-$(1); then \ echo "Success: bytecode $(1) were built."; \ else \ echo "FAILURE: could not build bytecode $(1)."; \ exit -1; \ fi; \ else \ echo "NOT building bytecode $(1)..."; \ fi) # Build only native programs: native-programs: ocamlbuild-stuff native-programs-local $(NATIVE_PROGRAMS) $(ROOT_NATIVE_PROGRAMS) $(call BUILD_FROM_STUFF, native-programs, $(NATIVE_PROGRAMS) $(ROOT_NATIVE_PROGRAMS)) # Build only bytecode programs: byte-programs: ocamlbuild-stuff byte-programs-local $(BYTE_PROGRAMS) $(ROOT_BYTE_PROGRAMS) $(call BUILD_FROM_STUFF, byte-programs, $(BYTE_PROGRAMS) $(ROOT_BYTE_PROGRAMS)) # 'all' is just an alias for 'main': all: main # In some projects we may need to build something more than 'main', # but we do nothing more by default: world: world-local main @(echo 'Success.') ############################################################################ # Support for manually generated files (i.e. not generated with ocamlbuild) ############################################################################ # Example: (in your Makefile.local) # # foo.byte : manually_pre_actions # foo.native : manually_pre_actions # # MANUALLY_PRE_COPY_IN_build = include_as_string_p4.ml USAGE.txt # MANUALLY_PRE_MAKE_IN_build = include_as_string_p4.cmo # # _build/include_as_string_p4.cmo: include_as_string_p4.ml # ocamlc -c -I +camlp4 camlp4lib.cma -pp camlp4of -o $@ $< .PHONY : manually_pre_actions manually_post_actions ################################# PRE-ACTIONS support # Files that must be copied in _build/ *before* the ocamlbuild processing. MANUALLY_PRE_COPY_IN_build = # Targets that must be created in _build/ *before* the ocamlbuild processing. # For each foo.bar that appears in this list, you have to write a rule # _build/foo.bar in your Makefile.local MANUALLY_PRE_MAKE_IN_build = manually_pre_actions: $(call PERFORM_MANUALLY_PRE_ACTIONS, $(MANUALLY_PRE_COPY_IN_build),$(MANUALLY_PRE_MAKE_IN_build)) # Detect if "make clean" is required or copy and build manually targets # specified in MANUALLY_PRE_COPY_IN_build and MANUALLY_PRE_MAKE_IN_build PERFORM_MANUALLY_PRE_ACTIONS = \ @(\ if test -d _build/; \ then \ echo "Checking if files manually copied in _build/ have been modified..."; \ for x in $(1); do \ echo "Checking \"$$x\"..."; \ test ! -f _build/$$x || \ diff -q $$x _build/$$x 2>/dev/null || \ { echo -e "********************\nmake clean required!\n********************"; exit 1; } ;\ done; \ else \ mkdir _build/; \ fi; \ for x in $(1); do echo "Manually pre-copying \"$$x\"..."; cp --parent -f $$x _build/; done; \ for y in $(2); do echo "Manually pre-building \"$$y\"..."; make _build/$$y || exit 1; done; \ ) ################################# POST-ACTIONS support # Files that must be copied in _build/ *after* the ocamlbuild processing. MANUALLY_POST_COPY_IN_build = # Targets that must be created in _build/ *after* the ocamlbuild processing. # For each foo.bar that appears in this list, you have to write a rule # _build/foo.bar in your Makefile.local MANUALLY_POST_MAKE_IN_build = manually_post_actions: $(call PERFORM_MANUALLY_POST_ACTIONS, $(MANUALLY_POST_COPY_IN_build), $(MANUALLY_POST_MAKE_IN_build)) PERFORM_MANUALLY_POST_ACTIONS = \ @(\ for x in $(1); do echo "Manually post-copying \"$$x\"..."; cp --parent -f $$x _build/; done; \ for y in $(2); do echo "Manually post-building \"$$y\"..."; make _build/$$y || exit 1; done; \ ) ############################################################################ # Other entries # Edit all ml/mli files and Makefile.local with your $EDITOR edit: test -n "$$EDITOR" && eval $$EDITOR Makefile.local $$(find . \( -name "_build*" -o -name "meta.ml" -o -name "$(EXCLUDE_FROM_EDITING)" -o -name "version.ml" -o -name "gui.ml" -o -name myocamlbuild.ml \) -prune -o -type f -a \( -name "*.ml" -o -name "*.mli" \) -print) & # Create the documentation documentation: world documentation-local chmod +x Makefile.d/doc.sh Makefile.d/doc.sh -pp "$(PP_OPTION)" -e "$(UNDOCUMENTED)" -i $(DIRECTORIES_TO_INCLUDE) doc: documentation INDEX_HTML=_build/doc/html/index.html browse: test -f $(INDEX_HTML) || make documentation test -n "$$BROWSER" && $$BROWSER $(INDEX_HTML) # Install programs and libraries: install: install-programs install-libraries install-data install-configuration install-documentation install-local @(echo 'Success.') # The user is free to override this to add custom targets to install into the # $prefix_install/share/$name installation directory: OTHER_DATA_TO_INSTALL = # The user is free to override this to add custom targets to install into the # $documentationprefix/$name installation directory: OTHER_DOCUMENTATION_TO_INSTALL = # Install the documentation from this package (_build/doc) into $prefix_install/share/$name: install-documentation: META CONFIGME install-documentation-local @($(call READ_CONFIG, documentationprefix); \ $(call READ_META, name); \ directory=$$documentationprefix/$$name; \ shopt -s nullglob; \ if [ -e _build/doc ]; then \ documentationifany=`ls -d _build/doc/*`; \ else \ documentationifany=''; \ fi; \ if [ "$$documentationifany" == "" ]; then \ echo "No documentation to install: ok, no problem..."; \ else \ echo "Installing $$name documentation into $$directory ..."; \ echo "Creating $$directory ..."; \ if mkdir -p $$directory; then \ echo "The directory $$directory was created with success."; \ else \ echo "Could not create $$directory"; \ exit -1; \ fi; \ echo "Copying $$name documentation to $$directory ..."; \ for x in COPYING README $$documentationifany $(OTHER_DOCUMENTATION_TO_INSTALL); do \ if cp -af $$x $$directory; then \ echo "Installed $$x into $$directory/"; \ else \ echo "Could not write $$directory/$$x."; \ exit -1; \ fi; \ done; \ echo "Documentation installation for $$name was successful."; \ fi) # Just a handy alias: install-doc: install-documentation # Install the data from this package into $prefix_install/share/$name: install-data: META CONFIGME main install-data-local @($(call READ_CONFIG, prefix_install); \ $(call READ_META, name); \ directory=$$prefix_install/share/$$name; \ shopt -s nullglob; \ if [ -e share ]; then \ dataifany=`ls -d share/*`; \ else \ dataifany=''; \ fi; \ if [ "$$dataifany" == "" ]; then \ echo "No data to install: ok, no problem..."; \ else \ echo "Installing $$name data into $$directory ..."; \ echo "Creating $$directory ..."; \ if mkdir -p $$directory; then \ echo "The directory $$directory was created with success."; \ else \ echo "Could not create $$directory"; \ exit -1; \ fi; \ echo "Copying $$name data to $$directory ..."; \ for x in COPYING README $$dataifany $(OTHER_DATA_TO_INSTALL); do \ if cp -af $$x $$directory; then \ echo "Installed $$x into $$directory/"; \ else \ echo "Could not write $$directory/$$x."; \ exit -1; \ fi; \ done; \ echo "Data installation for $$name was successful."; \ fi) # Install the software configuration files, if any: install-configuration: META CONFIGME install-configuration-local @($(call READ_CONFIG, configurationprefix); \ $(call READ_META, name); \ if [ -e etc ]; then \ echo "Installing configuration files into $$configurationprefix/$$name..."; \ mkdir -p $$configurationprefix/$$name; \ shopt -s nullglob; \ for file in etc/*; do \ basename=`basename $$file`; \ echo "Installing $$basename into $$configurationprefix/$$name..."; \ if ! cp $$file $$configurationprefix/$$name/; then \ echo "ERROR: Could not install $$basename into $$configurationprefix/$$name"; \ exit -1; \ fi; \ done; \ else \ echo "We don't have any configuration files to install."; \ fi) # Uninstall the software configuration files, if any: uninstall-configuration: CONFIGME uninstall-configuration-local @($(call READ_CONFIG, configurationprefix); \ if [ -e etc ]; then \ echo "Removing configuration files from $$configurationprefix..."; \ shopt -s nullglob; \ for file in etc/*; do \ basename=`basename $$file`; \ echo "Uninstalling $$basename from $$configurationprefix..."; \ if ! rm -f $$configurationprefix/$$basename; then \ echo "ERROR: Could not remove $$basename from $$configurationprefix"; \ exit -1; \ fi; \ done; \ else \ echo "We don't have any configuration files to remove."; \ fi) # Remove the data of this package from $prefix_install/share/$name: uninstall-data: META CONFIGME uninstall-data-local @( ($(call READ_CONFIG, prefix_install); \ $(call READ_META, name); \ directory=$$prefix_install/share/$$name; \ echo "Removing $$name data from $$prefix_install/share/..."; \ shopt -s nullglob; \ if rm -rf $$directory; then \ echo "The entire directory $$directory was removed."; \ else \ echo "Could not delete $$directory"; \ exit -1; \ fi); \ echo 'Data uninstallation was successful.') # Remove the documentation of this package from $documentationprefix/$name: uninstall-documentation: META CONFIGME uninstall-documentation-local @( ($(call READ_CONFIG, documentationprefix); \ $(call READ_META, name); \ directory=$$documentationprefix/$$name; \ echo "Removing $$name documentation from $$documentationprefix..."; \ shopt -s nullglob; \ if rm -rf $$directory; then \ echo "The entire directory $$directory was removed."; \ else \ echo "Could not delete $$directory"; \ exit -1; \ fi); \ echo 'Documentation uninstallation was successful.') # The user is free to override this to add custom targets to install into the # $prefix_install/bin installation directory; the typical use of this would be # installing scripts. OTHER_PROGRAMS_TO_INSTALL = # These are programs to be installed into $prefix_install/sbin # instead of $prefix_install/bin: ROOT_NATIVE_PROGRAMS = ROOT_BYTE_PROGRAMS = # Install the programs from this package into $prefix_install/bin: install-programs: META CONFIGME programs install-programs-local @($(call READ_CONFIG, prefix_install); \ $(call READ_META, name); \ echo "Creating $$prefix_install/bin/..."; \ (mkdir -p $$prefix_install/bin &> /dev/null || true); \ echo "Creating $$prefix_install/sbin/..."; \ (mkdir -p $$prefix_install/sbin &> /dev/null || true); \ echo "Installing programs from $$name into $$prefix_install/bin/..."; \ shopt -s nullglob; \ for file in $(OTHER_PROGRAMS_TO_INSTALL) _build/*.byte _build/*.native; do \ basename=`basename $$file`; \ if echo " $(ROOT_NATIVE_PROGRAMS) $(ROOT_BYTE_PROGRAMS) " | grep -q " $$basename "; then \ echo "Installing "`basename $$file`" as a \"root program\" into $$prefix_install/sbin..."; \ cp -a $$file $$prefix_install/sbin/; \ chmod +x $$prefix_install/sbin/$$basename; \ else \ echo "Installing "`basename $$file`" into $$prefix_install/bin..."; \ cp -a $$file $$prefix_install/bin/; \ chmod +x $$prefix_install/bin/$$basename; \ fi; \ done) && \ echo 'Program installation was successful.' # Remove the programs from this package from $prefix_install/bin: uninstall-programs: META CONFIGME main uninstall-programs-local @($(call READ_CONFIG, prefix_install); \ $(call READ_META, name); \ echo "Removing $$name programs..."; \ shopt -s nullglob; \ for file in $(OTHER_PROGRAMS_TO_INSTALL) _build/*.byte _build/*.native; do \ basename=`basename $$file`; \ if echo " $(ROOT_NATIVE_PROGRAMS) $(ROOT_BYTE_PROGRAMS) " | grep -q " $$basename "; then \ echo -e "Removing the \"root program\" $$basename from $$prefix_install/sbin..."; \ export pathname=$$prefix_install/sbin/`basename $$file`; \ else \ echo -e "Removing $$basename from $$prefix_install/bin..."; \ export pathname=$$prefix_install/bin/`basename $$file`; \ fi; \ rm -f $$pathname; \ done) && \ echo 'Program uninstallation was successful.' # The user is free to override this to add custom targets to install into the # library installation directory: OTHER_LIBRARY_FILES_TO_INSTALL = # Install the library in this package into the path chosen at configuration time: install-libraries: libraries install-libraries-local @($(call READ_META,name); \ if [ "$(NATIVE_LIBRARIES) $(BYTE_LIBRARIES)" == " " ]; then \ echo "There are no native libraries to install: ok, no problem..."; \ else \ (echo "Installing $$name libraries into "$(LIBRARYPREFIX)"/$$name/..."; \ (mkdir -p $(LIBRARYPREFIX)/$$name &> /dev/null || true); \ shopt -s nullglob; \ cp -f META $(OTHER_LIBRARY_FILES_TO_INSTALL) \ _build/*.cma _build/*.cmxa _build/*.a _build/*.so \ `find _build/ -name \*.cm\[iox\] | grep -v /myocamlbuild` \ `find _build/ -name \*.mli | grep -v /myocamlbuild` \ $(LIBRARYPREFIX)/$$name/) && \ if test -d $(LIBRARYPREFIX)/stublibs/; then \ find _build/ -name "dll*.so" -exec cp -f "{}" $(LIBRARYPREFIX)/stublibs/ ";" ; \ fi; \ echo 'Library installation was successful.'; \ fi) # Uninstall programs and libraries: uninstall: uninstall-programs uninstall-libraries uninstall-data uninstall-configuration uninstall-documentation uninstall-local @(echo 'Success.') # Remove the library from the installation path chosen at configuration time: uninstall-libraries: main uninstall-libraries-local @(($(call READ_META,name); \ echo "Uninstalling $$name libraries from "$(LIBRARYPREFIX)" ..."; \ shopt -s nullglob; \ rm -rf $(LIBRARYPREFIX)/$$name/) && \ echo 'Library uninstallation was successful.') # Make a source tarball: dist: clean dist-local @($(call READ_META, name, version); \ $(call FIX_VERSION); \ echo "Making the source tarball _build/$$name-$$version.tar.gz ..."; \ if [ -d .bzr ]; then \ $(MAKE) meta.ml.released; \ $(MAKE) ChangeLog; \ fi; \ mkdir -p _build/$$name-$$version; \ cp -af * _build/$$name-$$version/ &> /dev/null; \ (tar --exclude=_build --exclude=meta.ml --exclude=.bzr -C _build -czf \ _build/$$name-$$version.tar.gz $$name-$$version/ && \ rm -rf _build/$$name-$$version)) && \ if [ -d .bzr ]; then \ rm -f meta.ml.released ChangeLog; \ fi; \ echo "Success." # These files are included also in binary tarballs: FILES_TO_ALWAYS_DISTRIBUTE = \ COPYING README INSTALL AUTHORS THANKS META Makefile Makefile.local CONFIGME \ REQUIREMENTS NEWS ChangeLog # Make a binary tarball: dist-binary: dist-binary-local main documentation @(($(call READ_META, name, version); \ $(call FIX_VERSION); \ architecture=$$(echo `uname -o`-`uname -m` | sed 's/\//-/g'); \ directoryname=$$name-$$version--binary-only--$$architecture; \ filename=$$directoryname.tar.gz; \ echo "Making the binary tarball _build/$$filename ..."; \ $(MAKE) ChangeLog; \ mkdir -p _build/$$directoryname; \ mkdir -p _build/$$directoryname/_build; \ shopt -s nullglob; \ for x in $(FILES_TO_ALWAYS_DISTRIBUTE) share doc etc; do \ cp $$x _build/$$directoryname &> /dev/null; \ done; \ for x in $(NATIVE_PROGRAMS) $(NATIVE_LIBRARIES) $(BYTE_PROGRAMS) $(BYTE_LIBRARIES); do \ cp _build/$$x _build/$$directoryname/_build; \ done; \ for x in `find _build/ -name \*.cmi | grep -v /my$(OCAMLBUILD) | grep -v _build/$$directoryname` \ `find _build/ -name \*.mli | grep -v /my$(OCAMLBUILD) | grep -v _build/$$directoryname` \ `find _build/ -name \*.cma | grep -v /my$(OCAMLBUILD) | grep -v _build/$$directoryname` \ `find _build/ -name \*.cmxa | grep -v /my$(OCAMLBUILD) | grep -v _build/$$directoryname` \ `find _build/ -name \*.a | grep -v /my$(OCAMLBUILD) | grep -v _build/$$directoryname` \ `find _build/ -name \*.byte | grep -v /my$(OCAMLBUILD) | grep -v _build/$$directoryname` \ `find _build/ -name \*.native | grep -v /my$(OCAMLBUILD) | grep -v _build/$$directoryname` \ ; do \ cp $$x _build/$$directoryname/_build; \ done; \ for x in _build/*.docdir; do \ cp -af $$x _build/$$directoryname; \ done; \ for x in main main-local install-libraries-local install-programs-local \ install-local install-data-local clean clean-local \ documentation documentation-local install-documentation-local \ ocamlbuild-stuff \ ; do \ echo "This dummy file prevents make from building the \"$$x\" target." \ > _build/$$directoryname/$$x; \ done; \ (tar czf _build/$$filename -C _build $$directoryname/ && \ (rm -rf _build/$$directoryname && \ rm -f ChangeLog))) && \ echo "Success.") # Automatically generate a nice ChangeLog from bzr's history: ChangeLog: @(if ! [ -d .bzr ]; then \ echo 'No ChangeLog available (bzr metadata are missing)' > $@; \ else \ bzr log --gnu-changelog > $@; \ fi) # Remove generated stuff (the ChangeLog is only removed if we have Darcs # metadata to re-generate it): clean: clean-local @(rm -rf _build; \ find -name "_build*" -prune -o -type f -name \*~ -exec rm -f {} \;; \ find -name "_build*" -prune -o -type f -name \#\*\# -exec rm -f {} \;; \ find -name "_build*" -prune -o -type f -name core -exec rm -f {} \;; \ rm -f _tags meta.ml myocamlbuild.ml; \ if [ -d .bzr ]; then \ rm -f meta.ml.released ChangeLog; \ fi; \ echo "Success.") # Meta-help about the targets defined in this make file: targets: @cat Makefile Makefile.local | grep -B 1 "^[a-z0-9_-]*[:]" | \ awk '/BEGIN/ {r=""} /^[#]/ { r=substr($$0,2); next; } /^[a-z0-9_-]*[-]local[:]/ {r=""; next} /^[a-z0-9_-]*[:]/{split($$0,a,/:/); printf("%s\r\t\t\t--- %s\n",a[1],r); r=""; next} {r=""}' | sort ###################################################################### # Default implementation for '-local' targets: # All the user-definable '-local' targets have an empty implementation # by default: main-local: world-local: data-local: native-libraries-local: byte-libraries-local: libraries-local: native-programs-local: byte-programs-local: programs-local: install-local: uninstall-local: install-programs-local: uninstall-programs-local: install-libraries-local: uninstall-libraries-local: install-data-local: uninstall-data-local: install-configuration-local: uninstall-configuration-local: install-documentation-local: uninstall-documentation-local: dist-local: dist-binary-local: documentation-local: clean-local: # Let's avoid confusion between all and main: they're the same thing # for us, and we only support main-local: all-local: echo 'all-local does not exist. Use main-local instead' exit 1 ##################################################################### # Default compilation flags. The user *is* expected to override or # extend these: DATA = NATIVE_LIBRARIES = BYTE_LIBRARIES = NATIVE_PROGRAMS = BYTE_PROGRAMS = COMPILE_OPTIONS = -thread PP_OPTION = DIRECTORIES_TO_INCLUDE = LIBRARIES_TO_LINK = OBJECTS_TO_LINK = C_OBJECTS_TO_LINK = ##################################################################### # Default rules: # Bytecode libraries: %.cma: ocamlbuild-stuff c-modules @($(OCAMLBUILD) $@) # Native libraries: %.cmxa: ocamlbuild-stuff c-modules @($(OCAMLBUILD) $@) # Bytecode programs: %.byte: ocamlbuild-stuff c-modules @($(call BUILD_WITH_OCAMLBUILD, $@) ) # Native programs: %.native: ocamlbuild-stuff c-modules @($(call BUILD_WITH_OCAMLBUILD, $@) ) # Build the target $(1) using OCamlBuild. ocamlbuild-stuff is assumed # to be already generated. BUILD_WITH_OCAMLBUILD = \ $(OCAMLBUILD) $@; \ if [ -e $@ ]; then \ rm $@; \ echo "Success: $@ was built"; \ else \ echo "FAILURE when building $@"; \ exit -1; \ fi ##################################################################### # Some macros, used internally and possibly by Makefile.local: ##################################################################### # Return 'native' if we have a native compiler available, otherwise # ''. NATIVE = \ (if which ocamlopt.opt &> /dev/null || which ocamlopt &> /dev/null ; then \ echo 'native'; \ else \ echo ''; \ fi) # Return 'byte' if we have a bytecode compiler available, otherwise # ''. BYTE = \ (if which ocamlc.opt &> /dev/null || which ocamlc &> /dev/null; then \ echo 'byte'; \ else \ echo ''; \ fi) # Return 'native' if we have a native compiler available, otherwise # 'byte' if we have a byte compiler; otherwise fail. NATIVE_OR_BYTE = \ (if [ "$$( $(call NATIVE) )" == 'native' ]; then \ echo 'native'; \ elif [ "$$( $(call BYTE) )" == 'byte' ]; then \ echo 'byte'; \ else \ echo 'FATAL ERROR: could not find an ocaml compiler' ">$$native< >$$byte<"; \ exit -1; \ fi) PROCESSOR_NO = $(shell grep "^processor.*:" /proc/cpuinfo | sort | uniq | wc -l) # The log location with respect to the directory _build/ # So, with respect to the Makefile, the log location is _build/_build/_log OCAMLBUILD_LOG=_build/_log LOGFILE=_build/$(OCAMLBUILD_LOG) # Return the proper command line for ocamlbuild, including an option # -byte-plugin if needed: OCAMLBUILD_COMMAND_LINE = \ (if [ $$( $(call NATIVE_OR_BYTE) ) == 'byte' ]; then \ echo 'ocamlbuild -j $(PROCESSOR_NO) -byte-plugin -verbose 2 -log $(OCAMLBUILD_LOG) $(OCAMLBUILD_OPTIONS)'; \ else \ echo 'ocamlbuild -j $(PROCESSOR_NO) -verbose 2 -log $(OCAMLBUILD_LOG) $(OCAMLBUILD_OPTIONS)'; \ fi) # Macro extracting, via source, the value associated to some keys # $(2),..,$(9) in a file $(1). # Example: # $(call SOURCE_AND_TEST,CONFIGME,prefix); # $(call SOURCE_AND_TEST,CONFIGME,prefix,libraryprefix); SOURCE_AND_TEST = \ if ! source $(1) &> /dev/null; then \ echo 'Evaluating $(1) failed.'; \ exit 1; \ fi; \ for i in $(2) $(3) $(4) $(5) $(6) $(7) $(8) $(9) $(10); do \ CMD="VAL=$$`echo $$i`"; eval $$CMD; \ if test -z "$$VAL"; then \ echo "FATAL: $${i} is undefined in $(1)."; \ exit 1; \ fi; \ done; \ unset CMD VAL i # Macro extracting, via grep, the value associated to keys # $(2),..,$(9) in a file $(1). # Examples: # $(call GREP_AND_TEST,META,name); # $(call GREP_AND_TEST,META,name,version); GREP_AND_TEST = \ for i in $(2) $(3) $(4) $(5) $(6) $(7) $(8) $(9) $(10); do \ if ! CMD=`grep "^$$i=" $(1)`; then \ echo "FATAL: $$i is undefined in $(1)."; \ exit 1; \ fi; \ eval $$CMD; \ done; \ unset CMD i # Instance of SOURCE_AND_TEST: source the file "CONFIGME" and test # if the given names are defined # Example: # $(call READ_CONFIG,prefix,libraryprefix); # READ_CONFIG = \ $(call SOURCE_AND_TEST,CONFIGME,$(1),$(2),$(3),$(4),$(5),$(6),$(7),$(8),$(9),$(10)) # Instance of GREP_AND_TEST: read the file "META" searching for a names # for all given names. # Example: # $(call READ_META,name,version); # READ_META = \ $(call GREP_AND_TEST,META,$(1),$(2),$(3),$(4),$(5),$(6),$(7),$(8),$(9),$(10)) # If the value of the 'version' variable contains the substring 'snapshot' then # append to its value the current date, in hacker format. 'version' must be already # defined. No arguments, no output. FIX_VERSION = \ if echo $$version | grep snapshot &> /dev/null; then \ version="$$version-"`date +"%Y-%m-%d"`; \ fi # A simple macro automatically finding all the subdirectories containing ML sources, # setting the variable 'sourcedirectories' to a string containing all such # subdirectories, alphabetically sorted, separated by spaces, and finally echo'ing # the value of sourcedirectories: SOURCE_SUBDIRECTORIES = \ sourcedirectories=''; \ for d in `find \( -path "_build*" -o -name "[.]bzr" -o -name "$(EXCLUDE_FROM_SOURCE_FINDING)" \) -prune -o -type d \ | grep -v /_build\$$ | grep -v /_build/ \ | grep -v ^.$$ | sort`; do \ if ls $$d/*.ml &> /dev/null || \ ls $$d/*.mli &> /dev/null || \ ls $$d/*.mll &> /dev/null || \ ls $$d/*.mly &> /dev/null ; then \ sourcedirectories+="$$d "; \ fi; \ done; \ echo $$sourcedirectories # Set the shell variable $(1) as the string obtained by prefixing each token # in $(2) with the prefix $(3): for example if the shell variable # 'sourcedirectories' is set to './A ./B' then # $(call ADD_PREFIX_TO_EACH_WORD, includes, $$sourcedirectories, -I) # sets the shell variable 'includes' to '-I ./A -I ./B '. # The value of $(1) is finally echo'ed. ADD_PREFIX_TO_EACH_WORD = \ $(call SOURCE_SUBDIRECTORIES); \ result=''; \ for element in $(2); do \ result+="$(3) $$element "; \ done; \ $(1)=$$result; \ echo $$result # This macro expands to the project name, extracted from META. No parameters. # Example: # echo "$(call PROJECT_NAME) is beautiful." PROJECT_NAME = \ $$( $(call GREP_AND_TEST,META,name); \ echo $$name ) # Automatically generate _tags and the $(OCAMLBUILD) plugin. Note that the # target name is never created as a file. This is intentional: those # two targets should be re-generated every time. ocamlbuild-stuff: _tags myocamlbuild.ml meta.ml # We automatically generate the _tags file needed by OCamlBuild. # Every subdirectory containing sources is included. This may be more than what's needed, # but it will always work and require no per-project customization. sed is used to remove # the initial './' from each directory. We refer some settings implemented in our (still # automatically generated) $(OCAMLBUILD) plugin. _tags: @(echo -e "# This file is automatically generated. Please don't edit it.\n" > $@; \ for directory in $$( $(call SOURCE_SUBDIRECTORIES) ); do \ directory=`echo $$directory | sed s/^.\\\\///`; \ echo "<$$directory>: include" >> $@; \ done; \ echo >> $@; \ echo "<**/*.byte>: ourincludesettings, ourbytelinksettings, ourcmodules" >> $@; \ echo "<**/*.{ml,mli,byte,native,cma,cmxa}>: ourincludesettings" >> $@; \ echo "<**/*.{native,cma,cmxa}>: ourcmodules" >> $@ ; \ echo "<**/*.cmx>: ournativecompilesettings" >> $@; \ echo "<**/*.cmo>: ourbytecompilesettings" >> $@; \ echo "<**/*.native>: ourincludesettings, ournativelinksettings" >> $@; \ echo "<**/*.{ml,mli}>: ourocamldocsettings" >> $@ ; \ echo "<**/*.{ml,mli}>: ourppsettings" >> $@) # We automatically generate the $(OCAMLBUILD) plugin customizing the build process # with our user-specified options, include directories, etc.: myocamlbuild.ml: @(echo -e "(* This file is automatically generated. Please don't edit it. *)\n" > $@; \ echo -e "open Ocamlbuild_plugin;;" >> $@; \ echo -e "open Command;;" >> $@; \ echo -e "open Arch;;" >> $@; \ echo -e "open Format;;\n" >> $@; \ echo -en "let our_pp_options = [ " >> $@; \ echo "Just for debugging: PP_OPTION is \"$(PP_OPTION)\""; \ echo "Just for debugging: OCAML_LIBRARYPREFIX is \"$(OCAML_LIBRARYPREFIX)\""; \ echo "Just for debugging: LIBRARYPREFIX is \"$(LIBRARYPREFIX)\""; \ for x in $(PP_OPTION); do \ echo -en "A \"$$x\"; " >> $@; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_compile_options = [ " >> $@; \ for x in $(COMPILE_OPTIONS); do \ echo -en "A \"$$x\"; " >> $@; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_byte_compile_options = [ " >> $@; \ for x in $(BYTE_COMPILE_OPTIONS); do \ echo -en "A \"$$x\"; " >> $@; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_native_compile_options = [ " >> $@; \ for x in $(NATIVE_COMPILE_OPTIONS); do \ echo -en "A \"$$x\"; " >> $@; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_include_options = [ " >> $@; \ echo -en "A \"-I\"; A \"$(OCAML_LIBRARYPREFIX)\"; " >> $@; \ for x in $(DIRECTORIES_TO_INCLUDE); do \ if test -d $(OCAML_LIBRARYPREFIX)/$$x; then echo -en "A \"-I\"; A \"$(OCAML_LIBRARYPREFIX)/$$x\"; " >> $@; fi; \ done; \ for x in $(DIRECTORIES_TO_INCLUDE); do \ if test -d $(LIBRARYPREFIX)/$$x; then echo -en "A \"-I\"; A \"$(LIBRARYPREFIX)/$$x\"; " >> $@; fi; \ done; \ for x in $(DIRECTORIES_TO_INCLUDE); do \ if test -d ./$$x; then echo -en "A \"-I\"; A \"../$$x\"; " >> $@; fi; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_c_modules = [ " >> $@; \ for x in $(C_OBJECTS_TO_LINK); do \ echo -en "A \"$$x.o\"; " >> $@; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_c_modules_options = our_c_modules @ [ " >> $@; \ for x in $(C_OBJECTS_TO_LINK_OPTIONS); do \ echo -en "A \"$$x\"; " >> $@; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_byte_link_options = our_include_options @ [ " >> $@; \ for x in $(LIBRARIES_TO_LINK); do \ echo -en "A \"$$x.cma\"; " >> $@; \ done; \ for x in $(OBJECTS_TO_LINK); do \ echo -en "A \"$$x.cmo\"; " >> $@; \ done; \ echo -e "];;" >> $@; \ echo -en "let our_native_link_options = our_include_options @ [ " >> $@; \ for x in $(LIBRARIES_TO_LINK); do \ echo -en "A \"$$x.cmxa\"; " >> $@; \ done; \ for x in $(OBJECTS_TO_LINK); do \ echo -en "A \"$$x.cmx\"; " >> $@; \ done; \ echo -e "];;\n" >> $@; \ echo -e "dispatch (function After_rules ->" >> $@; \ echo -e " flag [\"ocaml\"; \"compile\"; \"ourincludesettings\"]" >> $@; \ echo -e " (S (our_compile_options @ our_include_options));" >> $@; \ echo -e " flag [\"ocaml\"; \"compile\"; \"ourbytecompilesettings\"]" >> $@; \ echo -e " (S (our_byte_compile_options));" >> $@; \ echo -e " flag [\"ocaml\"; \"compile\"; \"ournativecompilesettings\"]" >> $@; \ echo -e " (S (our_native_compile_options));" >> $@; \ echo -e " flag [\"ocaml\"; \"pp\"; \"ourppsettings\"]" >> $@; \ echo -e " (S our_pp_options);" >> $@; \ echo -e " flag [\"ocaml\"; \"link\"; \"ourbytelinksettings\"]" >> $@; \ echo -e " (S (our_compile_options @ our_byte_link_options));" >> $@; \ echo -e " flag [\"ocaml\"; \"link\"; \"ournativelinksettings\"]" >> $@; \ echo -e " (S (our_compile_options @ our_native_link_options));" >> $@; \ echo -e " flag [\"ocaml\"; \"doc\"; \"ourocamldocsettings\"]" >> $@; \ echo -e " (S ([A \"-keep-code\"; A \"-colorize-code\"] @ our_include_options));" >> $@; \ echo -e " flag [\"ocaml\"; \"link\"; \"ourcmodules\"]" >> $@; \ echo -e " (S our_c_modules_options);" >> $@; \ echo -e " | _ -> ());;" >> $@) # Auto-generate a source file including meta information and configuration-time # settings, which become accessible at runtime: meta.ml: META CONFIGME @(echo "Building $@..." && \ $(call READ_META, name, version); \ $(call READ_CONFIG, prefix, prefix_install, configurationprefix, documentationprefix localeprefix); \ echo -e "(** Automatically generated meta-informations about the project and its building. *)" > $@ && \ echo -e "(* This file is automatically generated; please don't edit it. *)\n" >> $@ && \ echo -e "let name = \"$$name\";;" >> $@ && \ echo -e "let version = \"$$version\";;" >> $@ && \ echo -e "let prefix = \"$$prefix\";;" >> $@ && \ echo -e "let prefix_install = \"$$prefix_install\";;" >> $@ && \ echo -e "let ocaml_version = \"$(OCAML_VERSION)\";;" >> $@ && \ echo -e "let ocaml_libraryprefix = \"$(OCAML_LIBRARYPREFIX)\";;" >> $@ && \ echo -e "let libraryprefix = \"$(LIBRARYPREFIX)\";;" >> $@ && \ echo -e "let configurationprefix = \"$$configurationprefix\";;" >> $@ && \ echo -e "let localeprefix = \"$$localeprefix\";;" >> $@ && \ echo -e "let documentationprefix = \"$$documentationprefix\";;" >> $@ && \ echo -e "let uname = \"$(shell uname -srvmo)\";;" >> $@ && \ echo -e "let build_date = \"$(shell date '+%Y-%m-%d %k:%M:%S %z')\";;" >> $@ && \ if [ -d .bzr ]; then \ echo -e "let revision = \"$$(bzr revno)\";;" >> $@ && \ echo -e "let source_date = \"$$(bzr info --verbose | /bin/grep 'latest revision' | cut -d: -f2- | cut -d' ' -f3-)\";;" >> $@ && \ echo -e "let source_date_utc_yy_mm_dd = \"$$(./Makefile.d/bzr_date -- -u "+%Y-%m-%d")\";;" >> $@ ; \ else \ grep "let revision" > $@ && \ grep "let source_date" > $@ ; \ grep "let source_date_utc_yy_mm_dd" > $@ ; \ fi &&\ echo "Success.") meta.ml.released: meta.ml if [ -d .bzr ]; then \ cp $< $@ fi; \ ########################################################################### # Include the project-dependant file (if any) which implements the '-local' # targets: -include Makefile.local -include RPMS/Makefile