I'm using GNU Make 3.82 and I want to dynamically create goals in a Makefile using define
.
However there was a problem when trying to process the lists passed to the macro. Here is a simple example of code that for some reason does not work as expected:
MAKEFLAGS += -s
SHELL := /bin/bash
define create_target
$(1):
echo $(1); \
echo $(2); \
for i in $(2); do \
echo $$i; \
done
endef
$(eval $(call create_target, test, 1 2 3 4 5))
When I run make test
, the following output is produced:
test
1 2 3 4 5
<5 blank lines>
That is, the variable i
in the loop does not expand as it should and I could not force it to do so with all combinations of $
and ()
.
How do I get the for
loop to iterate over these values?
You have to count the expansions. You have an extra expansion due to the call
, that you are not taking into account.
After the call
runs and expands the variable, it will have an expanded value like this:
test:
echo test; \
echo 1 2 3 4 5; \
for i in 1 2 3 4 5; do \
echo $i; \
done
Note how the $$i
was reduced to $i
. You can already see the problem. Now eval
will turn this into a recipe, then when make
runs the recipe it will expand the $i
as a make variable, which is the empty string, so the recipe passed to the shell will be:
echo test; \
echo 1 2 3 4 5; \
for i in 1 2 3 4 5; do \
echo ; \
done
You need to double-escape anything you want to be passed to the shell, if you're going to expand it with call
(there is some verbiage in the manual about this I believe):
define create_target
$(1):
echo $(1); \
echo $(2); \
for i in $(2); do \
echo $$$$i; \
done
endef
When working with eval
the best debugging you can do is to replace the eval
call with info
. This will have make print out exactly what text it will be evaluating:
$(info $(call create_target, test, 1 2 3 4 5))
$(eval $(call create_target, test, 1 2 3 4 5))