GNU make中的多行定义

时间:2015-04-22 16:44:05

标签: makefile 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)函数。

这是一个错误还是预期的行为?如果“泄漏”是故意的,它是如何运作的?

P.S。 GNU在Linux / x64上制作v3.81

2 个答案:

答案 0 :(得分:4)

这里要记住的是 make 将每个食谱存储为一个递归变量。在 make 确定它必须运行您的配方时,它会扩展该变量。 生成然后将生成的扩展中的每个行传递给一个单独的shell,如果这些shell执行中的任何一个返回错误,则停止。

在您的示例中,在运行任何内容之前 make 展开@echo W=$(word 1,$(A))

  1. $(A)变为1¶2(不知道您的浏览器上的内容是什么,但我使用来表示换行符)
  2. 现在,就{em> make 而言,1¶2只是一个单词,因此$(word 1,1¶2)自然会扩展为1¶2(你能看到它的发展方向吗?了吗?)
  3. 这会使 make 包含字符串@echo W=1¶2。尽职尽责地将第一行传递给shell(没有@,因为 make 是特殊的。 shell执行echo W=1
  4. make new shell中执行2
  5. 第二个shell抱怨它无法找到命令2
  6. 所以,是的,预期的行为。

    [警告:上面略微简化,我掩饰了 make 能够忽略shell的位,如果字符串中没有shell元字符,则调用命令本身)

答案 1 :(得分:2)

$(word)函数在空格上分割。不是空格,空格。

您的A宏中没有空格,因此无法分割。

1行或2行的前导空格处添加尾随空格,即可获得预期的行为。

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

您在调用它时看到“溢出”的原因是因为定义的扩展方式。它按字面意思,换行符和所有内容进行扩展。 (想想模板扩展。)

因此make将define扩展为对$(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作为输出而不是预期的(并且更有用)foo,{{ 1}}和bar在三个不同的行上。