【问题标题】:Wrong expansion for the variable "$?" in makefile变量“$?”的错误扩展在生成文件中
【发布时间】:2015-08-20 09:37:50
【问题描述】:

来自docs

$?

比目标更新的所有先决条件的名称, 它们之间有空格。



现在,给定一个 makefile:

# Create target 'all', that is created later than 'old', which was created after 'older'.
$(shell touch older)
$(shell sleep 1)
$(shell touch old)
$(shell sleep 1)
$(shell touch all)

all : old phony;
    @echo '"$$?" is: "$?"'

# A command to turn the file 'old' even "older", by acquiring the modification-time of 'older'.
old ::
    cp -p 'older' 'old'


.PHONY: phony



跑步,我明白了:

$ make
cp -p 'older' 'old'
"$?" is: "old phony"

# Trying again, but this time, with a *parallel-execution*.
$ make -j
cp -p 'older' 'old'
"$?" is: "phony"



*你看,对于 并行执行 (-j),Make 扩展 $? 的值与 em>非并行执行?*

我们先分析第一种情况,即非并行执行。

allold的修改时间为:

  • 在构建之前oldall“旧”。这是不言而喻的。对吧?
  • Make 构建完前提条件后,即 Make "builds" old, old got "older" 之后,可以说是通过“获取”修改时间一个名为:older 的文件。这基本上是 shell 命令的最终结果:cp -p older old。现在,不难看出,olderall“老”方式

现在,由于 other 先决条件,Make 最终构建了目标 all,即:phony

但是,根据文档,$? 应该只扩展为“比目标更新的所有先决条件的名称”。这是一个准确的引用。

我们是否可以同意,old从未更新all。而且,如果不是 phony,Make 甚至不会重新构建 all

那么,对于 Make 来说,将 $? 扩展为 old phony 是多么错误。

phony 我明白了。但是old?真的吗?!



但是,现在让我们将注意力转向并行执行,其中 Make 将 $? 扩展为 phony

这里:

  1. 当然,可以说这个扩展是正确的(与非并行执行中的扩展相比)。 原因是,只有phony触发all重新构建的文件。没有它,Make 根本不会费心重新构建 all

  2. 仍然有人想知道,对于这两种执行模式,如何以不同方式扩展变量。 我什至无法想到,这与$? 的扩展有何关系。

    总之,看起来“随机”变化(即执行模式的修改,从并行非并行)影响了看似无关的实体,即自动变量的扩展。为什么?

【问题讨论】:

  • 我刚刚发布了对链接问题here 的回答,我相信它也回答了这个问题。

标签: makefile gnu-make


【解决方案1】:

任何由 make 构建或更新的文件都已更新,因此它会隐含地假定它是较新的,即使您修改了使其变旧的命令。

理论上,Make 应该处理文件的内容,而不是日期。如果内容不同,那么您应该运行依赖构建。鉴于我们没有提供简单内容派生(哈希等)的文件系统,它使用 last-modified-date 来执行此操作。由于这也不是 100% 可靠的 - 例如,请参阅那些日期没有足够准确度或将来可能只是的系统 - 它也将其用作信息源。如果它只是构建它,则必须对其进行修改,因此将其视为“更新”或“重建”是正确的。

【讨论】:

    【解决方案2】:

    使用规则构建了old,Make 现在认为它是依赖关系图中的最新文件。它在制作后不会检查old

    这对于虚假目标显然是正确的做法,对于文件目标通常也是正确的做法。

    【讨论】:

    • 1) 从技术上讲,在重新构建它之后进行“检查”old。如果不是 phony,Make 将不会重新构建 all。此外,您可以尝试像all: new 这样的makefile,在构建之前,newall 更新,如果 Make 通过将其修改时间修改为一个 oldernew /b> 比all,make 将不会构建all。换句话说,Make 检查它的时间(依赖关系)它的构建之后,并且如果它然后target更新,然后只有这样,才会重新构建target
    • 2) 如果您修改 Makefile,其中 Make 并没有真正改变修改时间,而是运行一些随机命令,或者可能是一个复制(并保留其模式)恰好具有的文件的命令完全相同的修改时间,则 Make 不会将 $? 扩展到 old
    • 3) 即使在上述情况下,如果您碰巧在 parallel-mode (-j) 下运行,Make 也不会扩展为 old。所以,很明显这里出了点问题。
    猜你喜欢
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 2020-04-20
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    相关资源
    最近更新 更多