I have the following Makefile:
CC=g++ -std=c++17
MYCXXFLAGS=-Werror -Wall
clean:
rm -f *.o main
a.moc:
@echo "mocing $@"
%.o: %.cpp %.moc
@echo "all prerequisites $^"
$(CC) $(MYCXXFLAGS) -o $@ -c $<
Under the same directory where the Makefile lives, there is a file called "a.cpp".
When I do "make a.o", the following gets printed:
mocing a.moc
all prerequisites a.cpp a.moc
g++ -std=c++17 -Werror -Wall -o a.o -c a.cpp
Which is perfect. The "a.moc" gets identified and gets executed.
However, if I replace
a.moc:
@echo "mocing $@"
with
%.moc:
@echo "mocing $@"
Then the thing starts to change. Only the following stuff is printed:
g++ -c -o a.o a.cpp
It seems the introduction of "%.moc:" messes everything up. This is just a demo example. In my real environment, the "%.moc" really does some Qt mocing operation. I am wondering why "a.moc" can be identified as a valid target and gets executed, while "%.moc" cannot achieve the goal?
The problem is that make has a series of built-in implicit rules. One of these rules tells make how to build a .o
file from a .c
file. You have added a rule that tells make how to build a .o
file from both a .c
and .moc
file. How does make choose which one to use?
The order of testing implicit rules is always that your rules are checked first, which is why it works when you have a.moc
. So why does it fail if you change that to %.moc
?
The full algorithm is described precisely in the GNU make manual. Basically when you switch the rule from a.moc
to %.moc
, now the target a.moc
is not mentioned anywhere in your makefile and so make doesn't consider that it "ought to exist" (see the algorithm for this definition).
You can fix this in many different ways:
You can list a.moc
as an explicit prerequisite by adding:
a.o: a.moc
You can add the -r
option to the GNU make command line to disable all built-in implicit rules:
$ make -r
You can add the -r
option into your makefile by setting the MAKEFLAGS
variable:
MAKEFLAGS += -r
You can alternatively disable all suffix rules by adding this to your makefile:
.SUFFIXES: