The rebuild-the-world-if-anything-changed approach turned out to be pretty simple I think. Opinions welcome on the below solution, I haven't used it much yet. It can be tricked by pathological stuff like ifdef SOME_VAR ... endif SOME_VAR=constant_val (without any effects on other variables in ...) earlier in the Makefile but is it otherwise ok?
# For putting newlines in strings: define nl endef # Roots of the DAG should all depend on smv (Serialized Make Variables) bar: foo smv # Fake build for demo: cp $< $@ clean: rm -f smv # This should be at the end of the Makefile (or after all var declarations): $(file \ >nsmv, \ $(foreach v,$(.VARIABLES),$(flavor $(v)) var $(v) has value $($(v))$(nl))) # Note: not removing nsmv would be tiny bit more mess but might be nice to # be able to see what's going on. $(shell (([ -a smv ] && (diff smv nsmv >/dev/null)) || cp nsmv smv); rm nsmv)