在 Makefile 中有几乎重复的目标规则的后果是啥?

Posted

技术标签:

【中文标题】在 Makefile 中有几乎重复的目标规则的后果是啥?【英文标题】:What are the consequences of having almost duplicate target rules in a Makefile?在 Makefile 中有几乎重复的目标规则的后果是什么? 【发布时间】:2020-05-02 16:07:45 【问题描述】:

我继承了导致构建问题的有问题的 Makefile.am。在这个 makefile 中,有几个实例几乎存在重复的目标规则。它们几乎是重复的,因为第二个有一个或两个额外的先决条件。这是一个例子:

target1 target2: prereq1 prereq2 
        ACTION

target1 target2: prereq1 prereq2 prereq3
        ACTION

动作相同,target1和target2相同。这样做的后果是什么?两条规则都会执行吗?

稍微扩展一下这个问题,如果 prereq3 是在 make 过程中自动生成的,这将如何发挥作用?如果 make 并行运行,这会导致大问题吗?

【问题讨论】:

【参考方案1】:

动作相同,target1和target2相同。什么 这是后果吗?两条规则都会执行吗?

结果是基于此Makefile.am 生成的makefile 将逐字包含这两个规则,将不符合makefile 的POSIX 规范。 POSIX 禁止多个目标规则为任何给定目标提供配方。

如果你碰巧使用 GNU make 来构建,那么它不会直接拒绝 makefile,而是使用每个目标的最后给出的配方;每个目标的所有其他目标规则将被视为仅先决条件规则,无论它们是否提供配方。如果您使用不同的make(Autotools 明确支持),那么结果可能会有所不同。在 Autotools 构建系统中,依赖于特定于实现的行为是非常糟糕的形式。

由于配方相同,目标相同,并且早期规则的先决条件列表是后面规则的先决条件列表的子集,我认为没有任何理由保留早期规则。只是批发删除它。在 GNU make 下,任何行为都不会改变,您不必担心其他 makes 的行为会因为这个问题而有所不同。

不过,这确实假定target1target2 没有其他 目标规则。如果提供配方的target2 的最后出现规则与提供配方的target1 的最后出现规则不同,则将运行两个配方:一个用于生成target1(可能带有边同时生成target2的效果),另一个生成target2(可能还有同时生成target1的副作用)。它们的相对顺序未指定,结果可能不一致。

您还应该阅读the Automake manual's comments on tools and rules that generate multiple targets。

稍微扩展一下这个问题,如果 prereq3 是在 make 过程中自动生成的,这将如何发挥作用?

与已经描述的没有什么不同,至少对于 GNU make。您描述的构造可能是出于对这个问题的误解,或者它可能针对 make 实现而不是 GNU 的某些特定于实现的行为,但如果目前软件构建正确使用 GNU make 然后删除第一条规则只会将生成的 makefile 转换为符合 POSIX 的文件(在这方面),没有理由期望行为会发生任何变化。

可能存在与您的具体情况相关的细微差别和替代解决方案,但无论任何此类细节如何,上述所有 cmets 均适用。

如果 make 并行运行,这会导致大问题吗?

您描述的表单的规则重复与并行make 没有特定的交互。但是,如果您不表达每个目标的完整依赖关系,尤其是对其他构建目标的依赖关系,您可能会遇到并行 make 的问题。但请注意,您通常不需要表达对 C 或 C++ 头文件的依赖关系,甚至是构建的头文件,因为 Automake 生成的 makefile 包含用于自动检测和跟踪这些文件的代码。

但是,如果您有其他目标规则为一个或两个目标提供配方,如上所述,那么是的,这将是并行 make 的问题。帮自己一个忙,并确保没有一个目标具有由多个目标规则指定的配方。

此外,虽然规则重复可能不是并行 make 的问题,但如果一次运行配方生成两个目标,那么 可能会为并行 make 造成问题。有关该点的更多评论,请参阅上面链接的 Automake 手册。

【讨论】:

非常感谢您的全面回复。我花了很多时间来研究你给我的信息,试图找出应该删除哪些规则。在这样做的过程中,我一直在删除某些规则并尝试构建。我尝试的第一件事是删除所有受骗者并保持第二条规则不变。我想既然这些是被制造所尊重的,我可以把其他的拿出来。事实并非如此。一旦这些规则被删除,构建就不再成功。所以这些规则必须以某种方式使用,对吗? 我尝试的第二件事是,在“骗子”中,我保留了具有最多先决条件的规则。这也失败了。 @short-aj,你描述的第一个策略听起来与我推荐的一致。如果在那之后构建不再起作用,那么我倾向于认为问题没有传达一些重要的细节。另请注意:一次使用一组重复规则而不是一次使用所有规则可能是值得的。这将缩小更改的范围,让您可以单独关注每种情况。 我确实没有提到所有这些规则都是模式规则。我猜这会成功,所以 make 不仅会选择文件中的最后一个吗?【参考方案2】:

假设您使用的是 gnu make,警告表明第一条规则被忽略。使用 lol 运行 make 从第二个配方执行操作。可以删除第一个配方中的 ACTION(这将删除警告!)。

make

Makefile:5: warning: overriding recipe for target 'target1'
Makefile:2: warning: ignoring old recipe for target 'target1'
Makefile:5: warning: overriding recipe for target 'target2'
Makefile:2: warning: ignoring old recipe for target 'target2'
echo "Action2"
Action2

引自 gnu make 手册:https://www.gnu.org/software/make/manual/make.html

警告:覆盖目标 xxx' warning: ignoring old recipe for targetxxx' 的配方

GNU make 只允许一个配方 每个目标指定(双冒号规则除外)。如果你给一个 一个已经被定义为有一个目标的配方,这个 发出警告,第二个配方将覆盖第一个。看 一个目标的多个规则。

【讨论】:

你能用你写的小makefile来增加你的答案吗? 没关系,我想我也明白了,谢谢你的回答

以上是关于在 Makefile 中有几乎重复的目标规则的后果是啥?的主要内容,如果未能解决你的问题,请参考以下文章

makefile

Makefile文件_书写规则

Makefile总述②

跟我一起写Makefile

makefile 双冒号规则

Recursive makefile 没有规则使目标“全部”。停止