食谱中变量的早期扩展

Early Expansion of Variables in Recipes

我知道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,但是我需要一种方法来可靠地定义一个新的临时变量。有没有办法扩大目标,例如使用评估?

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

看起来你只是想要 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 与所有特殊目标一样,以 . 开头)

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

考虑这个变量:

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

没什么奇怪的。但是看看当我们将它传递给 eval:

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

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

  • 使扩展$(eval ${rule})
    • 首先扩展${rule}
      • $$ 扩展为 $
      • ${FOO} 的所有 次出现都被替换为 Bar
      • 给我们留下这段文字:
        PHONY: Bar
        Bar:
        </code> <code> </code> <code>@echo $@ Bar
        你能看出 ${FOO} 的当前值是如何被烘焙到配方中的吗?
    • 现在 make 语法块被传递给 $(eval)
      • Make 创建新规则作为 eval
      • 的副作用
    • eval 的扩展虽然是空的。

不错。

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

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

您离避免使用全局变量而使用局部参数不远了:

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

一定是件好事,不是吗?

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