"make" reads/resolves 具有 percentage-matched 目标的 Makefile 与显式相比如何?
How "make" reads/resolves Makefile with percentage-matched target vs. explicit?
我以为我理解 %
模式匹配:
%.o : %.c
#...
...等同于“显式”编写目标规则:
f1.o : f1.c
#...
f2.o : f2.c
#...
(假设只有 .c
个文件)
我也知道为同一个显式目标编写多个规则会导致规则被最后定义的规则覆盖:
r :
#1
r :
#2
(make
输出 #2
)
那么,make
到底是如何解析下面的Makefile的呢?
foo : bar
bar :
#bar
% : %.c
#%
当bar.c
是目录中唯一的.c
文件时(或者有none),输出:
#bar
如果只有 foo
和 foo.c
(以及 Makefile):
#bar
#%
我不确定当有 bar.c
文件时会发生什么,但我认为如果没有 运行 唯一的“命令”将是 #bar
.
那么,这些rules/dependencies是如何解决的呢?
我感兴趣的原因是因为这个 implicit/explicit “double-rule” 语法似乎对于理解 -M
和 include
如何自动化 header 依赖项,例如:
a.out: main.o
g++ main.o
%.o: %.cpp
g++ $< -c
main.o: main.cpp foo.h # <-- what *.d files look like
...导致所需的行为,如:
a.out: main.o
g++ main.o
main.o: main.cpp foo.h
g++ $< -c
I thought I understood that % pattern matching ... was equivalent to "explicitly" writing the targets ... (assuming those are the only .c files)
不对。
模式规则是一个模板,告诉 make 如何构建目标。模式规则仅在没有针对该目标的明确规则时使用。模式规则不会说“去查找所有匹配此模式的文件并为它们创建明确的规则”。它说,“如果你发现你需要构建一个目标,但你还没有任何明确的规则,并且目标匹配这个模式,那么你可以按照以下方式构建它”。
例如,如果您有一个仅包含模式规则的 makefile,即使这些模式规则与现有文件匹配,并且您只需键入 make
,您将收到一条消息,表明 make 无关.那是因为你没有要求 make 构建任何东西,你只是告诉 make 如何构建一些东西。
I also know that writing multiple rules for the same explicit target results in the rule being overwritten by the last defined rule
当然,如果您这样做会覆盖现有食谱,您会收到警告。
了解您可以根据需要使用任意多行向目标添加新的先决条件,这一点很重要。直到您创建了一个配方,您才创建了一个明确的规则。在那之前,没有符合目标的实际规则。
在 MadScientist
的专家回答之上,我想我会解释它如何应用于 Makefile 的两个输出(这可能对像我这样的 make
初学者有用):
foo: bar
bar :
#bar
% : %.c
#%
#bar
当没有 bar
文件时:
bar :
#bar
...那么 bar
是一个“非文件”(虚假)目标。没有先决条件的虚假目标总是执行配方——与文件目标相反,没有先决条件意味着目标永远不会执行其配方(不确定为什么这不会导致警告)。所以,具有讽刺意味的是,当没有 bar
文件时,我们会看到 #bar
输出,否则我们不会看到。
#%
正如 MadScientist 在他的回答中所说,% : %.c
永远无法与 bar
/bar.c
匹配,因为 bar
有一个明确的规则(即带有食谱的规则) .但是,我们可以使用
中的食谱
% : %.c
#%
... 如果我们有文件 foo
/foo.c
。这是因为 foo : bar
不是明确的规则(没有配方)。 Makefile 等同于:
foo: bar
bar :
#bar
foo : foo.c
#%
...相当于:
foo: bar foo.c
#%
bar :
#bar
所以如果没有 bar
文件,或者如果 foo
的时间戳比 bar
或 foo.c
.
#bar
#%
为了计算出我们需要同时获得 #bar
和 #%
的文件组合,我们使用来自 #bar
部分(以上)的逻辑,这更简单:我们不能有一个 bar
文件。查看 #%
部分,我们发现如果我们没有 bar
文件,那么我们仍然需要 foo
和 foo.c
文件(但时间戳无关紧要)。因此目录将是:foo
、foo.c
、Makefile
,加上除 bar
.
之外的任何其他文件
我以为我理解 %
模式匹配:
%.o : %.c
#...
...等同于“显式”编写目标规则:
f1.o : f1.c
#...
f2.o : f2.c
#...
(假设只有 .c
个文件)
我也知道为同一个显式目标编写多个规则会导致规则被最后定义的规则覆盖:
r :
#1
r :
#2
(make
输出 #2
)
那么,make
到底是如何解析下面的Makefile的呢?
foo : bar
bar :
#bar
% : %.c
#%
当bar.c
是目录中唯一的.c
文件时(或者有none),输出:
#bar
如果只有 foo
和 foo.c
(以及 Makefile):
#bar
#%
我不确定当有 bar.c
文件时会发生什么,但我认为如果没有 运行 唯一的“命令”将是 #bar
.
那么,这些rules/dependencies是如何解决的呢?
我感兴趣的原因是因为这个 implicit/explicit “double-rule” 语法似乎对于理解 -M
和 include
如何自动化 header 依赖项,例如:
a.out: main.o
g++ main.o
%.o: %.cpp
g++ $< -c
main.o: main.cpp foo.h # <-- what *.d files look like
...导致所需的行为,如:
a.out: main.o
g++ main.o
main.o: main.cpp foo.h
g++ $< -c
I thought I understood that % pattern matching ... was equivalent to "explicitly" writing the targets ... (assuming those are the only .c files)
不对。
模式规则是一个模板,告诉 make 如何构建目标。模式规则仅在没有针对该目标的明确规则时使用。模式规则不会说“去查找所有匹配此模式的文件并为它们创建明确的规则”。它说,“如果你发现你需要构建一个目标,但你还没有任何明确的规则,并且目标匹配这个模式,那么你可以按照以下方式构建它”。
例如,如果您有一个仅包含模式规则的 makefile,即使这些模式规则与现有文件匹配,并且您只需键入 make
,您将收到一条消息,表明 make 无关.那是因为你没有要求 make 构建任何东西,你只是告诉 make 如何构建一些东西。
I also know that writing multiple rules for the same explicit target results in the rule being overwritten by the last defined rule
当然,如果您这样做会覆盖现有食谱,您会收到警告。
了解您可以根据需要使用任意多行向目标添加新的先决条件,这一点很重要。直到您创建了一个配方,您才创建了一个明确的规则。在那之前,没有符合目标的实际规则。
在 MadScientist
的专家回答之上,我想我会解释它如何应用于 Makefile 的两个输出(这可能对像我这样的 make
初学者有用):
foo: bar
bar :
#bar
% : %.c
#%
#bar
当没有 bar
文件时:
bar :
#bar
...那么 bar
是一个“非文件”(虚假)目标。没有先决条件的虚假目标总是执行配方——与文件目标相反,没有先决条件意味着目标永远不会执行其配方(不确定为什么这不会导致警告)。所以,具有讽刺意味的是,当没有 bar
文件时,我们会看到 #bar
输出,否则我们不会看到。
#%
正如 MadScientist 在他的回答中所说,% : %.c
永远无法与 bar
/bar.c
匹配,因为 bar
有一个明确的规则(即带有食谱的规则) .但是,我们可以使用
% : %.c
#%
... 如果我们有文件 foo
/foo.c
。这是因为 foo : bar
不是明确的规则(没有配方)。 Makefile 等同于:
foo: bar
bar :
#bar
foo : foo.c
#%
...相当于:
foo: bar foo.c
#%
bar :
#bar
所以如果没有 bar
文件,或者如果 foo
的时间戳比 bar
或 foo.c
.
#bar
#%
为了计算出我们需要同时获得 #bar
和 #%
的文件组合,我们使用来自 #bar
部分(以上)的逻辑,这更简单:我们不能有一个 bar
文件。查看 #%
部分,我们发现如果我们没有 bar
文件,那么我们仍然需要 foo
和 foo.c
文件(但时间戳无关紧要)。因此目录将是:foo
、foo.c
、Makefile
,加上除 bar
.