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
.ofile from a.cfile. You have added a rule that tells make how to build a.ofile from both a.cand.mocfile. 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.mocto%.moc, now the targeta.mocis 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.mocas an explicit prerequisite by adding:You can add the
-roption to the GNU make command line to disable all built-in implicit rules:You can add the
-roption into your makefile by setting theMAKEFLAGSvariable:You can alternatively disable all suffix rules by adding this to your makefile: