"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

如果只有 foofoo.c(以及 Makefile):

#bar
#%

我不确定当有 bar.c 文件时会发生什么,但我认为如果没有 运行 唯一的“命令”将是 #bar.

那么,这些rules/dependencies是如何解决的呢?


我感兴趣的原因是因为这个 implicit/explicit “double-rule” 语法似乎对于理解 -Minclude 如何自动化 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 的时间戳比 barfoo.c.

#bar

#%


为了计算出我们需要同时获得 #bar#% 的文件组合,我们使用来自 #bar 部分(以上)的逻辑,这更简单:我们不能有一个 bar 文件。查看 #% 部分,我们发现如果我们没有 bar 文件,那么我们仍然需要 foofoo.c 文件(但时间戳无关紧要)。因此目录将是:foofoo.cMakefile,加上除 bar.

之外的任何其他文件