在makefile中订购

时间:2015-02-04 12:43:01

标签: makefile gnu-make

我有两个目标foobar。既不依赖于另一个,但如果必须重建bar,则必须在foo之前完成。它们是gnu-make所谓的虚假目标,它们的规则总是在指定时执行。

目前,我们表达了一个主要目标,它依赖于这两个:

# user level targets
all: bar
        @$(MAKE) foo
        @echo all

alt: foo
        @echo alt

# internal targets
foo:
        @echo foo

bar: qux
        @echo bar

qux:
        @echo qux
        @touch qux

我们有必要的行为:如果qux不是最新的:make bar输出qux bar foo all(按此顺序)和make alt输出foo alt;如果qux是最新的,make bar输出bar foo allmake alt输出foo alt

这越来越不舒服,因为foo必须专门处理(所有依赖于两者的目标必须以这种方式处理,foo不能放在描述依赖关系的变量中bar也存在,submake本身就是一个问题,必须维护命令行以传递其他变量)。我们现在有另一个目标必须以同样的方式处理,我正在寻找其他更方便的方法来处理结构。


注1:在实践中,我目前只使用gnu-make,但是对POSIX上的gnu-make扩展唯一已知的依赖是包含文件的可能性(可以广泛使用)。我更喜欢保持当前状态的东西(即广泛支持的构造),但如果不可能,只使用gnu-make扩展是可以接受的。


注2:gnu-make有一个 order-only-prerequisites 的概念,但它显然没有提供我们需要的东西。与

# user level targets
all: bar foo 
        @echo all

alt: foo
        @echo alt

# internal targets
foo: | bar
        @echo foo

bar:
        @echo bar

make alt也构建bar(如果文件bar存在,其日期不会影响重建foo的决定,这是记录的行为)


注3:我想的越多,我认为在不使用递归调用的情况下使用make解决此问题的可能性就越小。在我看来,它需要依赖图上的两个传递,一个用于确定必须构建的内容,一个用于确定排序,而我在make行为中不知道任何事情都无法完成传递算法。

1 个答案:

答案 0 :(得分:1)

嗯,这个黑客怎么样(对于黑客来说无疑是: - ))。

基本上,您可以运行make -d -n加上命令参数。输出将包含多行,如Must remake target 'clean'。此信息会告诉您此次 make 是否会尝试同时构建foo bar。如果情况确实如此,只需添加一条规则即可实现所需的序列化。

草图:

this := $(lastword ${MAKEFILE_LIST})

ifndef DONTRECURSE
  targets-that-will-get-remade := $(patsubst %',%,$(shell ${MAKE} -f ${this} ${MAKECMDGOALS} --debug=b -n DONTRECURSE=nosiree | grep -Po "Must remake target '\K.*'"))
endif

ifeq (bar foo,$(sort $(filter bar foo,${targets-that-will-get-remade})))
foo: bar
endif

.PHONY: foo bar
foo bar:
    sleep 3
    : $@

所以,你运行 make DONTRECURSE未设置,因此$(shell …)运行。它使用相同的makefile和目标第二次运行 make ,但添加了-d(调试)和-n(实际上不运行配方)标志。 DONTRECURSE设置为阻止 make 的第三个副本运行。

扩展所有这一系列make的目标列表将尝试在此次运行中构建。 (提取目标名称非常烦人 - 可能有一种更清洁的方式。)

如果此目标列表同时包含foobar,则只需添加foo: bar依赖项。任务完成。使用sleep 3(例如)时,-j4行显示此序列化正常工作。