为什么“%.moc”在我的 Makefile 中不起作用?

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

我有以下 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 $<

在Makefile所在的同一目录下,有一个名为“a.cpp”的文件。

当我执行“make a.o”时,将打印以下内容:

mocing a.moc
all prerequisites a.cpp a.moc
g++ -std=c++17 -Werror -Wall -o a.o -c a.cpp

太完美了。 “a.moc”被识别并被执行。

但是,如果我替换

a.moc: 
    @echo "mocing $@"

%.moc: 
   @echo "mocing $@"

然后事情开始发生变化。仅打印以下内容:

g++    -c -o a.o a.cpp

似乎“%.moc:”的引入把一切都搞砸了。这只是一个演示示例。在我的真实环境中,“%.moc”确实执行一些 Qt 移动操作。我想知道为什么“a.moc”可以被识别为有效目标并被执行,而“%.moc”不能达到目标?

问题在于 make 有一系列内置的隐式规则。这些规则之一告诉 make 如何从 .c 文件构建 .o 文件。您添加了一条规则,告诉 make 如何从 .c.moc 文件构建 .o 文件。 make如何选择使用哪一个?

测试隐式规则的顺序始终是首先检查您的规则,这就是当您有 a.moc 时它起作用的原因。那么,如果将其更改为 %.moc 为什么会失败?

full algorithm 在 GNU make 手册中有准确描述。基本上,当您将规则从 a.moc 切换到 %.moc 时,现在目标 a.moc 不会在您的 makefile 中的任何地方提及,因此 make 不会认为它“应该存在”(请参阅此定义的算法)。

您可以通过多种不同的方式解决此问题:

您可以通过添加以下内容将 a.moc 列为明确的先决条件:

a.o: a.moc

您可以将 -r 选项添加到 GNU make 命令行以禁用所有内置隐式规则:

$ make -r

您可以通过设置 MAKEFLAGS 变量将 the -r option 添加到您的 makefile 中:

MAKEFLAGS += -r

您也可以 disable all suffix rules 将此添加到您的 makefile 中:

.SUFFIXES: