srcs_default = $(addprefix $(DEFAULT_PATH)/,$(srcfiles_default))
srcs_override = $(addprefix $(OVERRIDE_PATH)/,$(srcfiles_override))
$(foreach p,$(srcs_override) $(srcs_default),$(eval\
$(CACHEDIR)/$(notdir $(p)): $(p)\
@echo "Executing rule for $$@"\
cp $$< $$@))
Here we’ve saved you the trouble of trying the loop without using $(eval ...)
,
which also fails, and without the escaped end-of-lines. Each of these
attempts fails with a head-scratching error message. See what Make says
about the code shown above:
$ make -f multi_loc_prereq_simple.mk all_cache
make: *** No rule to make target '@echo', needed by 'build/cache/fileB.tcl'. Stop.
Some important behavioral details of Make are colliding in this situation:
- All function calls (whether built-in or user-defined) must be a single line in the make file.
- Replaced text is not treated as input unless passed as an argument to the
$(eval ...)
function. - Escaping the end-of-line character(s) effectively discards them (converting the input to single-line).
- Function calls can return multi-line text.
- Variables that hold multi-line text must be created with ‘define’, not simple assignment.
Navigating this set of requirements by trial and error is painful. We have to escape the end of line in order to satisfy the $(foreach ...)
,
but doing so causes the first line of the recipe to become a
prerequisite! In the example above, escaping the newlines to satisfy
the $(foreach ...)
simultaneously escapes them for the $(eval ...)
,
which breaks the formatting required for Make to properly parse the
generated rules. In general, to dynamically generate Make rules, we
have to use both a defined multi-line variable and the $(eval ...)
function.