Makefile 生成多次使用变量的不同值调用另一个规则的规则

Makefile 生成多次使用变量的不同值调用另一个规则的规则,makefile,gnu-make,Makefile,Gnu Make,我有一个规则something,它对变量VAR起作用。我还有另一个规则something all,需要运行something,将VAR设置为vars中的每个值 vars = hello world something: echo $(VAR) something-all: $(foreach VAR,$(vars),something) 我知道这不太管用 noob@work:~/Desktop$ make something-all something something

我有一个规则
something
,它对变量
VAR
起作用。我还有另一个规则
something all
,需要运行
something
,将
VAR
设置为
vars
中的每个值

vars = hello world

something:
    echo $(VAR)

something-all:
    $(foreach VAR,$(vars),something)
我知道这不太管用

noob@work:~/Desktop$ make something-all
something something
make: something: No such file or directory
make: *** [something-all] Error 1
它可能会打印
hello\nworld

我曾经用通配符规则从
%
中检索
VAR
,但感觉这样做是错误的。这看起来像这样:

vars = hello world

all: $(foreach VAR,$(vars),something-$(VAR))

something-%:
    echo $*

这里有一种方法:

VARS := hello world
THINGS := $(addprefix something-, $(VARS))

allthings: $(THINGS)

something-%:
    echo $*

下面的代码应该可以解决您的问题

使用foreach(在sparc solaris 2.8和windows上的GNU Make 3.80上试用)

使用shell for loop(在GNU Make 3.80上试用,在sparc solaris 2.8上试用cc Make)


毫不奇怪

vars := hello world
something-all:
    $(foreach VAR,$(vars),something)
尝试运行
某物
。这正是
foreach
扩展到的内容,因为在第三个表达式中没有引用
VAR

您只需引用
VAR
并使用
echo
等命令即可:

vars := hello world
something-all:
    $(foreach VAR,$(vars),echo $(VAR);)

$ make
echo hello; echo world;
hello
world
请注意,用分号链接命令可以避免出现多个shell或--喘息--递归
进行
调用。没有比这更有效的了

或者,如果命令接受几个something作为参数

vars := hello world
something-all:
    echo $(foreach VAR,$(vars),$(VAR))

$ make
echo hello world
hello world

但这相当于超级简单的
echo$(vars)
。因此,跳出框框,尝试改变您的需求,使这个简单的解决方案发挥作用,这可能会有回报。

TL;DR:如果您想编程make,请放弃GNU make而选择BSD make。

这是我个人的推荐。虽然BSD Make似乎比GNU Make更为有限,因为它提供的编程工具更少,但它确实是,而且有一个独特的功能。这就是我提出GNU Make解决方案和BSD Make解决方案的原因:

用GNU制作 使用GNU Make,您可以定义一个目标。在Makefile中定义序列的规范方法是将序列的步骤作为依赖项添加到目标,如下所示:

vars= hello world

define something_t =
something: something-$(1)
something-$(1):
    @echo $(1)
endef

$(foreach _,$(vars),$(eval $(call something_t,$_)))
建议使用此组织(而不是仅定义一个目标),因为如果中断序列,您可以使用此组织使任务易于恢复。一种生成文件,其进程完全由文件系统的状态来描述。如果每个步骤都与一个文件相关联,那么任务就很容易恢复,通常是一个编译对象,但有时也是一个空文件,它被触摸以指示重要的检查点已经通过

使用辅助宏是一种灵活的解决方案,可以适应比重复名称更复杂的任务。请注意,这确实适用于最新版本的GNU Make(4.1)。在GNU Make 3.81上,应该从宏定义中删除等号

将您的示例改编为BSD Make 如果这是您的一个选择,我建议您放弃使用GNU Make,并用BSD Make替换它,也就是说:虽然GNU Make的文档非常冗长,而且有些不清楚,但BSD Make具有复杂规则集(or)的行业优势示例,并且它有一个简单且可预测的宏语言

vars= hello world

something:
.for _var in ${vars}
    echo ${_var}
.endfor
这可以演变为支持更复杂的任务,只需用适应的命令替换
echo
,或使用中间步骤即可

允许用户覆盖某些任务(也在BSD Make中) 在这个稍微高级一点的变体中,我们允许用户覆盖我们自己的方法来构建目标
something hello
something world
。 对于列表中的每个项目,如果目标
something-*
不存在,则会创建它,并将其添加到
something
的依赖项中。定义这些目标的整个操作只有在
某些内容未定义时才会发生。因此,这些宏的用户可以:

  • 覆盖
    something hello
    something world
  • 覆盖绑定到
    某物的完整过程
  • 如果我们想为Make编写有用的、可重用的宏,实现这种定制的可能性是必须的。不幸的是,这类定制很难实现


    你能详细说明一下“通配符规则”的方法吗?您可能正在描述我遇到的解决方案,但您可能没有。Thx@Beta我添加了这个。@Beta现在请看,谢谢您不想使用模式规则。你说的“规范”是什么意思?@Beta:我接受GNU高级用户使用的任何规范,比如automake,和/但仍然是人类可读的&&
    编码,最后加上
    真的
    ——这就是我经常使用的。问题是它否定了并行化。@Dummy00001阅读你的评论就像阅读自己的思想一样。:)在数字2中,您需要在make调用之后添加
    | | exit 1
    ,以便传播来自子make的错误。另请参见我对Jens回答的评论:在数字1中,除了最后一个错误外,您忽略所有错误。@Dummy00001谢谢。我已经更新了答案。由于OP没有要求,我没有将其包括在样本中;但OP可能忽略了这一点。。。。你刚才剽窃了一个问题并把它作为你自己的答案吗?OP已经有了,他问是否有更好的解决方案。不,我很确定这就是我说的我不想要的解决方案。IIRC从语法中删除=也会使它在GNU make的旧版本上工作。@hkBst我只是尝试了一下。你确实是对的!还有一点需要注意:如果使用利基软件不是问题,omake是最先进的make实用程序之一。如果我没有弄错的话,在基于Debian的系统上,BSD make作为
    bmake
    (以前是
    pmake
    )提供
    vars= hello world
    
    define something_t =
    something: something-$(1)
    something-$(1):
        @echo $(1)
    endef
    
    $(foreach _,$(vars),$(eval $(call something_t,$_)))
    
    vars= hello world
    
    something:
    .for _var in ${vars}
        echo ${_var}
    .endfor
    
    vars = hello world
    
    .if!target(depend)
    .for _var in ${vars}
    .if!target(something-${_var})
    something-${_var}:
        echo ${_var}
    .endif
    something: something-${_var}
    .endfor
    .endif