Makefile strange variable substitution

In this case you need to handle wildcards explicitly, with the wildcard function (at least in GNU Make):

%.foo: %.bar
    cp $< $@

foos = $(patsubst %.bar,%.foo,$(wildcard *.bar))

test: $(foos)
    echo $(foos)

$(wildcard *.bar) expands to all the files ending in .bar, the patsubst call replaces .bar with .foo, and all the targets are then processed as you’d expect.


There is no *.foo file to begin with. So what make does is look for how to make *.foo literaly and the first rule does this. Make expands $< to the first pre-requisite (*.bar, which happens to be b.bar in this case). Make then runs the shell command cp b.bar *.foo. Since there is no *.foo, shell expands it to cp b.bar *.foo literally. That's how you get a *.foo file.

You can verify this by running make -d test.

You can get the effect you want by generating the list of targets based on list of prerequisites.

TARGETS = $(patsubst %.bar,%.foo,$(wildcard *.bar))
%.foo: %.bar
    @cp $< $@
test: $(TARGETS)
    @echo $(TARGETS)
    echo *.foo

Tags:

Make