为什么 GNU Make 会尝试编译一个不存在的目标文件,用于没有配方的规则?

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

如果您 运行 make test 在以下 Makefile 上(否则目录为空):

test.%:
    @echo $*

test: test.dummyextension

你得到以下输出:

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

为什么?

我怀疑它与隐式规则有关,但我在我的机器上搜索了 make -p,但找不到任何匹配 %: % 的隐式规则。我希望输出只是 dummyextension,但它几乎就像我的目录中有一个幻影 test.o 文件(尽管我检查了十次没有)。

如果您在 test.dummyextension 先决条件之后放置 ;,或者向 test 规则添加任何内容,一切都会按预期进行。这是我能想到的最小的失败示例,我不知道为什么您会看到这种行为。有什么想法吗?

Make 可以链接多个规则来创建一个目标。在这种情况下,它具有以下内置规则:

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

这告诉 make,如果它能找到制作中间文件 test.o 的方法,它就可以制作 test。所以现在它寻找一种方法来制作 test.o 并且它看到你的模式规则 test.%:,它与词干 o 相匹配。所以它找到了方法!

您还告诉 make test 需要 test.dummyextension,因此它会寻找一种方法来实现这一点,然后模式 test.%: 再次匹配,这次是词干 [=21] =].

所以 make 首先运行 test.% 配方两次来制作两个先决条件。然后它运行 %: %.o 配方来制作最终目标。配方中的 $^ 是所有先决条件,因此从内置模式规则获得的 test.o 和通过 Makefile 中的显式依赖获得的 test.dummyextension 都出现在命令中.

您可以通过使用 -r 标志禁用内置规则来测试它,然后将上述模式规则手动添加到您的 Makefile。

这里要理解的重点是:

一行的形式:

test: test.dummyextension

仅向目标添加依赖项。它不是制定目标的规则。这可能来自其他地方。 Make 没有看到这一点,因此决定 test 应该使用空白配方创建。

以下形式的节:

test: test.dummyextension
        ;

这个制定目标的规则。作为显式规则,它比可能也匹配的模式规则具有更高的优先级。这确实告诉 make 它已经找到使用配方 ; 制作 test 的规则,并且它停止寻找另一个规则。

如果找不到明确的目标,Make 将搜索隐式规则来创建任何目标。如果你不想让它这样做,你可以给它一个明确的规则,就像上面那样,或者用 .PHONY: target 声明目标是假的。不搜索隐式规则以查找虚假目标。