【问题标题】:Why can I not create variables in a GNU make 'define' directive为什么我不能在 GNU make 'define' 指令中创建变量
【发布时间】:2017-06-20 04:13:18
【问题描述】:

我正在尝试构建一个 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时不能“正常”创建变量?

【问题讨论】:

  • 您链接到的罐头食谱文档谈论的是 shell sn-ps,而不是 Make (事实上,Make 上下文中的“recipe”一词始终意味着“规则的外壳代码部分”)。
  • @MichaelLivshin 谢谢,这是我消除所有困惑所需的花絮。如果您想将其发布为“答案”,我很乐意接受

标签: android makefile gnu-make recipe


【解决方案1】:

答案源于一个具有重大影响的简单点——makefile 有两种方言,1) make 语言本身和 2) 用于调用 gcc 之类的 shell 语言。

提醒一下正常的make“规则”语法:

targets : prerequisites
        recipe

当 make 目标和先决条件在 make 中时 语法,配方中的内容是 在 shell 语法中,而不是 make 语法

这解释了为什么您不能将诸如将 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 的一些调用会产生许多 @987654331 @子进程)。

上面的操作 #2 解释了为什么您可以在配方中使用 eval 来为您的配方添加一些 make 语法。 eval 将变成一个空字符串,这不会对 shell 造成任何问题,但是 make 会在你的语句中评估字符串,所以像变量定义这样的东西是可能的。

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

更多信息:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多