GNU make not matching shortest stem - makefile

Why is the shortest stem not being matched in this makefile?
foo/%/baz:
#echo "Prereq - stem $*"
foo/%/baz/thing.txt: foo/%/baz
#echo "Good match - stem $*"
foo/%:
#echo "Bad match - stem $*"
Here's the output:
> make foo/bar/baz/thing.txt
Bad match - stem bar/baz/thing.txt
I'd expect make to match the more specific (shorter stem) foo/%/baz/thing.txt instead of foo/%.
This is not a version 3.81 issue, (as was the case in these other two similar SO questions).
when multiple pattern rules match a target
Makefile implicit rule matching - prefix length not affecting match
> make --version
GNU Make 4.2.1
I can achieve expected behavior by either:
Removing the more general rule
foo/%/baz:
#echo "Prereq - stem $*"
foo/%/baz/thing.txt: foo/%/baz
#echo "Good match - stem $*"
> make foo/bar/baz/thing.txt
Prereq - stem bar
Good match - stem bar
Removing the prerequesite from the more specific rule
foo/%/baz:
#echo "Prereq - stem $*"
foo/%/baz/thing.txt:
#echo "Good match - stem $*"
foo/%:
#echo "Bad match - stem $*"
> make foo/bar/baz/thing.txt
Good match - stem bar
I'm confused why the prerequesite added to the specific rule causes the general rule to be matched instead.

Sorry, when I suggested you file a bug I didn't read your question carefully enough and was confused that it was the prerequisite that should have been matched, but you were wondering why the initial rule wasn't matched.
That is not a bug: it is due to this statement in the documentation:
Note however, that a rule whose prerequisites actually exist or are mentioned always takes priority over a rule with prerequisites that must be made by chaining other implicit rules.
I really apologize, that was totally my bad for not reading carefully :(.

Related

Multiple stems (%) in a Makefile prerequisite

I'm trying to use the following Makefile to create the target foo.a with foo.foo.b as a prerequisite, using the stem character (%) as shown.
%.a: %.%.b
touch $#
However running touch foo.foo.b; make foo.a doesn't work with No rule to make target. The debug output below shows that the stem % is only expanded once. How to get the desired behavior of replacing all % in the prerequisite?
Considering target file 'sdf.a'.
File 'sdf.a' does not exist.
Looking for an implicit rule for 'sdf.a'.
Trying implicit prerequisite 'sdf.%.b'.
Looking for a rule with intermediate file 'sdf.%.b'.
Avoiding implicit rule recursion.
Trying pattern rule with stem 'sdf.%.b'.
Trying implicit prerequisite 'sdf.%.b,v'.
(..)
No implicit rule found for 'sdf.a'.
Finished prerequisites of target file 'sdf.a'.
Must remake target 'sdf.a'.
make: *** No rule to make target 'sdf.a'. Stop.
Side note: this seems like a trivial question but for some reason I can't find the answer, maybe I'm using the wrong search terms or overlooking something simple, sorry if that is the case.
The stem is only replaced once. If you wish to have stem contents inserted more than once, you would need to use secondary expansion, i.e.:
$ cat Makefile
.SECONDEXPANSION:
%.a: $$*.$$*.b
echo Making $# from $<
Output:
$ touch foo.foo.b
$ make -s foo.a
Making foo.a from foo.foo.b

Makefile : last resort match anything pattern

According to the GNU make guide, "The rules you write take precedence over those that are built in. Note however, that a rule whose prerequisites actually exist or are mentioned always takes priority over a rule with prerequisites that must be made by chaining other implicit rules."
So I wrote this testing makefile to do a little experiment (GNUmakefile is the name of this testing makefile) :
% ::
#echo "last resort implicit rule is working"
.DEFAULT_GOAL = src/hello.o
src/hello.o :
GNUmakefile : ;#used to prevent remaking this makefile, although in this case it is unnecessary.
My file organization is illustrated as the following :
GNUmakefile(#ordinary file)
src(#directory)
----hello.c(#ordinary file)
I was expecting it to output "last resort implicit rule is working", since src/hello.o will match the target pattern % :: and this is a terminal match anything implicit rule. According to the Implicit rule search algorithm specified in GNU make guide, this rule should apply.
However, when I run make , it output cc -c -o src/hello.o src/hello.c.
I figured out that in fact src/hello.o was matched against the built-in implicit rule. When I run make -r , it output "last resort implicit rule is working". And the output of make -d attested this.
But I think this behavior is contradicting what is specified in GUN make guide.
Can anyone help?
By the way, I read the last resort rule in GUN make guide, it says "So such a rule’s recipe is used for all targets and prerequisites that have no recipe of their own and for which no other implicit rule applies.". Is this the solution to my question? I doubt that, because I think this depends on whether last resort rule is defined and where the last resort rule is defined because orders matters when searching for implicit rule using the algorithm specified in GNU make guide.
It works fine with some ancient make at my workplace...
[teve#madar mktest]$ tree
.
├── GNUmakefile
└── src
└── hello.c
1 directory, 2 files
[teve#madar mktest]$ cat GNUmakefile
% ::
#echo "last resort implicit rule is working"
.DEFAULT_GOAL = src/hello.o
src/hello.o :
GNUmakefile : ;#blablabla
[teve#madar mktest]$ make
last resort implicit rule is working
[teve#madar mktest]$ make --version
GNU Make 3.81
[...]
... and it does not work with one-step less ancient make:
[teve#madar mktest]$ make
cc -c -o src/hello.o src/hello.c
[gergelyc#sauron mktest]$ make --version
GNU Make 3.82
[...]
Given that the current versions are 4.x, I feel super lucky to have exactly these two versions with the behaviour-change.
I tried to look at occurrences of implicit, built, order, last and match in a changelog ending with 3.82, but I have not found anything obvious.
Canceling the built-in rule with an empty %o : %c works, by the way.

Match-Anything Pattern Rules

I am using GNU Make 3.81 version.
From the following example, I expect match anything pattern(%:) has to be print. Instead of that te%: has executed.
Can some one explain, why target '%:' did not run?
Is this not match all file name?
Makefile:
all: test
echo $#
%:
echo 1: $#
te%:
echo 2: $#
Output:
echo 2: test
2: test
echo all
all
There are special rules for how make treats match-anything pattern rules; see the documentation. You are creating a "non-terminal match-anything rule" here, and the rule for that is this:
A non-terminal match-anything rule cannot apply to a file name that indicates a specific type of data. A file name indicates a specific type of data if some non-match-anything implicit rule target matches it.
In your case you have a non-match-anything implicit rule target (te%) which matches the file name (test) and so a non-terminal match-anything rule (%:) cannot match it.

Rule with wildcard to depend on other rules [duplicate]

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.

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