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