Reputation: 3062
I think there is something kind of basic I am missing about the gnu make (I am using 3.81 if it matters) static pattern rule matching (which apparently someone else did as well where I work because this was discovered as I was trying to fix a rule that had been commented out). I have tried to simplify my example down to the crux of it (hopefully I haven't' missed anything essential in the real example).
So this appears to work as I'd expect
JUNK:=foo bar
BINS:=$(patsubst %,bin/%,$(JUNK))
all : $(BINS)
.PHONY : all
# This works
$(BINS) : bin/% : %
mkdir -p bin && cp $< $@
But this (which is closer to what I found in the real Makefile) does not
JUNK:=foo bar
BINS:=$(patsubst %,bin/%,$(JUNK))
all : $(BINS)
.PHONY : all
# This doesn't work
$(JUNK) : bin/% : %
mkdir -p bin && cp $< $@
# This doesn't work either
#bin/$(JUNK) : bin/% : %
# mkdir -p bin && cp $< $@
Based on my understanding of what should be happening in both cases I would have expected that both Makefiles would behave exactly the same; however, only the first one behaves as I expected (i.e., properly copies the files to bin) and the second gives the following output
Makefile:12: target `foo' doesn't match the target pattern
Makefile:12: target `bar' doesn't match the target pattern
make: *** No rule to make target `bin/foo', needed by `all'. Stop.
What is more confusing is there are nearly identical other static pattern rules in the make file I was examining that were working.
So I obviously know how to "work around" the issue if need be but I'd like to understand why the second (and the commented out portion in the second code block as well) do not do what I expect them to.
Thanks in advance for any help/insight.
Upvotes: 0
Views: 2543
Reputation: 101081
The first one doesn't work because, after expanding the JUNK
variable, make sees this:
foo bar : bin/% : %
The way static pattern rules work is that the first pattern (the target pattern) must match each word in the list of targets. That tells make which part of the target name is the stem (the part that matches the %
). If the target pattern doesn't match, make doesn't know what the stem is. The pattern bin/%
does not match the text foo
, (there is no bin/
in the text foo
) so you get the error you see.
The second one doesn't work because the result of exanding the JUNK
variable in this example (bin/$(JUNK) : bin/% : %
) looks like this:
bin/foo bar : bin/% : %
Here, bin/foo
matches the pattern, but bar
doesn't match and so you get the same error as you did in the previous one.
To make it work you must have bin/
prepended to every target, not just the first target, hence the use of patsubst
(or, addprefix
would work as well).
Upvotes: 4