I am using GNU make 3.81. Here is a test makefile that demonstrates the problem:
define BOZO a$(1): b c touch a$(1) endef $(foreach i,1 2 3,$(call BOZO,$(i)))
The idea here is to use a macro template (BOZO) to generate rules that follow a predictable pattern.
Problem: when I run make on this makefile I get an error saying:
Makefile.fake:10: *** multiple target patterns. Stop.
(where line 10 is the line with the foreach).
Now, I know what that error normally indicates. Let's see what that line expands to by using the info
function to send the expansion to standard out. I change line 10 to be:
$(info $(foreach i,1 2 3,$(call BOZO,$(i))))
and I run:
$ make -n a1: b c touch a1 a2: b c touch a2 a3: b c touch a3 make: *** No targets. Stop.
Note that the "no targets" message is expected, since the $(info ...) function evaluates to empty but causes make to print the generated rules.
Let's run those rules then shall we?
$make -n > out.txt make: *** No targets. Stop. $make -f out.txt a1 a2 a3 touch a1 touch a2 touch a3 $
AAARGH! The rules work fine. So... is the bug in make, or in my understanding?
One final clue that might help diagnose: if I change the foreach line to:
$(foreach i,1,$(call BOZO,$(i)))
(so that foreach has only one iteration)
and then do
$make a1
I get a different error:
make: *** No rule to make target `a1'. Stop.
I don't know of any way to "see" the expansion of $(foreach )
that make sees except for $(info )
, and its output is legal, so I'm quite stumped.
$(foreach i,1 2 3,$(eval $(call BOZO,$(i))))
The eval function tells Make to parse the structures as makefile syntax, to "enact" them. I'm not sure why Make objected to the un-eval'd rules this particular way, but that's kind of academic.
Beta's answer is correct but I wanted to address the comment, "I'm not sure why Make objected to un un-eval'd rules".
The reason the un-eval'd rules don't work is that a makefile is ultimately line-based, and lines are chopped BEFORE variables are expanded. So it's just not possible for an expansion of a variable to turn into a multiline result: even if the expansion contains newlines make treats the entire thing as one "line". When make finishes expanding the foreach
loop and parses the results it basically sees this:
a1: b c touch a1 a2: b c touch a2 a3: b c touch b3
which is why you get the "multiple target patterns" error.
The eval causes make to re-interpret the result of the expansion from the beginning as a complete snippet of makefile syntax, including the line-chopping etc., and that's why a multi-line expansion works there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With