Makefile GNU make中的多行定义

Makefile GNU make中的多行定义,makefile,gnu-make,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)函数之外 这是一个bug还是预期的行为?如果“泄漏”是故意的,它到底是如何工作的 p.S.GNU在Linux/x64上制作v3.81该$

我试图理解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)
函数之外

这是一个bug还是预期的行为?如果“泄漏”是故意的,它到底是如何工作的

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

$(word)
函数在空格上拆分。不是空白,而是空格

宏中没有空格,因此不会分割任何内容

1
行中添加一个尾随空格,或在
2
行中添加一个前导空格,您就可以获得预期的行为

在这里的一些快速测试中,GNU make 3.81、3.82、4.0和4.1的测试结果是一致的

您之所以看到您所称的“溢出”,是因为定义是如何展开的。它被逐字扩展,新行和所有。(想想模板扩展。)

因此make将define扩展到调用
$(word 1,…)
中,然后将结果(整个define包括换行符)扩展到配方模板中,并以它作为配方执行的两行结束

考虑这样一个宏:

define somecommands
echo foo
echo bar
echo baz
endef

all:
    $(somecommands)
你认为这里会发生什么?
全部的主体有多少行?这里有多少炮弹?执行什么命令?答案是三行、三个外壳和三个echo命令


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

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

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

  • $(A)
    变成
    1¨2
    (不知道这在浏览器上是什么样子,但我用
    ¨
    来表示换行符)
  • 现在,就make而言,
    1¨2
    是一个单词,因此
    $(单词1,1¨2)
    自然扩展为
    1¨2
    (你能看到这是怎么回事吗?)
  • 这将使用字符串
    @echo W=1¨2
    保留make。Make尽职尽责地将此命令的第一行传递给shell(不带特别要Make的
    @
    )。shell执行
    echo W=1
  • make在新shell中执行
    2
  • 第二个shell抱怨它找不到命令
    2
  • 所以,是的,是预期的行为


    [警告:上面稍微简化了一点,我忽略了make能够省略shell并在字符串中没有shell元字符时调用命令本身的位]

    我不是在问
    $(word)
    函数。我要求解释
    make:2:Command not found
    错误消息。我感兴趣的是“2”是如何/为什么出现在函数之外并进入make的执行管道的。这就是我问的问题。你问的是“部分
    $(A)
    是如何溢出$(word)函数的”。我刚刚回答了那个问题。。。虽然我现在明白了答案在我写的东西中没有得到充分解释(尽管它在那里)。等等,不。这不是一个真正的答案。这基本上是对官方(主题模糊)文件的推断,根本没有解决歧义。我开始认为这只是多行定义实现中的一个bug。例如,尝试在
    echo
    命令末尾添加分号,查看错误消息的变化。(如果在Linux下,请使用
    strace-ff-e execve
    运行,以查看其华丽之处)分号会更改错误,因为它会强制make执行shell(make认为可以时会避免)。因此,错误从
    exec
    尖叫关于
    2
    不是命令变为shell(
    /bin/sh
    ),尖叫
    2
    不是命令。是的,这是一个答案。
    A
    的值不会从对
    $(word)
    的调用中“溢出”。调用
    $(word)
    返回未修改的
    A
    的整个值。make然后将整个定义拆分为配方模板(包括换行符),然后将模板拆分为行并运行各个命令。