为什么我不能在 GNU make 'define' 指令中创建变量

Why can I not create variables in a GNU make 'define' directive

我正在尝试构建 GNU Make Canned Recipe,像这样:

define this-will-fail
my_var=1
$(info your variable is $(my_var))
endef

$(this-will-fail)

这会导致错误 *** missing separator. Stop.

但是,以下内容按预期工作:

define why-does-this-work
$(eval my_var=1)
$(info your variable is $(my_var))
endef

$(why-does-this-work)

通过打印 your variable is 1

我正在查看 AOSP's build system,经常看到 evaldefine 配对使用。这两项有什么关系,为什么我在使用define时不能创建变量"normally"?

答案源于一个简单的观点,但有很大的影响 - 一个 makefile 有两种方言,1) make 语言本身和 2) 你用于调用 gcc 之类的东西的 shell 语言。

正常 make "rule" 语法的提示:

targets : prerequisites
        recipe

虽然 make 目标和先决条件在 make 中 语法,食谱中的东西是 in the shell syntax,而不是 make syntax.

这解释了为什么您不能像这样将 make 变量赋值作为配方的一部分:

all: the_dependencies_of_all
    this_will_not_work := because_the_shell_does_not_know_what_this_line_means

在 shell 语法位中,make 进行了三个特殊的文本操作,然后将剩余的字符串逐字传递给 shell。这三个步骤是

  1. 处理转义的换行符(例如反斜杠后跟换行符)
  2. 运行 任何 make 函数(如 $(filter ....)$(eval ..)
  3. 扩展任何 make 目标变量(如 $@

在正常情况下,这个 3-steps-then-shell 过程在每个配方行发生一次,所以你的 makefile 配方的每一行都是 运行 在不同的 shell (因此为什么有些调用 make 会产生许多 /bin/sh sub-processes).

上面的操作 #2 解释了为什么可以在配方中使用 eval 来向配方中添加一些 make 语法。 Eval 将变成一个空字符串,这不会导致 shell 出现问题,但是 make 会在您的语句中计算字符串,因此可以进行变量定义之类的操作。

这个评估发生的精确时刻有点难以确定 - 它似乎发生在变量第一次展开时,这本身取决于您在 makefile 中引用该变量的位置。也许有人可以更清楚地说明这一点,因为当这种情况发生时,使用 -j 标志对 运行 多个并行的配方行的调用产生了后果

更多信息: