Makefile:仅在执行其他规则时始终执行的规则

时间:2018-02-15 20:01:53

标签: makefile

我有这个:

.PHONY: all shared_setup
all: foo bar

shared_setup:
    # do some stuff that always needs to be done if 'foo' or 'bar' run
    # but shouldn't be done if neither 'foo' nor 'bar' run

foo: shared_setup some_other_foo_prerequisite
    # do something that depends on shared_setup
    touch foo

bar: shared_setup some_other_bar_prerequisite
    # do something else that depends on shared_setup
    touch bar

当我运行make all时,如果shared_setupfoo被执行,我希望始终执行bar,但不要导致foo或{{ 1}}被认为已过时。另请注意,如果barshared_setupd都没有运行,foo就不会运行。

1 个答案:

答案 0 :(得分:1)

您可以shared_setup foobar {em} order-only prerequisite (而不是正常先决条件) (注意|符号):

shared_setup:
    # do some stuff that always needs to be done if 'foo' or 'bar' run
    # but shouldn't be done if neither 'foo' nor 'bar' run

foo: some_other_foo_prerequisite | shared_setup
    # do something that depends on shared_setup
    touch foo

bar: some_other_bar_prerequisite | shared_setup
    # do something else that depends on shared_setup
    touch bar

这样,执行规则shared_setup将导致foobar都不会过时。

作为每次“阻止”shared_setup执行的解决方法,您可以创建(非private target-specific variable {{1} }。让我们考虑一下must-run-shared-setup目标:

foo

自动变量foo: must-run-shared-setup := $(filter $|, $?) foo: some_other_foo_prerequisite | shared_setup .... 包含比目标{{1}更新的所有先决条件(无论是正常还是仅订单)的名称},$?包含所有foo仅限订单的先决条件的名称(即:仅{,1 {}} $|

由于我们将foo设置为从shared_setup过滤foo的内容的结果,如果must-run-shared-setup $|变量将为非空必须更新,否则为空。

这样,根据此变量$?的内容(即:实际上是否为空),可以有条件地决定内部must-run-shared-setup的配方是否做某事。

您可以类似地执行foo目标。

更简单的解决方案

这个解决方案意味着改变你的设计,但对我来说似乎更简单。它包含使用空文件shared_setup作为简单时间戳,以便must-run-shared-setup可以确定是否应该运行它。

您可以从虚假目标列表中删除bar。然后,将其添加为shared_targetmake的仅订单先决条件。 shared_setup应具有foobar的所有其他先决条件,其配方应将其创建为空文件。

shared_setup

如果由于任何先决条件发生变化而必须更新foobar,则必须.PHONY: all all: foo bar shared_setup: some_other_foo_prerequisite some_other_bar_prerequisite # do some stuff that always needs to be done if 'foo' or 'bar' run # but shouldn't be done if neither 'foo' nor 'bar' run touch shared_setup foo: some_other_foo_prerequisite | shared_setup # do something that depends on shared_setup touch foo bar: some_other_bar_prerequisite | shared_setup # do something else that depends on shared_setup touch bar 。如果foobar都不需要更新,则shared_setup也不需要更新,因为目标foo已经存在,而且它们的先决条件并不新。