为什么 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
声明目标是假的。不搜索隐式规则以查找虚假目标。
如果您 运行 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
声明目标是假的。不搜索隐式规则以查找虚假目标。