首页 > 解决方案 > Makefile:由字符串模式区分的多个目录和文件的规则

问题描述

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

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

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

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

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

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

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

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

任何帮助,将不胜感激。

标签: rmakefilerstudio

解决方案


您想使用几个非常相似的规则,而方差对于模式规则来说太复杂了。这看起来像是一份“罐头食谱”的工作。

我们写一个模板:

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

(确切的语法因 Make 的不同版本而异,因此您可能需要在“define”行的末尾使用 '='。)

我们现在可以location1使用以下命令生成规则文本call

$(call data-rule,location1)

并让 Make 将该文本解释为实际的 makefile 代码eval

$(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))

推荐阅读