配方中变量的早期扩展

时间:2019-01-21 11:28:11

标签: gnu-make variable-expansion

我知道GNU Make中两种变量之间的区别。

我目前正在编写一个构建系统,其中在子目录(例如VERSION)中定义了某些变量。为了简化子目录作者的工作,我不想强​​迫他们使变量在全局范围内唯一。我也想避免递归。

我的问题是,现在我需要一种方法来提供一些简单的库目标,以在定义目标时扩展这些公共变量。举一个简单的例子:

FOO := Bar
PHONY: $(FOO)
$(FOO):
    @echo $(FOO)

FOO := Definitely not Bar

PHONY: test2
test2: Bar
    @echo $(FOO)

我需要make test2的输出为

Bar
Definitely not Bar

我当然可以在第一个规则中使用临时变量强制FOO扩展,但是随后我需要一种可靠地定义新临时变量的方法。有没有办法扩大目标,例如使用eval?

编辑:在示例代码中使FOO的奇怪扩展更加清楚。

2 个答案:

答案 0 :(得分:1)

似乎您只是想target-specific variables, 例如

制作文件

.PHONY: Bar test2

Bar: FOO := Bar
Bar:
    @echo $(FOO)

test2: FOO := Definitely not Bar
test2: Bar
    @echo $(FOO)

运行方式:

$ make test2
Bar
Definitely not Bar

(请注意,.PHONY和所有特殊目标一样,都以.开头)

答案 1 :(得分:0)

您可以使用$(eval …)编写一些功能良好的代码(用于双关语)。您可以编写闭包,并决定什么时候展开。

考虑此变量:

define rule =
PHONY: ${FOO}
${FOO}:
        @echo $$@ ${FOO}
endef

这里没什么奇怪的。但是看看将其传递给 eval

会发生什么?
FOO := Bar
$(eval ${rule})

我们最好详细看看最后一行。

  • make 展开$(eval ${rule})
    • 首先,它会扩展${rule}
      • $$扩展为$
      • 所有出现的${FOO} Bar
      • 取代
      • 把这段文字留给我们:
        PHONY: Bar
        Bar:
        @echo $@ Bar
        您能看到${FOO}当前值如何烘焙到配方中吗?
    • 现在将 make 语法块传递给$(eval)
      • 制作创建新规则,作为 eval
      • 的副作用
    • eval 的扩展名是空的。

很好。

FOO := Dead
$(eval ${rule})

FOO := Beef
$(eval ${rule})

避开全局变量而使用局部参数并不是很遥远:

$(call makerule,Dead)
$(call makerule,Beef)

一定是件好事,不是吗?

[AFAICR eval make 3.81中效果不佳,因此请至少使用版本3.82]