关于 force targets 的 Makefile 文档说明如下:
如果规则没有先决条件或配方,并且规则的目标 是一个不存在的文件,然后 make 想象这个目标已经 每当运行其规则时更新。这意味着所有目标 取决于这个,他们的食谱总是会运行。
我对上述声明的解释是,规则的目标必须是一个不存在的文件,目标才能成为强制目标。因此,我不认为力目标是下面示例中发生的事情,但我很高兴得知相反的证据。
考虑以下 Makefile:
.PHONY: update-db-type
.DEFAULT: run-only-if-env-var-updated
ifeq ("$(shell echo $$DB_TYPE)","mysql")
DB_TYPE := mysql
else
DB_TYPE := tidb
endif
run-only-if-env-var-updated: db_type
echo "Do an expensive operation"
sleep 1
touch $@
# Note that db_type is a real file.
db_type: update-db-type
update-db-type:
echo "DB_TYPE: $(DB_TYPE)"
ifneq ("$(shell cat db_type)","$(DB_TYPE)")
echo "$(DB_TYPE)" > db_type
endif
现在考虑以下命令及其输出:
echo mysql > db_type
DB_TYPE=mysql make
# Output
# echo "DB_TYPE: mysql"
# DB_TYPE: mysql
# echo "Do an expensive operation"
# Do an expensive operation
# sleep 1
# touch run-only-if-env-var-updated
DB_TYPE=tidb make
# Output
# echo "DB_TYPE: tidb"
# DB_TYPE: tidb
# echo "tidb" > db_type
DB_TYPE=tidb make
# echo "DB_TYPE: tidb"
# DB_TYPE: tidb
# echo "Do an expensive operation"
# Do an expensive operation
# sleep 1
# touch run-only-if-env-var-updated
观察到昂贵的操作
run-only-if-env-var-updated
仅在second调用DB_TYPE=tidb make
时运行。
这意味着,在第一次调用中,Make 没有观察到文件
db_type
的时间戳已更新,并且比文件run-only-if-env-var-updated
更新。
请注意,这不是我期望的行为;我的心智模型是 Make 总是会将依赖项的时间戳与目标的时间戳进行比较,以确定目标是否需要运行。
现在,如果我们对 Makefile 做一个小的修改,通过给目标
db_type
一个非空的配方,如下所示,然后我们得到在第一次调用 DB_TYPE=tidb make
时运行昂贵操作的预期行为。
db_type: update-db-type
echo "Running DB_TYPE"
第一个示例中的行为(没有额外的
echo
)是Make的预期行为吗?
如果是这样,是否有文档解释为什么在第一次执行时忽略更新的时间戳?