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?


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.