Makefile:如何为两个文件列表设置先决条件

Makefile: how to set up prerequisites for two lists of files

我有两个文件列表作为先决条件

我需要 运行 他们的所有组合。单个看起来像这样:

input1_config3.output: input1.xx config3.yy
    run_script $^

同样在现实中,他们的名字没有编号,但我已经在 INPUTSCONFIGS 中定义了他们的词干。有了它,我可以一起生成所有目标

TARGETS:=$(foreach input,$(INPUTS),$(foreach config,$(CONFIGS),$(input)_$(config).output))

但是我对先决条件有困难。看来我需要

  1. 获取基名
  2. 分裂 _
  3. 添加扩展名 .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