included clean_cache no need to specify anything in user's Makefile, clean_cache target is automatically invoked from `make clean`.
diff --git a/Makefile b/Makefile index cf0abf5..c551428 100644 --- a/Makefile +++ b/Makefile
@@ -178,7 +178,7 @@ $(AWK) 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' .PHONY: clean -clean: clean_cache +clean: $(RM) -r *.dSYM # Mac OS-X specific $(RM) core *.o *.obj *.$(SHARED_EXT) *.$(SHARED_EXT).* *.a libxxhash.pc $(RM) xxhsum.wasm xxhsum.js xxhsum.html
diff --git a/build/make/README.md b/build/make/README.md index da20e93..76c068d 100644 --- a/build/make/README.md +++ b/build/make/README.md
@@ -1,19 +1,22 @@ # multiconf.make -**multiconf.make** is a self-contained Makefile include that lets you build the **same targets under many different flag sets**—debug vs release, ASan vs UBSan, GCC vs Clang, etc.—without the usual “object-file soup.” -It hashes every combination of `CC/CXX`, `CFLAGS/CXXFLAGS`, `CPPFLAGS`, `LDFLAGS` and `LDLIBS` into a **dedicated cache directory**, so objects compiled with one configuration are never reused by another. Swap flags, rebuild, swap back—previous objects are still there and never collide. +**multiconf.make** is a self-contained Makefile include that lets you build the **same targets under many different flag sets**. For example debug vs release, ASan vs UBSan, GCC vs Clang. +Each different set of flags generates object files into its own **dedicated cache directory**, so objects compiled with one configuration are never reused by another. +Object files from previous configurations are preserved, so swapping back to a previous configuration only requires compiling objects which have actually changed. --- -## Key Benefits +## Benefits at a glance -| Why it matters | What multiconf.make does | +| Benefit | What `multiconf.make` does | | --- | --- | | **Isolated configs** | Stores objects into `cachedObjs/<hash>/`, one directory per unique flag set. | | **Fast switching** | Reusing an old config is instant—link only, no recompilation. | | **Header deps** | Edits to headers trigger only needed rebuilds. | | **One-liner targets** | Macros (`c_program`, `cxx_program`, …) hide all rule boilerplate. | | **Parallel-ready** | Safe with `make -j`, no duplicate compiles of shared sources. | +| **Controlled verbosity** | Default only lists objects, while `V=1` display full commands. | +| **`clean` included** | `make clean` deletes all objects, binaries and links. | --- @@ -24,6 +27,7 @@ ```make C_SRCDIRS := src src/cdeps # all .c are in these directories CXX_SRCDIRS := src src/cxxdeps # all .cpp are in these directories +``` ### 2 · Add and include @@ -36,9 +40,13 @@ ```make app: -$(eval $(call c_program,app,app.o obj1.o obj2.o)) +$(eval $(call c_program,app,app.o cdeps/obj.o)) + test: -$(eval $(call cxx_program,test, test.o objcxx1.o objcxx2.o)) +$(eval $(call cxx_program,test, test.o cxxdeps/objcxx.o)) + +lib.a: +$(eval $(call static_library,lib.a, lib.o cdeps/obj.o)) ``` ### 4 · Build any config you like @@ -58,11 +66,3 @@ --- -## Additional capabilities - -| Command | Description | -| --- | --- | -| `make clean_cache` | Wipe **all** cached objects & deps (full rebuild next time) | -| `V=1` | Show full compile/link commands | - ----
diff --git a/build/make/multiconf.make b/build/make/multiconf.make index ae598da..808d97b 100644 --- a/build/make/multiconf.make +++ b/build/make/multiconf.make
@@ -99,6 +99,14 @@ RANLIB ?= ranlib LN ?= ln +# Include dependency files +include $(wildcard $(CACHE_ROOT)/**/*.d) +include $(wildcard $(CACHE_ROOT)/generic/*/*.d) + +# -------------------------------------------------------------------------------------------- +# 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 @@ -109,13 +117,10 @@ $(CACHE_ROOT)/%/. : $(MKDIR) -p $@ -# Include dependency files -include $(wildcard $(CACHE_ROOT)/**/*.d) -include $(wildcard $(CACHE_ROOT)/generic/*/*.d) -define addTargetObject # targetName, addlDeps +define addTargetCObject # targetName, addlDeps ifeq ($$(V),2) -$$(info $$(call addTargetObject,$(1))) +$$(info $$(call $(0),$(1),$(2))) endif .PRECIOUS: $$(CACHE_ROOT)/%/$(1) @@ -123,11 +128,11 @@ @echo CC $$@ $$(CC) $$(CPPFLAGS) $$(CFLAGS) $$(DEPFLAGS) $$(CACHE_ROOT)/$$*/$(1:.o=.d) -c $$< -o $$@ -endef # addTargetObject +endef # addTargetCObject define addTargetAsmObject # targetName, addlDeps ifeq ($$(V),2) -$$(info $$(call addTargetAsmObject,$(1))) +$$(info $$(call $(0),$(1),$(2))) endif .PRECIOUS: $$(CACHE_ROOT)/%/$(1) @@ -139,7 +144,7 @@ define addTargetCxxObject # targetName, addlDeps ifeq ($$(V),2) -$$(info $$(call addTargetCxxObject,$(1))) +$$(info $$(call $(0),$(1),$(2))) endif .PRECIOUS: $$(CACHE_ROOT)/%/$(1) @@ -149,6 +154,32 @@ endef # addTargetCxxObject +# Create targets for individual object files +C_SRCDIRS += . +vpath %.c $(C_SRCDIRS) +CXX_SRCDIRS += . +vpath %.cpp $(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))) +CXX_SRCS ?= $(notdir $(foreach dir,$(CXX_SRCDIRS),$(wildcard $(dir)/*.cpp))) +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)) +CXX_OBJS ?= $(patsubst %.cpp,%.o,$(CXX_SRCS)) +ASM_OBJS ?= $(patsubst %.S,%.o,$(ASM_SRCS)) + +$(foreach OBJ,$(C_OBJS),$(eval $(call addTargetCObject,$(OBJ)))) +$(foreach OBJ,$(CXX_OBJS),$(eval $(call addTargetCxxObject,$(OBJ)))) +$(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. define static_library # targetName, targetDeps, addlDeps, addRecipe, hashSuffix ifeq ($$(V),2) @@ -201,32 +232,14 @@ $$(eval $$(call program_base,$(1),$(2),$(3),$(4),,CXX,CXXFLAGS)) endef # cxx_program_shared_o +# -------------------------------------------------------------------------------------------- -# Create targets for individual object files -C_SRCDIRS += . -vpath %.c $(C_SRCDIRS) -CXX_SRCDIRS += . -vpath %.cpp $(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))) -CXX_SRCS ?= $(notdir $(foreach dir,$(CXX_SRCDIRS),$(wildcard $(dir)/*.cpp))) -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)) -CXX_OBJS ?= $(patsubst %.cpp,%.o,$(CXX_SRCS)) -ASM_OBJS ?= $(patsubst %.S,%.o,$(ASM_SRCS)) - -$(foreach OBJ,$(C_OBJS),$(eval $(call addTargetObject,$(OBJ)))) -$(foreach OBJ,$(CXX_OBJS),$(eval $(call addTargetCxxObject,$(OBJ)))) -$(foreach OBJ,$(ASM_OBJS),$(eval $(call addTargetAsmObject,$(OBJ)))) - - -# Cleaning - +# Cleaning: delete all objects and binaries created with this script +.PHONY: clean_cache clean_cache: $(RM) -rf $(CACHE_ROOT) $(RM) $(ALL_PROGRAMS) + +# automatically attach to standard clean target +.PHONY: clean +clean: clean_cache