My Makefile looks like this:

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

test: *.foo
    echo *.foo

I have 2 files in the directory: a.bar and b.bar. When I run make test it outputs:

cp b.bar *.foo
echo *.foo

It also creates a file *.foo in the current directory.

I am actually expecting to see this:

cp a.bar a.foo
cp b.bar b.foo
echo *.foo
a.foo b.foo

And also creating a.foo and b.foo. How to achieve that?

marked as duplicate by ilkkachu, Mr Shunz, roaima, Michael Homer, elbarna Mar 17 at 20:28

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.


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

Not the answer you're looking for? Browse other questions tagged or ask your own question.