| # ########################################################################## |
| # multiconf.make |
| # Copyright (C) Yann Collet |
| # |
| # GPL v2 License |
| # |
| # 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, write to the Free Software Foundation, Inc., |
| # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| # |
| # ########################################################################## |
| |
| |
| # Provides c_program(_shared_o) and cxx_program(_shared_o) target generation macros |
| # Provides static_library and c_dynamic_library target generation macros |
| # Support recompilation of only impacted units when an associated *.h is updated. |
| # Provides V=1 / VERBOSE=1 support. V=2 is used for debugging purposes. |
| # Complement target clean: delete objects and binaries created by this script |
| |
| # Requires: |
| # - C_SRCDIRS, CXX_SRCDIRS, ASM_SRCDIRS defined |
| # OR |
| # C_SRCS, CXX_SRCS and ASM_SRCS variables defined |
| # *and* vpath set to find all source files |
| # OR |
| # C_OBJS, CXX_OBJS and ASM_OBJS variables defined |
| # *and* vpath set to find all source files |
| # - directory `cachedObjs/` available to cache object files. |
| # alternatively: set CACHE_ROOT to some different value. |
| # Optional: |
| # - HASH can be set to a different custom hash program. |
| |
| # *_program*: generates a recipe for a target that will be built in a cache directory. |
| # The cache directory is automatically derived from CACHE_ROOT and list of flags and compilers. |
| # *_shared_o* variants are optional optimization variants, that share the same objects across multiple targets. |
| # However, as a consequence, all these objects must have exactly the same list of flags, |
| # which in practice means that there must be no target-level modification (like: target: CFLAGS += someFlag). |
| # If unsure, only use the standard variants, c_program and cxx_program. |
| |
| # All *_program* macro functions take up to 4 argument: |
| # - The name of the target |
| # - The list of object files to build in the cache directory |
| # - An optional list of dependencies for linking, that will not be built |
| # - An optional complementary recipe code, that will run after compilation and link |
| |
| |
| # Silent mode is default; use V = 1 or VERBOSE = 1 to see compilation lines |
| VERBOSE ?= $(V) |
| $(VERBOSE).SILENT: |
| |
| # Directory where object files will be built |
| CACHE_ROOT ?= cachedObjs |
| |
| # -------------------------------------------------------------------------------------------- |
| |
| # Dependency management |
| DEPFLAGS = -MT $@ -MMD -MP -MF |
| |
| # Include dependency files |
| include $(wildcard $(CACHE_ROOT)/**/*.d) |
| include $(wildcard $(CACHE_ROOT)/generic/*/*.d) |
| |
| # -------------------------------------------------------------------------------------------- |
| |
| # Automatic determination of build artifacts cache directory, keyed on build |
| # flags, so that we can do incremental, parallel builds of different binaries |
| # with different build flags without collisions. |
| |
| UNAME ?= $(shell uname) |
| ifeq ($(UNAME), Darwin) |
| HASH ?= md5 |
| else ifeq ($(UNAME), FreeBSD) |
| HASH ?= gmd5sum |
| else ifeq ($(UNAME), OpenBSD) |
| HASH ?= md5 |
| endif |
| HASH ?= md5sum |
| |
| HAVE_HASH := $(shell echo 1 | $(HASH) > /dev/null && echo 1 || echo 0) |
| ifeq ($(HAVE_HASH),0) |
| $(info warning : could not find HASH ($(HASH)), required to differentiate builds using different flags) |
| HASH_FUNC = generic/$(1) |
| else |
| HASH_FUNC = $(firstword $(shell echo $(2) | $(HASH) )) |
| endif |
| |
| |
| MKDIR ?= mkdir |
| LN ?= ln |
| |
| # -------------------------------------------------------------------------------------------- |
| # The following macros are used to create object files in the cache directory. |
| # The object files are named after the source file, but with a different path. |
| |
| # Create build directories on-demand. |
| # |
| # For some reason, make treats the directory as an intermediate file and tries |
| # to delete it. So we work around that by marking it "precious". Solution found |
| # here: |
| # http://ismail.badawi.io/blog/2017/03/28/automatic-directory-creation-in-make/ |
| .PRECIOUS: $(CACHE_ROOT)/%/. |
| $(CACHE_ROOT)/%/. : |
| $(MKDIR) -p $@ |
| |
| |
| define addTargetAsmObject # targetName, addlDeps |
| $$(if $$(filter 2,$$(V)),$$(info $$(call $(0),$(1),$(2)))) |
| |
| .PRECIOUS: $$(CACHE_ROOT)/%/$(1) |
| $$(CACHE_ROOT)/%/$(1) : $(1:.o=.S) $(2) | $$(CACHE_ROOT)/%/. |
| @echo AS $$@ |
| $$(CC) $$(CPPFLAGS) $$(CXXFLAGS) $$(DEPFLAGS) $$(CACHE_ROOT)/$$*/$(1:.o=.d) -c $$< -o $$@ |
| |
| endef # addTargetAsmObject |
| |
| define addTargetCObject # targetName, addlDeps |
| $$(if $$(filter 2,$$(V)),$$(info $$(call $(0),$(1),$(2)))) #debug print |
| |
| .PRECIOUS: $$(CACHE_ROOT)/%/$(1) |
| $$(CACHE_ROOT)/%/$(1) : $(1:.o=.c) $(2) | $$(CACHE_ROOT)/%/. |
| @echo CC $$@ |
| $$(CC) $$(CPPFLAGS) $$(CFLAGS) $$(DEPFLAGS) $$(CACHE_ROOT)/$$*/$(1:.o=.d) -c $$< -o $$@ |
| |
| endef # addTargetCObject |
| |
| define addTargetCxxObject # targetName, suffix, addlDeps |
| $$(if $$(filter 2,$$(V)),$$(info $$(call $(0),$(1),$(2),$(3)))) |
| |
| .PRECIOUS: $$(CACHE_ROOT)/%/$(1) |
| $$(CACHE_ROOT)/%/$(1) : $(1:.o=.$(2)) $(3) | $$(CACHE_ROOT)/%/. |
| @echo CXX $$@ |
| $$(CXX) $$(CPPFLAGS) $$(CXXFLAGS) $$(DEPFLAGS) $$(CACHE_ROOT)/$$*/$(1:.o=.d) -c $$< -o $$@ |
| |
| endef # addTargetCxxObject |
| |
| # Create targets for individual object files |
| C_SRCDIRS += . |
| vpath %.c $(C_SRCDIRS) |
| CXX_SRCDIRS += . |
| vpath %.cpp $(CXX_SRCDIRS) |
| vpath %.cc $(CXX_SRCDIRS) |
| ASM_SRCDIRS += . |
| vpath %.S $(ASM_SRCDIRS) |
| |
| # If C_SRCDIRS, CXX_SRCDIRS and ASM_SRCDIRS are not defined, use C_SRCS, CXX_SRCS and ASM_SRCS |
| C_SRCS ?= $(notdir $(foreach dir,$(C_SRCDIRS),$(wildcard $(dir)/*.c))) |
| CPP_SRCS ?= $(notdir $(foreach dir,$(CXX_SRCDIRS),$(wildcard $(dir)/*.cpp))) |
| CC_SRCS ?= $(notdir $(foreach dir,$(CXX_SRCDIRS),$(wildcard $(dir)/*.cc))) |
| CXX_SRCS ?= $(CPP_SRCS) $(CC_SRCS) |
| ASM_SRCS ?= $(notdir $(foreach dir,$(ASM_SRCDIRS),$(wildcard $(dir)/*.S))) |
| |
| # If C_SRCS, CXX_SRCS and ASM_SRCS are not defined, use C_OBJS, CXX_OBJS and ASM_OBJS |
| C_OBJS ?= $(patsubst %.c,%.o,$(C_SRCS)) |
| CPP_OBJS ?= $(patsubst %.cpp,%.o,$(CPP_SRCS)) |
| CC_OBJS ?= $(patsubst %.cc,%.o,$(CC_SRCS)) |
| CXX_OBJS ?= $(CPP_OBJS) $(CC_OBJS) # Note: not used |
| ASM_OBJS ?= $(patsubst %.S,%.o,$(ASM_SRCS)) |
| |
| $(foreach OBJ,$(C_OBJS),$(eval $(call addTargetCObject,$(OBJ)))) |
| $(foreach OBJ,$(CPP_OBJS),$(eval $(call addTargetCxxObject,$(OBJ),cpp))) |
| $(foreach OBJ,$(CC_OBJS),$(eval $(call addTargetCxxObject,$(OBJ),cc))) |
| $(foreach OBJ,$(ASM_OBJS),$(eval $(call addTargetAsmObject,$(OBJ)))) |
| |
| # -------------------------------------------------------------------------------------------- |
| # The following macros are used to create targets in the user Makefile. |
| # Binaries are built in the cache directory, and then symlinked to the current directory. |
| # The cache directory is automatically derived from CACHE_ROOT and list of flags and compilers. |
| |
| |
| # static_library - Create build rules for a static library with caching |
| # Parameters: |
| # 1. libName - Library name (becomes output file and phony target) |
| # 2. objectDeps - Object file dependencies (will be built in cache path) |
| # The following parameters are all optional: |
| # 3. extraDeps - Additional dependencies (no cache path prefix) |
| # 4. postBuildCmds - Extra commands to run after AR |
| # 5. extraHash - Additional key to compute the unique cache path |
| # Example: |
| # $(call static_library,libmath.a,vector.o matrix.o,$(CONFIG_H),strip $@,$(VERSION)) |
| define static_library # libName, objectDeps, extraDeps, postBuildCmds, extraHash |
| |
| $$(if $$(filter 2,$$(V)),$$(info $$(call $(0),$(1),$(2),$(3),$(4),$(5)))) |
| MCM_ALL_BINS += $(1) |
| |
| $$(CACHE_ROOT)/%/$(1) : $$(addprefix $$(CACHE_ROOT)/%/,$(2)) $(3) |
| @echo AR $$@ |
| $$(AR) $$(ARFLAGS) $$@ $$^ |
| $(4) |
| |
| .PHONY: $(1) |
| $(1) : ARFLAGS = rcs |
| $(1) : $$(CACHE_ROOT)/$$(call HASH_FUNC,$(1),$(2) $$(CPPFLAGS) $$(CC) $$(CFLAGS) $$(CXX) $$(CXXFLAGS) $$(AR) $$(ARFLAGS) $(5))/$(1) |
| $$(LN) -sf $$< $$@ |
| |
| endef # static_library |
| |
| |
| # c_dynamic_library - Create build rules for a C dynamic/shared library with caching |
| # Parameters: |
| # 1. libName - Library name (becomes output file and phony target) |
| # 2. objectDeps - Object file dependencies (will be built in cache path) |
| # The following parameters are all optional: |
| # 3. extraDeps - Additional dependencies (no cache path prefix) |
| # 4. postLinkCmds - Extra commands to run after linking |
| # 5. extraHash - Additional key to compute the unique cache path |
| # Example: |
| # $(call c_dynamic_library,libmath.so,vector.o matrix.o,$(CONFIG_H),strip $@,$(VERSION)) |
| define c_dynamic_library # libName, objectDeps, extraDeps, postLinkCmds, extraHash |
| |
| $$(if $$(filter 2,$$(V)),$$(info $$(call $(0),$(1),$(2),$(3),$(4),$(5)))) |
| MCM_ALL_BINS += $(1) |
| |
| $$(CACHE_ROOT)/%/$(1) : $$(addprefix $$(CACHE_ROOT)/%/,$(2)) $(3) |
| @echo LD $$@ |
| $$(CC) $$(CPPFLAGS) $$(CFLAGS) $$(LDFLAGS) -shared -o $$@ $$^ $$(LDLIBS) |
| $(4) |
| |
| .PHONY: $(1) |
| $(1) : CFLAGS += -fPIC |
| $(1) : $$(CACHE_ROOT)/$$(call HASH_FUNC,$(1),$(2) $$(CPPFLAGS) $$(CC) $$(CFLAGS) $$(LDFLAGS) $$(LDLIBS) $(5))/$(1) |
| $$(LN) -sf $$< $$@ |
| |
| endef # c_dynamic_library |
| |
| |
| # program_base - Create build rules for an executable program with caching |
| # Parameters: |
| # 1. progName - Executable name (becomes output file and phony target) |
| # 2. objectDeps - Object file dependencies (will be prefixed with cache path) |
| # Parameters 3 to 5 are optional: |
| # 3. extraDeps - Additional dependencies (without cache path prefix) |
| # 4. postLinkCmds - Extra commands to run after linking |
| # 5. extraHash - Additional data to include in cache path hash |
| # Parameters 6 & 7 are compulsory: |
| # 6. compiler - Variable name of compiler to use (CC or CXX) |
| # 7. compilerFlags - Variable name of compiler flags to use (CFLAGS or CXXFLAGS) |
| # Example: |
| # $(call program_base,myapp,main.o utils.o,$(CONFIG_H),strip $@,$(VERSION),CC,CFLAGS) |
| # $(call program_base,mycppapp,main.o utils.o,$(CONFIG_H),strip $@,$(VERSION),CXX,CXXFLAGS) |
| define program_base # progName, objectDeps, extraDeps, postLinkCmds, extraHash, compiler, compilerFlags |
| |
| $$(if $$(filter 2,$$(V)),$$(info $$(call $(0),$(1),$(2),$(3),$(4),$(5),$(6),$(7)))) |
| MCM_ALL_BINS += $(1) |
| |
| $$(CACHE_ROOT)/%/$(1) : $$(addprefix $$(CACHE_ROOT)/%/,$(2)) $(3) |
| @echo LD $$@ |
| $$($(6)) $$(CPPFLAGS) $$($(7)) $$^ -o $$@ $$(LDFLAGS) $$(LDLIBS) |
| $(4) |
| |
| .PHONY: $(1) |
| $(1) : $$(CACHE_ROOT)/$$(call HASH_FUNC,$(1),$$($(6)) $$(CPPFLAGS) $$($(7)) $$(LDFLAGS) $$(LDLIBS) $(5))/$(1) |
| $$(LN) -sf $$< $$@$(EXT) |
| |
| endef # program_base |
| # Note: $(EXT) must be set to .exe for Windows |
| |
| define c_program # progName, objectDeps, extraDeps, postLinkCmds |
| $$(eval $$(call program_base,$(1),$(2),$(3),$(4),$(1)$(2),CC,CFLAGS)) |
| endef # c_program |
| |
| define c_program_shared_o # progName, objectDeps, extraDeps, postLinkCmds |
| $$(eval $$(call program_base,$(1),$(2),$(3),$(4),,CC,CFLAGS)) |
| endef # c_program_shared_o |
| |
| define cxx_program # progName, objectDeps, extraDeps, postLinkCmds |
| $$(eval $$(call program_base,$(1),$(2),$(3),$(4),$(1)$(2),CXX,CXXFLAGS)) |
| endef # cxx_program |
| |
| define cxx_program_shared_o # progName, objectDeps, extraDeps, postLinkCmds |
| $$(eval $$(call program_base,$(1),$(2),$(3),$(4),,CXX,CXXFLAGS)) |
| endef # cxx_program_shared_o |
| |
| # -------------------------------------------------------------------------------------------- |
| |
| # Cleaning: delete all objects and binaries created by this script |
| .PHONY: clean_cache |
| clean_cache: |
| $(RM) -rf $(CACHE_ROOT) |
| $(RM) $(MCM_ALL_BINS) |
| |
| # automatically attach to standard clean target |
| .PHONY: clean |
| clean: clean_cache |