included clean_cache

no need to specify anything in user's Makefile,
clean_cache target is automatically invoked from `make clean`.
This commit is contained in:
Yann Collet
2025-05-04 14:06:19 -07:00
parent b46c9e94b8
commit f0761f4d9a
3 changed files with 61 additions and 48 deletions

View File

@@ -178,7 +178,7 @@ help: ## list documented targets
$(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

View File

@@ -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 @@ It hashes every combination of `CC/CXX`, `CFLAGS/CXXFLAGS`, `CPPFLAGS`, `LDFLAGS
```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 @@ include multiconf.make
```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 @@ Objects for each command live in different sub-folders; nothing overlaps.
---
## Additional capabilities
| Command | Description |
| --- | --- |
| `make clean_cache` | Wipe **all** cached objects & deps (full rebuild next time) |
| `V=1` | Show full compile/link commands |
---

View File

@@ -99,6 +99,14 @@ MKDIR ?= mkdir
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 @@ LN ?= ln
$(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 @@ $$(CACHE_ROOT)/%/$(1) : $(1:.o=.c) $(2) | $$(CACHE_ROOT)/%/.
@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 @@ endef # addTargetAsmObject
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 @@ $$(CACHE_ROOT)/%/$(1) : $(1:.o=.cpp) $(2) | $$(CACHE_ROOT)/%/.
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 @@ define cxx_program_shared_o # targetName, targetDeps, addlDeps, addRecipe
$$(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