【问题标题】:How do environment variables and macros interact in GNU Make?环境变量和宏在 GNU Make 中如何交互?
【发布时间】:2021-08-17 23:50:22
【问题描述】:

在 GNU Makefiles 中,环境变量和参数/变量/宏之间经常存在交互。还有几种不同的赋值运算符,有可以在命令行上提供的“覆盖”变量,还有一个override 指令。

这些交互的优先规则是什么?

考虑这个 Makefile:

# Use := to avoid infinite recursion of macro expansion
CFLAGS := -g -O2 $(CFLAGS)
hello: src/hello.c
    cc $(CFLAGS) -o $@ $<

如果你调用CFLAGS=-pipe make hello,你会得到cc -g -O2 -pipe -o hello src/hello.c。如果你调用make CFLAGS=-pipe hello,你会得到cc -pipe -o hello src/hello.c。有什么区别?

如果您将 Makefile 更改为:

CFLAGS ?= -g -O2 $(CFLAGS)
hello: src/hello.c
    cc $(CFLAGS) -o $@ $<

在这两种情况下你都会得到cc -pipe -o hello src/hello.c

【问题讨论】:

  • 也许更好的标题应该是“Makefile 变量何时从环境、命令行或 Makefile 本身获取它们的值?”。此外,make 的另一个流行标签是 Makefile

标签: environment-variables gnu-make


【解决方案1】:

此答案基于 https://stackoverflow.com/a/63187052/2954547 以及 GNU Make manual 的 cmets 中的信息。

优先级是,按照从强到弱的顺序,是:

  1. override 指令
  2. 命令行覆盖
  3. =, :=
  4. 环境变量
  5. ?=

有几个单独的规则相互作用以创建此优先级:

  • 为每个环境变量创建一个宏。如果例如设置了HOME,就会有一个$(HOME)宏。

  • 如果已经定义了宏,=:= 会覆盖之前的宏定义。这包括环境变量,它们(概念上)在解释 Makefile 的其余部分之前创建。所以=:= 会覆盖一个环境变量。但是如果定义了环境变量,它仍然可以在赋值的右侧被引用:

    CFLAGS := -g -O2 $(CFLAGS)
    

    请注意,在这种情况下您必须使用:=,因为如果您使用=,您会得到一个宏,它会尝试在运行时以递归方式永远地扩展自身。

  • 根据section 6.5 of the manualVAR ?= val相当于:

    ifeq ($(origin VARIABLE), undefined)
      VAR = val
    endif
    

    环境变量的origin 设置为'environment',因此?= 将始终被环境变量覆盖。与=:= 不同的是,如果设置了环境变量,则其与?= 对应的赋值将永远不会被调用。

  • 命令行“覆盖变量”覆盖所有变量。这意味着make VAR=val 会覆盖环境变量VAR,以及VAR = valVAR := valVAR ?= val 的赋值。

  • override 指令覆盖所有内容,包括命令行覆盖。

请注意,GNU Make 具有-e/--environment-overrides 选项,它会导致环境变量覆盖=:=。这导致它们在宏定义方面的行为与命令行覆盖变量相同,但(我认为)后者仍将优先。

【讨论】:

  • 我会提到“宏”和“变量”在这里可以互换使用。 2. 我将添加一个对override 指令的文档引用,并为“命令行覆盖”定义或添加一个引用。不是每个人都知道“命令行覆盖”是指“在make 命令行中设置的变量”。
  • 在“命令行“覆盖变量”覆盖所有变量”中,我相信,你的意思是“......覆盖所有分配,override 除外”。另外,添加对override 的文档引用。
  • 也是?=,不是=?
猜你喜欢
  • 2016-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-26
  • 1970-01-01
  • 2014-04-09
相关资源
最近更新 更多