Reputation: 13664
In my gnu-make-3.81 Makefile, I wish to define two implicit rules, such that the more specific first one takes precedence over the more general second one:
src/%_bar.o : src/%_bar.c
$(CC) -Wall -Wno-unused-but-set-variable -c $^ -o $@
src/%.o : src/%.c
$(CC) -Wall -c $^ -o $@
The issue I have is that foo_bar.c represents autogenerated code that triggers a warning with -Wall that I'd prefer to suppress, so the first rule is meant to catch this special case.
According to make's manual:
It is possible that more than one pattern rule will meet these criteria. In that case, make will choose the rule with the shortest stem (that is, the pattern that matches most specifically).
I thought that for a filename of src/foo_bar.o
, the first rule would generate the stem foo
, and the second would generate foo_bar
. The former is the shortest so I'd expect it to apply. However this doesn't seem to be the case, the second rule is selected by make and executed. Running make -d
doesn't even show an attempt to match with the stem foo
- only foo_bar
is considered.
If I make the following change, by making the second rule's stem deliberately longer by shortening the prefix from src/
to sr
, the second rule is still selected:
src/%_bar.o : src/%_bar.c
$(CC) -Wall -Wno-unused-but-set-variable -c $^ -o $@
sr%.o : sr%.c
$(CC) -Wall -c $^ -o $@
I can't reconcile this with the make documentation.
In addition, if I remove the src/
prefix entirely, the second rule is selected:
src/%_bar.o : src/%_bar.c
$(CC) -Wall -Wno-unused-but-set-variable -c $^ -o $@
%.o : %.c
$(CC) -Wall -c $^ -o $@
Although this solves my problem, it's actually not suitable because it overrides/interacts with another implicit rule on the current directory that I need to keep:
%.o : %.c
# do something else
My question is why does make
behave this way in this case, and is this consistent with the documentation? If so, is there a better way to specify a more specialised implicit rule?
Upvotes: 3
Views: 286
Reputation: 100956
First, be aware that the "shortest stem" method of pattern matching was introduced in GNU make 3.82. If you're using GNU make 3.81 then your version of make uses the old method which was "first match". It's always best to read the documentation that comes with your distribution, if possible, rather than the web documentation because the web documentation is for the latest version of GNU make. GNU make 3.81 was released in April 2006... that's pretty old.
However, the example you provided actually DOES work the way you wanted it to:
src/%_bar.o : src/%_bar.c ; @echo shorter: $*
src/%.o : src/%.c ; @echo longer: $*
all: src/foo_bar.o
$ make-3.81
shorter: foo
$ make-3.82
shorter: foo
I suspect that when you asked your question here you didn't use the same code you're using in your real environment. In that environment you must have the shorter pattern after the longer pattern, like this:
src/%.o : src/%.c ; @echo longer: $*
src/%_bar.o : src/%_bar.c ; @echo shorter: $*
all: src/foo_bar.o
$ make-3.81
longer: foo_bar
$ make-3.82
shorter: foo
When asking questions it's very important to be sure that the simplified examples in the question accurately reflect the real situation.
Upvotes: 4