qtmakefilemoc

Why the "%.moc" does not work in my Makefile?


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?


Solution

  • 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: