您如何在构建规则中使用 (GNU) make 的 "simply expanded" 变量而不获取最后的定义?

How do you use (GNU) make's "simply expanded" variables in build rules and not get the last definition?

我需要编写一组复杂的规则来生成大量“参数化”输出文件,我认为与其手动展开它们,不如重复“包含”一个模板文件使用规则集并使用 (GNU)make 的工具允许 "simply expanded" 变量来避免痛苦。

(以前我一直在使用“递归扩展”变量的方法,所以这对我来说是新的)

作为我认为可行的一个简单示例,我尝试将以下内容放入 Makefile

Targ:=A
Param1:=Pa
Param2:=Qa
$(Targ):
    @echo expect A, get $(Targ), Target is $@. Params are $(Param1) and $(Param2) 

Targ:=B
Param1:=Pb
Param2:=Qb
$(Targ):
    @echo expect B, get $(Targ), Target is $@. Params are $(Param1) and $(Param2) 

Targ:=C
Param1:=Pc
Param2:=Qc
$(Targ):
    @echo expect C, get $(Targ), Target is $@. Params are $(Param1) and $(Param2) 

最终计划是用包含数十条不同规则的包含文件替换规则,每条规则都引用各种“参数”变量。

然而,我得到的是...

prompt> make A
expect A, get C, Target is A. Params are Pc and Qc


prompt> make B
expect B, get C, Target is B. Params are Pc and Qc

本质上,与每个规则的目标 选择预期的定义不同,$(Targ)$(Param1)$(Param2)每个规则的 command 改为 运行 与 final 定义。

有谁知道如何防止这种情况发生,即如何强制命令在 Makefile 中遇到定义时使用该定义?

这里简单与递归扩展没有区别;无论您使用哪种方式,您都会看到相同的行为。 GNU make 变量是 global 并且显然只能有一个值。

你得明白什么时候展开变量。该文档对此提供了 detailed description。目标和先决条件在 读入 makefile 时 被扩展,因此在解析 makefile 时使用 Targ 的值。

配方被展开当配方被调用时,直到所有 makefile 被解析并且 make 开始构建目标之后。那时当然变量 Targ 有它的最后一个设定值。

在不知道您的 makefile 真正做什么的情况下,很难提出替代方案。一种选择是使用 target-specific 变量:

Targ := A
$(Targ): LocalTarg := $(Targ)
$(Targ):
        @echo expect A, get $(LocalTarg), Target is $@

另一种选择是使用构造变量名:

Targ := A
Targ_$(Targ) := $(Targ)
$(Targ):
        @echo expect A, get $(Targ_$@), Target is $@

很抱歉回答我自己的问题,但我现在意识到可以通过 运行 递归地解决我遇到的问题。

例如如果规则的参数变量是 Targ、Param1 和 Param2,则

#Set up "default" values for the parameters (As @madscientist points out, 
#these will safely be overridden by the defs on the @(make) commands below

Targ=XXXXXXXXXX
Param=XXXXXXXXXX
Param2=XXXXXXXXXX
Recursing=

#
# define N (==3) templated rule(s)
#
$(Targ)%a:
    @echo Run Combo_a $(Targ) $(Param1) $(Param2) $@

$(Targ)%b:
    @echo Run Combo_b $(Targ) $(Param2) $(Param1) reversed $@

$(Targ)%c:
    @echo Run Combo_c  $(Param1) $(Targ) $(Param2) mixed again $@

#
#Enumerate "M" (==2) sets of parameters, 
# (Except if we are already recursing because unrecognised targets may cause
# it to descend forever)
#
ifneq ($(Recursing), Yes)
Set1%:
    @$(MAKE) Targ=Set1 Param1=foo Param2=bar Recursing=Yes $@

Set2%:
    @$(MAKE) Targ=Set2 Param1=ray Param2=tracing Recursing=Yes $@
endif

然后这允许 N*M 种不同的组合,用于 N+M 的打字成本。 例如。 (从 make re 递归中删除消息)

>make Set1.a
Run Combo_a Set1 foo bar Set1.a

>make Set2.c
Run Combo_c ray Set2 tracing mixed again Set2.c