Brent
Brent

Reputation: 4283

Why does my Makefile pattern rule run its recipe multiple times?

As per the gnu make documentation, a pattern rule's "...recipe is executed only once to make all the targets." However, I have the following Makefile

.PHONY: entrypoint
entrypoint: test_1.cpp test_2.cpp

test_%.cpp:
    echo $@

And running make produces:

echo test_1.cpp
test_1.cpp
echo test_2.cpp
test_2.cpp

I'm new to make, and I'm probably misunderstanding something, but the documentation seems misleading if clear.

$ make -v
GNU Make 4.0
...

Upvotes: 0

Views: 1712

Answers (2)

Vroomfondel
Vroomfondel

Reputation: 2898

The following functions construct a dynamic list of dependencies of your multiple-target where the non-existent files are named last. This is more or less the method named "Another attempt" in the link you gave, except that it doesn't trip over missing files and is able to make a missing file by giving it as target on the command line. What it does not: execute the multitarget recipe if one of the multitargets is out of date relative to the others, but I think this is more of wanted side effect than a problem. The only drawback is the syntactic ugliness as you have to write it into an eval expression which forces you to quote all variables in the recipe which shall be evaluated at execution time.

define newline :=


endef
list2rules = $(firstword $1) $(if $(word 2,$1),: $(word 2,$1)$(newline)$(call list2rules,$(wordlist 2,1000,$1)))
multitarget = $(call list2rules,$(wildcard $1) $(filter-out $(wildcard $1),$1))

.PHONY: all

targets = test1 test2 footest3
#$(info $(call multitarget,$(targets)))

all: somefile

somefile: $(targets)
    touch somefile

# here we generate the dependency list on the spot. Only one recipe to update all targets.
$(eval $(call multitarget,\
$(targets)) : ; \
    touch $(targets) \
)

Upvotes: 0

MadScientist
MadScientist

Reputation: 100856

You're misreading the documentation. It means, the recipe is run only one time assuming that all the target patterns in that rule will be created.

Since you have only one target pattern in your rule (test_%.cpp`) make knows that each time it runs that recipe it will create one output file matching that pattern. To create different targets that match that pattern it will run multiple instances of the recipe.

If you had a rule like this:

%.x %.y %.z :
        dothings

then make would expect that a single invocation of the recipe dothings would create all the targets matching this pattern (e.g., foo.x, foo.y, and foo.z).

Contrast this with an explicit rule like this:

foo.x foo.y foo.z :
        dothings

Make here treats this exactly as if you'd written this:

foo.x :
        dothings
foo.y :
        dothings
foo.z :
        dothings

That is, to build all three of these targets it would run the recipe three times.

There's no way to tell make "please run this recipe one time and it will produce every single target that could possibly match the pattern foo_%.cpp".

Upvotes: 4

Related Questions