来自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"
*你能否看到,Make为并行执行($?
)以不同于非并行的方式扩展-j
的值-execution ?*
让我们首先分析第一种情况,即非并行执行。
all
和old
的修改时间为:
old
比all
“更早”。这是不言而喻的。正确?old
之后,old
变得“更老”,可以这么说通过“获取”名为older
的文件的修改时间。这基本上是shell命令的净结果:cp -p older old
。现在,不难看出,older
方式“年龄大于”all
。现在,由于其他先决条件,即:all
,Make最终构建了目标phony
。
但是,根据文档,$?
应仅扩展为“比目标更强更新的所有先决条件的名称”。这是一个完全引用。
我们是否同意,old
从不 较新而不是all
。而且,如果不是phony
,那么Make甚至不会重新构建all
。
那么,对于Make来说,将$?
扩展为old phony
会有多么错误。
phony
我明白了。但old
?真的吗?!
但是,我们现在将注意力转向并行执行,其中Make将$?
扩展为phony
。
下面:
当然,可以说,此扩展是正确的(与非并行执行中的扩展相比)。
原因是,只有phony
触发重新构建all
的文件。如果没有它,Make就不会费心去重建all
了。
然而,人们不禁要问,如何以这两种执行模式不同地扩展变量。
我甚至无法思考,这与$?
的扩展有什么关系。
总之,看起来“随机”更改(即执行模式的修改,从并行到非并行)会影响看似无关的实体,这是自动变量的扩展。为什么呢?
答案 0 :(得分:1)
make生成或更新的任何文件都已更新,因此它会隐式地假设它更新,即使您破解了使其更旧的命令。
理论上,Make应该处理文件的内容,而不是日期。如果内容不同,那么您应该运行依赖构建。鉴于我们没有文件系统提供简单的内容派生(哈希等),它使用最后修改日期来执行此操作。因为这也不是100%可靠 - 例如,参见那些日期不具备足够准确性的系统,或者将来只是的系统 - 它也会使用这是一个信息来源。如果它只是构建它,它必须被修改,因此它是正确的考虑它"更新"或者"重建"。
答案 1 :(得分:1)
使用规则构建old
后,Make现在认为它是依赖关系图中的最新文件。 在完成之后不会检查old
。
对于虚假目标来说,这显然是正确的做法,对于文件目标来说通常也是正确的事情。