Rule with wildcard to depend on other rules [duplicate] - filter

I'm observing an interesting behavior of make and I wonder if there is a reasonable explanation to it besides a bug in gmake.
Let's say we have the following in makefile:
%-animal:
echo "$* is an animal"
%-fox: %-fox-animal
%-wolf: %-wolf-animal
The difference between the last two targets is that "%-wolf" does not have any recipe, and "%-fox" has an empty recipe (i.e. just a line with a tab at the beginning).
When we try to execute the rules, here's what happens:
[root#cv19 tmp]# make freddy-animal
echo "freddy is an animal"
freddy is an animal
[root#cv19 tmp]# make freddy-wolf
make: *** No rule to make target `freddy-wolf'. Stop.
[root#cv19 tmp]# make freddy-fox
echo "freddy-fox is an animal"
freddy-fox is an animal
i.e.the pattern rule that has a recipe (although an empty one) works, the one that doesn't does not. Am I missing something in the way it's supposed to work?

Pattern rules with no recipes at all are documented as meaning something quite different from those providing a recipe, even an empty one. Instead they cancel any pre-existing implicit rule:
You can cancel a built-in implicit rule by defining a pattern rule with the same target and prerequisites, but no recipe.
Thus your "%-wolf" pattern actually serves to cancel any existing implicit rule for %-wolf-animal -> %-wolf. And there wasn't one anyway.

Related

GNU make - implicit rule is not used, but static pattern rule is

Consider the following makefile (and any hi.c):
.PHONY: analyze-%
hi: hi.c
gcc -o $# $<
%.json: %
touch $# # actually created by analysis-tool
analyze-%: %.json # why does this not work?
As my comment in the makefile points out, the implicit rule does not work:
$ make analyze-hi
make: *** No rule to make target 'analyze-hi'. Stop.
It only works after transforming it into a static pattern rule:
...
analyze-hi: analyze-%: %.json
Why is this the case? Shouldn't make be able to figure this out on its own, without me having to explicitly write the full target name? There is no ambiguity or anything (as far as I'm aware).
Pattern rules must have recipes. If they don't have a recipe then they're not creating a pattern rule, they're canceling one.
See https://www.gnu.org/software/make/manual/html_node/Canceling-Rules.html
A static pattern rule, contrary to what's implied by its name, is not actually creating an implicit rule (pattern or suffix rule). It's creating explicit rules, just based on a pattern. Explicit rules don't have to have recipes.

Implict rule cancellation in Makefile

I have come across the following line in U-boot Makefile ( https://github.com/siemens/u-boot/blob/master/Makefile#L128 ) with comment "Cancel implicit rules on top Makefile".
Can you help me to understand the following line, how/what will happen while executing the following line by make utility.
$(CURDIR)/Makefile Makefile: ;
See How Makefiles Are Remade:
If you know that one or more of your makefiles cannot be remade and you want to keep make from performing an implicit rule search on them, perhaps for efficiency reasons, you can use any normal method of preventing implicit rule look-up to do so. For example, you can write an explicit rule with the makefile as the target, and an empty recipe.
And that is exactly what $(CURDIR)/Makefile Makefile: ; rule does - it has an empty recipe.

Makefile Pattern Rule is found but recipe does not run

I have a makefile that has the following pattern rule to create an implicit rule:
%.cpp:
$(warning foo)
When I check the output of make -d I see that this implicit rule is being found and matching a file. I verify that when I remove the pattern rule, the output of make -d no longer shows a match. However, even when the implicit rule is found, the warning doesn't show up. The recipe isn't running, even though the implicit rule matches.
What gives?
That recipe tells make how to create a %.cpp file (and gives it no prerequisites).
When are you expecting it to be run?
It will not run for any existing *.cpp files as the lack of prerequisites means that make considers the files up to date.
Try running make totally-doesnt-exist.cpp and you should see the warning.

Get error for "make: Nothing to be done for 'target'"

Let me illustrate it with an example.
mkdir test
cd test
touch target
make target
This will result in: make: Nothing to be done for 'target'.
So make tells me there is nothing to do. This is because make did not find a rule to make target, but because the target already exists make tells me there is nothing to do.
Now, I don't want that. I want make to give me an error when it cannot find a rule for target, even though the target already exists.
I have tried the following:
echo '.DEFAULT:
echo make: *** No rule to make target `$#'. Stop.
false'> Makefile
But this does not stop the make when making multiple targets.
The problem is, that make assumes the target name is also a file which will be build by the given commands.
But sometimes this is not true (e.g. think of "clean").
To tell make that some targets don't build this file, you need to make them "phony". Put the following line into your Makefile:
.PHONY: target
If you think about it, you would end up with a chicken-and-egg situation (or infinite regress). Suppose you managed to have a rule that said 'You must have a rule to create target before it is legitimate', then you'd have a rule that says 'target depends on X' for some other file X. That's written:
target: X
command to build target from X
But then you'd be back to the starting point: you'd also want a rule to create X. How can you do that? You might have a rule that depends on nothing and magically creates the file X when it is needed:
X:
command to build X from nothing
Without a rule like that, you have an infinite regress.
So, make is designed to ensure that files exist and are up to date. If a file exists and there are no rules - implicit or explicit - to specify how it is made, then the file is up to date. What you are seeking to do is not possible.
Actually this sounds like a perfectly reasonable (if misguided ;-)) request. You will have to explicitly list every source file with a rule with an empty recipe though.
Here you go:
Makefile: ;
.PHONY: dodgy
dodgy%: dodgy; $(error You must provide a rule for $*)
%: dodgy% ;
The proof of the pudding:
$ rm aa
$ make aa
Makefile:4: *** You must provide a rule for aa. Stop.
$ touch aa
$ make aa
Makefile:4: *** You must provide a rule for aa. Stop.
Note that the line Makefile: ; is necessary. After all, the first thing make tries to do is rebuild the Makefile.
Note also that the catch-all pattern rule is non-terminal. This can be a massive performance hit. As the manual says about match anything rules "They are very useful, but it can take a lot of time for make to think about them."

makefile pattern rules without recipes

I'm observing an interesting behavior of make and I wonder if there is a reasonable explanation to it besides a bug in gmake.
Let's say we have the following in makefile:
%-animal:
echo "$* is an animal"
%-fox: %-fox-animal
%-wolf: %-wolf-animal
The difference between the last two targets is that "%-wolf" does not have any recipe, and "%-fox" has an empty recipe (i.e. just a line with a tab at the beginning).
When we try to execute the rules, here's what happens:
[root#cv19 tmp]# make freddy-animal
echo "freddy is an animal"
freddy is an animal
[root#cv19 tmp]# make freddy-wolf
make: *** No rule to make target `freddy-wolf'. Stop.
[root#cv19 tmp]# make freddy-fox
echo "freddy-fox is an animal"
freddy-fox is an animal
i.e.the pattern rule that has a recipe (although an empty one) works, the one that doesn't does not. Am I missing something in the way it's supposed to work?
Pattern rules with no recipes at all are documented as meaning something quite different from those providing a recipe, even an empty one. Instead they cancel any pre-existing implicit rule:
You can cancel a built-in implicit rule by defining a pattern rule with the same target and prerequisites, but no recipe.
Thus your "%-wolf" pattern actually serves to cancel any existing implicit rule for %-wolf-animal -> %-wolf. And there wasn't one anyway.

Resources