GNU make 中的多行定义

Multi-line define in GNU make

我试图理解 GNU make 的多行 define 指令,但我做不到。示例:

define A
1
2
endef
all:
    @echo W=$(word 1,$(A))

运行 make 产生了我最不期望的结果:

W=1
make: 2: Command not found
make: *** [all] Error 127

$(A) 的一部分似乎溢出了 $(word) 函数。

这是错误还是预期的行为?如果 "spill" 是故意的,那么它是如何起作用的?

P.S。 GNU 在 Linux/x64

上制作 v3.81

$(word) 函数正在 space 上拆分。不白space,spaces.

您的 A 宏中没有 space,因此不会拆分任何内容。

1 行上添加尾随 space 或在 2 行上添加前导 space 即可获得预期的行为。

在此处的一些快速测试中,这在 GNU make 3.81、3.82、4.0 和 4.1 中是一致的。

您看到 "spill" 的原因是因为定义的扩展方式。它从字面上扩展,换行和所有。 (想想模板扩展。)

因此 make 将定义扩展到对 $(word 1,...) 的调用中,然后将该结果(包括换行符的整个定义)扩展到配方模板中,最后以两行作为配方执行。

考虑这样的宏:

define somecommands
echo foo
echo bar
echo baz
endef

all:
    $(somecommands)

您希望这里发生什么? all 的正文有多少行? 运行这里有多少炮弹?执行什么命令?答案是三行,三个 shell 和三个 echo 命令。

如果不计算换行符,那么您将在一个命令中有效地 运行 echo foo echo bar echo baz 并获得 foo echo bar echo baz 作为输出而不是预期的(并且更有用) foobarbaz 在三个不同的行上。

这里要记住的是 make 将每个配方存储为单个递归变量。当 make 决定它必须 运行 您的食谱时,它会扩展该变量。 Make 然后将结果扩展中的 each 行传递到单独的 shell,如果其中任何 shell 执行 return一个错误。

在您的示例中,在 运行ning 之前 make 扩展 @echo W=$(word 1,$(A)).

  1. $(A) 变为 1¶2(不知道这在您的浏览器上是什么样子,但我使用 表示换行符)
  2. 现在,就 make 而言,1¶2 是一个单词,所以 $(word 1,1¶2) 自然扩展为 1¶2(你能看到这是怎么回事了吗?)
  3. 这使得 make 带有字符串 @echo W=1¶2。 Make 尽职尽责地将其第一行传递给 shell(没有 @,因为它对 make 是特殊的)。 shell 执行 echo W=1.
  4. makenew shell.
  5. 中执行 2
  6. 第二个shell抱怨找不到命令2

所以,是的,预期的行为。

[警告:在上面略作简化,我忽略了 make 能够省略 shell 并在字符串具有的情况下调用命令本身的位其中没有 shell 个元字符]