我知道以前有人问过这个问题,但我找到的解决方案都不适合我,因为它们是反 DRY 的。
我有许多目标依赖于不容易添加时间戳的东西 - 例如从另一个系统复制的文件。我希望能够做的是列出变量中的依赖关系,例如nobuild=this,that
,并假定这些目标是最新的。 由于我有很多这样的,我不想ifdef
每一个;伪编码可取的是类似的东西
ignorable-target: dependencies
$(call ifnobuild,$@)
.. rest of normal build steps ..
如果nobuild
变量中提到了ignorable-target
,则ifnobuild
宏扩展到某种成功的gmake
指令退出此配方。
我也不想进入多行连续的shell 命令,以便将条件推迟到配方本身;我希望能够告诉 make "假设这些目标是最新的,不要试图构建它们",这样我就可以用已经从有问题的配方中获得的本地副本来测试其他方面。
gmake
中没有任何退出配方的成功机制,是吗?
[编辑希望使情况更加清晰。
下面是一个示例。 目标remote1
和remote2
都涉及使用ssh
在远程系统上执行一些耗时的操作,然后在本地复制结果。 目标local1
是在本地构建的,不是时间接收器。target-under-work
取决于上述所有三个。
local1: local1.c Makefile
remote1: local1
scp local1 remote-host:/tmp/
ssh remote-host /tmp/local1 some-args # takes a long time
scp remote-host:/tmp/local1.out remote1
remote2: local1
scp local1 other-host:/tmp/
ssh other-host /tmp/local1 other-args # takes a long time
scp other-host:/tmp/local1.out remote2
target-under-work: local1 remote1 remote2
do-something-with remote1,remote2
现在,当我运行make target-under-work
时,它将运行remote1
和remote2
的配方。 但是,这些文件的本地副本对于我的测试来说"足够好",所以我不希望它们每次都运行。 一旦投入生产,它们每次都会运行,但是当我开发target-under-work
时,我只想使用已经构建的副本,我可以每天(或其他方式(重建它们以获得必要的测试粒度。
以上过于简化;有多个步骤和目标取决于remote1
和/或remote2
。 我看到了如何通过使它们成为仅订单先决条件来获得我想要的效果——但这意味着更改将它们作为先决条件的每个目标的依赖项列表,而不是对remote1
和remote2
进行单一更改,以便我可以使用命令行中的一些变量来告诉他们的配方'假装这已经构建好了, 如果已经有副本,则不要实际构建它。
我希望这使我的问题更加清晰。
不,此早期退出功能不存在。
请注意,您的问题可能未充分指定,因为您没有解释当慢速目标尚不存在时您想要的行为。
让我们假设nobuild
中列出的慢速目标在且仅当它们不存在时,才应重建它们。与其使用 make 函数提前退出他们的配方,不如使用 make 函数来"隐藏"他们的先决条件列表。这样,如果它们已经存在,即使它们已经过时,也不会重建。唯一的微妙之处是,您将需要第二个扩展才能使用先决条件列表中的$@
自动变量。在以下示例中,slow
(您的remoteX
(取决于fast1
(您的local1
(。fast2
(您的target-under-work
(取决于fast1
和slow
:
host> cat Makefile
# Expands as empty string if $(1) exists and
# listed in $(nobuild). Else expands as $(2).
# $(1): target
# $(2): prerequisites
define HIDE_IF_NOBUILD
$(if $(wildcard $(1)),$(if $(filter $(1),$(nobuild)),,$(2)),$(2))
endef
nobuild :=
fast1:
@echo 'build $@'
@touch $@
fast2: fast1 slow
@echo 'build $@'
@touch $@
.SECONDEXPANSION:
slow: $$(call HIDE_IF_NOBUILD,$$@,fast1)
@echo 'build $@'
@touch $@
# Case 1: slow target not listed in nobuild and not existing
host> rm -f slow; touch fast1; make fast2
build slow
build fast2
# Case 2: slow target not listed in nobuild and existing and outdated
host> touch slow; sleep 2; touch fast1; make fast2
build slow
build fast2
# Case 3: slow target listed in nobuild and not existing
host> rm -f slow; touch fast1; make nobuild="slow" fast2
build slow
build fast2
# Case 4: slow target listed in nobuild and existing and outdated
host> touch slow; sleep 2; touch fast1; make nobuild="slow" fast2
build fast2