Makefile:如何为两个文件列表设置先决条件
Makefile: how to set up prerequisites for two lists of files
我有两个文件列表作为先决条件
input_i.xx
config_j.yy
我需要 运行 他们的所有组合。单个看起来像这样:
input1_config3.output: input1.xx config3.yy
run_script $^
同样在现实中,他们的名字没有编号,但我已经在 INPUTS
和 CONFIGS
中定义了他们的词干。有了它,我可以一起生成所有目标
TARGETS:=$(foreach input,$(INPUTS),$(foreach config,$(CONFIGS),$(input)_$(config).output))
但是我对先决条件有困难。看来我需要
- 获取基名
- 分裂
_
- 添加扩展名
.xx
和 .yy
.SECONDEXPANSION
$(TARGETS): $(basename $@)
run_script $^
有人可以告诉我该怎么做吗?不确定这是否是正确的方法,也许自下而上的方法更容易?
make
不太适合跟踪 M x N 矩阵的结果。根本问题是规则中不能有两个词干,所以不能说
# BROKEN
input%{X}_config%{Y}.output: input%{X}.xx config%{Y}.yy
作为一个粗略的近似值,您可以使用递归 make
规则来设置几个参数,然后从那里获取它,但这相当笨拙。
.PHONY: all
all:
$(MAKE) -$(MAKEFLAGS) X=1 Y=6 input1_config6.output
$(MAKE) -$(MAKEFLAGS) X=1 Y=7 input1_config7.output
$(MAKE) -$(MAKEFLAGS) X=2 Y=6 input2_config6.output
:
input$X_config$Y.output: input$X.xx config$Y.yy
run_script $^
如果您提供了一个完整的示例示例,其中包含一整套目标和先决条件以及您想要发生的事情,那就容易多了。
使用 .SECONDEXPANSION
可能 有效,但您没有正确使用它;请重新阅读文档。 .SECONDEXPANSION
的关键方面是您必须 转义 您想要避免扩展的变量,直到第二遍。在您的示例中,您没有逃避任何事情,因此 .SECONDEXPANSION
实际上并没有在这里做任何事情。但是,正如@tripleee 指出的那样,在单个目标中使用多个变量值并不容易。
要更轻松地执行此操作,您可能需要使用 eval
。像这样:
define DECLARE
_.output: .xx .yy
TARGETS += _.output
endef
TARGETS :=
$(foreach input,$(INPUTS),$(foreach config,$(CONFIGS),$(eval $(call DECLARE,$(input),$(config)))))
$(TARGETS):
run_script $^
我有另一个使用 include
和 bash for
循环的解决方案。
include trees.mk
trees.mk:
@for input in $(INPUTS); do \
for config in $(CONFIGS); do \
echo $${input}_$$config.output : $${input}.xx $$config.yy; \
echo -e '\t run_scipt $$^ ';\
done \
done > $@
一开始,trees.mk
不存在。双 for
循环使用文件重定向 >$@
.
将规则写入目标
我从 Managing Projects with GNU Make, Third Edition By Robert Mecklenburg 得到这个想法,
page 56
我有两个文件列表作为先决条件
input_i.xx
config_j.yy
我需要 运行 他们的所有组合。单个看起来像这样:
input1_config3.output: input1.xx config3.yy
run_script $^
同样在现实中,他们的名字没有编号,但我已经在 INPUTS
和 CONFIGS
中定义了他们的词干。有了它,我可以一起生成所有目标
TARGETS:=$(foreach input,$(INPUTS),$(foreach config,$(CONFIGS),$(input)_$(config).output))
但是我对先决条件有困难。看来我需要
- 获取基名
- 分裂
_
- 添加扩展名
.xx
和.yy
.SECONDEXPANSION
$(TARGETS): $(basename $@)
run_script $^
有人可以告诉我该怎么做吗?不确定这是否是正确的方法,也许自下而上的方法更容易?
make
不太适合跟踪 M x N 矩阵的结果。根本问题是规则中不能有两个词干,所以不能说
# BROKEN
input%{X}_config%{Y}.output: input%{X}.xx config%{Y}.yy
作为一个粗略的近似值,您可以使用递归 make
规则来设置几个参数,然后从那里获取它,但这相当笨拙。
.PHONY: all
all:
$(MAKE) -$(MAKEFLAGS) X=1 Y=6 input1_config6.output
$(MAKE) -$(MAKEFLAGS) X=1 Y=7 input1_config7.output
$(MAKE) -$(MAKEFLAGS) X=2 Y=6 input2_config6.output
:
input$X_config$Y.output: input$X.xx config$Y.yy
run_script $^
如果您提供了一个完整的示例示例,其中包含一整套目标和先决条件以及您想要发生的事情,那就容易多了。
使用 .SECONDEXPANSION
可能 有效,但您没有正确使用它;请重新阅读文档。 .SECONDEXPANSION
的关键方面是您必须 转义 您想要避免扩展的变量,直到第二遍。在您的示例中,您没有逃避任何事情,因此 .SECONDEXPANSION
实际上并没有在这里做任何事情。但是,正如@tripleee 指出的那样,在单个目标中使用多个变量值并不容易。
要更轻松地执行此操作,您可能需要使用 eval
。像这样:
define DECLARE
_.output: .xx .yy
TARGETS += _.output
endef
TARGETS :=
$(foreach input,$(INPUTS),$(foreach config,$(CONFIGS),$(eval $(call DECLARE,$(input),$(config)))))
$(TARGETS):
run_script $^
我有另一个使用 include
和 bash for
循环的解决方案。
include trees.mk
trees.mk:
@for input in $(INPUTS); do \
for config in $(CONFIGS); do \
echo $${input}_$$config.output : $${input}.xx $$config.yy; \
echo -e '\t run_scipt $$^ ';\
done \
done > $@
一开始,trees.mk
不存在。双 for
循环使用文件重定向 >$@
.
我从 Managing Projects with GNU Make, Third Edition By Robert Mecklenburg 得到这个想法, page 56