Home > Blockchain >  Why does GNU Make try to compile an object file that doesn't exist, for a rule without a recipe
Why does GNU Make try to compile an object file that doesn't exist, for a rule without a recipe

Time:12-06

If you run make test on the following Makefile (with an otherwise empty directory):

test.%:
    @echo $*

test: test.dummyextension

you get the following output:

dummyextension
o
cc   test.o test.dummyextension   -o test
clang: error: no such file or directory: 'test.o'
clang: error: no such file or directory: 'test.dummyextension'
clang: error: no input files
make: *** [test] Error 1

Why?

I suspect it has something todo with implicit rules, but I searched make -p on my machine, and can't find any implicit rules that match %: %. I would expect the output to simply be dummyextension, but it's almost like there's a phantom test.o file in my directory (despite my checking ten times that there is not).

If you put a ; after the test.dummyextension prerequisite, or add any content to the test rule, everything works as expected. This is the minimal failing example I can come up with, and I haven't a clue why you'd see this behaviour. Any ideas?

CodePudding user response:

Make can chain multiple rules to create a target. In this case it has the following built-in rule:

%: %.o
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

This tells make that it can make test if it can find a way to make intermediate file test.o. So now it looks for a way to make test.o and it sees your pattern rule test.%:, which matches with stem o. So it has found a way!

You have also told make that test needs test.dummyextension, so it looks for a way to make that and again the pattern test.%: matches, this time with stem dummyextension.

So make first runs the test.% recipe twice to make the two prereqs. Then it runs the %: %.o recipe to make the final target. The $^ in the recipe is all prerequisites, so both test.o, gained from the built-in pattern rule, and test.dummyextension, gained by the explicit dependency in your Makefile, appear in the command.

You can test this by using the -r flag to disable built-in rules and then add the above pattern rule manually to your Makefile.

The key points to understand here are:

A line of the form:

test: test.dummyextension

Only adds a dependency to a target. It is not a rule to make the target. That can come from elsewhere. Make does not see this and decide test should be created with a blank recipe.

A stanza of the form:

test: test.dummyextension
        ;

This is a rule to make the target. Being an explicit rule it has a higher priority than a pattern rule that might also match. This does tell make it has found the rule to make test using the recipe ; and it stops looking for another rule.

Make will search for an implicit rule to make any target if it does not find an explicit one. If you don't want it to do this, you can either give it an explicit rule, like above, or declare the target as phony, with .PHONY: target. Implicit rules are not searched for phony targets.

  • Related