如何阻止 make -n 多次回显相同的命令

how to stop make -n from echoing same command multiple times

我正在使用 GNU make 并有一个 Makefile 看起来像这样:

AB = A.txt B.txt

${AB}: makeAB.py
    python makeAB.py

C.txt: ${AB} makeC.py
    python makeC.py

当我键入 make -n C.txt 时,假设 makeAB.py 需要 运行,我得到输出:

python makeAB.py
python makeAB.py
python makeC.py

有没有什么办法可以写Makefile使得python makeAB.py行不重复?这只是一个玩具示例,但在我的实际应用程序中 AB 包含许多文件,因此我可能会得到一整屏不必要的输出。

p.s。在没有 -n 的情况下调用时,make(明智地)仅 运行s python makeAB.py 一次。所以我的问题只是 make -n.

双重输出的出现是因为配方被安排为 运行 两次,一次用于构建 A.txt,另一次用于构建 B.txt。这是 make 的正常行为。特别是一条规则,例如您的(扩展后的)...

A.txt B.txt: makeAB.py
    python makeAB.py

... 意味着这两个目标中的 each 可以通过关联的配方构建,而不是单次执行配方构建两者(无论单个 运行 确实构建了两者)。它 100% 等同于:

A.txt: makeAB.py
    python makeAB.py

B.txt: makeAB.py
    python makeAB.py

When called without -n, make (sensibly) only runs python makeAB.py once. So my problem is just with make -n.

当你运行和-n时,make不执行配方,所以它无法评估这样做是否更新(比如)A.txt也可能更新B.txt。它所知道的是两个目标都已过时,因此它输出将执行以更新每个目标的配方。这完全是明智的。

当你 运行 make 没有 -n 时,它有机会观察到更新 A.txtB.txt 之一后,另一个已是最新。它甚至可能很自然地没有注意到对方最初已经过时了。观察到这一点后,它当然不会再次执行配方。如果配方执行表示正在构建哪个目标,输出将更清楚地说明发生了什么。例如,试试这个规则的变体,它更像是 multiple-target 规则通常的写法。

A.txt B.txt: makeAB.py
    python makeAB.py $@

因此,两个 make 输出都以自己的方式正确。然而,可以说,makefile 是错误的,因为它没有捕捉到 运行 将配方一次生成两个输出的期望和事实。这是 makefile 语言传统上难以表达的情况,您会在 SO 和其他地方找到与此相关的其他问题。

如果您使用的是足够新的 GNU Make 版本,那么您可以利用它的 "grouped target" rules 概念,它正好解决了这个问题。通过在规则的第一行使用 &: 作为分隔符,您可以传达(仅针对最新版本的 GNU Make)规则的一次执行会创建所有指定的目标。示例:

A.txt B.txt &: makeAB.py
    python makeAB.py

传统的 makes 和旧的 GNU Make 只会将 & 解释为另一个目标名称。这意味着那些 makes 将接受这样的 makefile,但行为与最近的 GNU make 不同。除此之外,这意味着如果要求构建目标 &,他们会尝试这样做,由于 & 对 shell 的特殊意义,很可能会产生令人惊讶的效果。