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

Mon*_*ans 1 linux makefile gnu-make

如果您运行make test以下 Makefile(带有空目录):

test.%:
    @echo $*

test: test.dummyextension
Run Code Online (Sandbox Code Playgroud)

你会得到以下输出:

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
Run Code Online (Sandbox Code Playgroud)

为什么?

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

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

Tre*_*ntP 7

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

%: %.o
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
Run Code Online (Sandbox Code Playgroud)

这告诉 maketest如果它能找到制作中间文件的方法,它就可以制作test.o。所以现在它会寻找一种制作方法test.o,并看到您的模式规则test.%:,它与 Stem 匹配o。所以它找到了办法!

您还告诉 maketest需要test.dummyextension,因此它会寻找一种方法来实现该需求,并再次使模式test.%:匹配,这次是与 Stem dummyextension

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

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

这里需要理解的要点是:

一行的形式:

test: test.dummyextension
Run Code Online (Sandbox Code Playgroud)

只添加对目标的依赖关系。制定目标并不是规则。这可以来自其他地方。Make 没有看到这一点,并决定test应该使用空白配方创建。

形式的节:

test: test.dummyextension
        ;
Run Code Online (Sandbox Code Playgroud)

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

如果没有找到显式规则,Make 将搜索隐式规则来创建任何目标。如果您不希望它这样做,您可以给它一个明确的规则,如上面所示,或者将目标声明为虚假目标,使用.PHONY: target. 不会搜索隐式规则来查找虚假目标。