Makefile:由字符串模式区分的多个目录和文件的规则

Makefile: Rules for multiple directories and files differentiated by a string pattern

我在构建各种中间和输出数据文件的 RStudio 项目中有一个 Makefile 规则。一些关键规则如下所示:

outdir/<location>/outdata_<location>.file: script.R datadir/<location>/indata_<location>.file
    $(EXEC) $< <location>

其中 location 区分目录以及目标和先决条件的文件名,并且 同时作为参数传递 script.R .

例如,先决条件目录的结构如图所示:

datadir
|- location1
|  |- indata_location1.file 
|  |- ...
|
|- location2
|  |- indata_location2.file 
|  |- ...
|
|- location3

这些目录中的每一个都有不同级别的数据文件,因此决定按位置组织它们。此外,随着时间的推移会添加更多的项目位置,因此需要隐式规则来最大限度地减少不断修改 Makefile 的需要。

我已经尝试使用 GNU Make 文档中描述的模式规则,但它说模式占位符只能在目标或先决条件中出现一次。我尝试使用字符串操作和 foreach 函数,但未能解决它,因为我对 GNU Make 的经验有限。

我在多个目录上看到过类似的 SO 问题,但 none 提到使用区分字符串作为配方中的参数。

如有任何帮助,我们将不胜感激。

您想使用几个非常相似的规则,而方差对于一个模式规则来说太复杂了。这看起来像是 a "canned recipe".

的工作

我们写一个模板:

define data-rule
outdir/$(1)/outdata_$(1).file: script.R datadir/$(1)/indata_$(1).file
    $(EXEC) $$< $(1)
endef

(具体语法因不同版本的 Make 而异,因此您可能需要在 "define" 行末尾添加“=”。)

我们现在可以使用 call:

生成 location1 规则的文本
$(call data-rule,location1)

并使用 eval:

将文本解释为实际的 makefile 代码
$(eval $(call data-rule,location1))

一旦我们验证了这么多有效,我们就可以一条一条地生成规则:

$(eval $(call data-rule,location1))
$(eval $(call data-rule,location2))
$(eval $(call data-rule,location3))

或使用foreach:

LOCATIONS := location1 location2 location3
$(foreach loc,$(LOCATIONS),$(eval $(call data-rule,$(loc))))

最后,您可能需要一个构建所有这些文件的目标:

all-locations: outdir/location1/outdata_location1.file outdir/location2/outdata_location2.file outdir/location3/outdata_location3.file

您也可以自动执行此构造:

$(foreach loc,$(LOCATIONS),$(eval all-locations: outdir/$(loc)/outdata_$(loc).file))