本文介绍了在GNU make中,环境变量和宏是如何交互的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

考虑这个生成文件:

# 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。有什么不同?

如果将生成文件更改为:

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

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

推荐答案

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

优先顺序为:从强到弱:

  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选项,它会导致环境变量覆盖=:=。这使得它们在宏定义方面的行为与命令行覆盖变量相同,但(我认为)后者仍将优先。

这篇关于在GNU make中,环境变量和宏是如何交互的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-31 03:13