891

任何人都可以清楚地解释变量赋值在 Makefile 中是如何工作的。

和有什么区别:

 VARIABLE = value
 VARIABLE ?= value
 VARIABLE := value
 VARIABLE += value

我已经阅读了GNU Make 手册中的部分,但对我来说仍然没有意义。

4

6 回答 6

1165

懒人集

VARIABLE = value

一个变量的正常设置,但在该value字段中提到的任何其他变量都在使用该变量时使用它们的值递归扩展,而不是它在声明时的值

立即设置

VARIABLE := value

通过内部值的简单扩展来设置变量 - 其中的值在声明时扩展。

不存在时的惰性设置

VARIABLE ?= value

仅当变量没有值时才设置变量。value总是在VARIABLE被访问时评估。它相当于

ifeq ($(origin VARIABLE), undefined)
  VARIABLE = value
endif

有关更多详细信息,请参阅文档

附加

VARIABLE += value

将提供的值附加到现有值(如果变量不存在,则设置为该值)

于 2009-01-15T23:25:35.207 回答
307

使用=导致变量被赋值。如果变量已经有值,则将其替换。该值在使用时会被扩展。例如:

HELLO = world
HELLO_WORLD = $(HELLO) world!

# This echoes "world world!"
echo $(HELLO_WORLD)

HELLO = hello

# This echoes "hello world!"
echo $(HELLO_WORLD)

使用:=类似于使用=。但是,不是在使用时扩展值,而是在赋值期间扩展它。例如:

HELLO = world
HELLO_WORLD := $(HELLO) world!

# This echoes "world world!"
echo $(HELLO_WORLD)

HELLO = hello

# Still echoes "world world!"
echo $(HELLO_WORLD)

HELLO_WORLD := $(HELLO) world!

# This echoes "hello world!"
echo $(HELLO_WORLD)

如果之前未分配变量,则使用?=为变量分配一个值。如果变量之前被分配了一个空白值 ( ),我认为它仍然被认为是 set 。否则,功能与.VAR==

using+=类似于 using =,但不是替换值,而是将值附加到当前值,中间有一个空格。如果该变量以前是用 设置的,我认为:=它会被扩展。结果值在使用时会扩展我认为。例如:

HELLO_WORLD = hello
HELLO_WORLD += world!

# This echoes "hello world!"
echo $(HELLO_WORLD)

如果HELLO_WORLD = $(HELLO_WORLD) world!使用了类似的东西,就会产生递归,这很可能会结束你的 Makefile 的执行。如果A := $(A) $(B)使用了,结果将与使用不完全相同,+=因为用而B展开,:=+=不会导致B展开。

于 2009-01-15T23:34:46.093 回答
76

我建议你用“make”做一些实验。=这是一个简单的演示,显示和之间的区别:=

/* Filename: Makefile*/
x := foo
y := $(x) bar
x := later

a = foo
b = $(a) bar
a = later

test:
    @echo x - $(x)
    @echo y - $(y)
    @echo a - $(a)
    @echo b - $(b)

make test印刷:

x - later
y - foo bar
a - later
b - later bar

在此处查看更详细的说明

于 2012-12-23T14:43:59.037 回答
34

使用时VARIABLE = value,如果value实际上是对另一个变量的引用,那么只有在使用时才确定值VARIABLE。最好用一个例子来说明这一点:

VAL = foo
VARIABLE = $(VAL)
VAL = bar

# VARIABLE and VAL will both evaluate to "bar"

当你使用时VARIABLE := value,你会得到value 现在的价值。例如:

VAL = foo
VARIABLE := $(VAL)
VAL = bar

# VAL will evaluate to "bar", but VARIABLE will evaluate to "foo"

使用VARIABLE ?= val意味着您只设置VARIABLE if VARIABLE的值尚未设置。如果尚未设置,则将值的设置推迟到VARIABLE使用时(如示例 1 所示)。

VARIABLE += value只是附加valueVARIABLE. 的实际值value是按照最初设置时的值确定的,使用=:=

于 2009-01-15T23:26:15.410 回答
10

在上述答案中,重要的是要了解“值在声明/使用时扩展”的含义。给出类似的值*.c并不需要任何扩展。只有当命令使用此字符串时,它才会触发一些通配符。类似地,一个类似$(wildcard *.c)or的值$(shell ls *.c)不需要任何扩展,并且在定义时被完全评估,即使我们:=在变量定义中使用。

在您有一些 C 文件的目录中尝试以下 Makefile:

VAR1 = *.c
VAR2 := *.c
VAR3 = $(wildcard *.c)
VAR4 := $(wildcard *.c)
VAR5 = $(shell ls *.c)
VAR6 := $(shell ls *.c)

all :
    touch foo.c
    @echo "now VAR1 = \"$(VAR1)\"" ; ls $(VAR1)
    @echo "now VAR2 = \"$(VAR2)\"" ; ls $(VAR2)
    @echo "now VAR3 = \"$(VAR3)\"" ; ls $(VAR3)
    @echo "now VAR4 = \"$(VAR4)\"" ; ls $(VAR4)
    @echo "now VAR5 = \"$(VAR5)\"" ; ls $(VAR5)
    @echo "now VAR6 = \"$(VAR6)\"" ; ls $(VAR6)
    rm -v foo.c

运行make将触发创建一个额外(空)C 文件的规则,该文件被调用,foo.c但 6 个变量中没有一个具有foo.c其值。

于 2016-12-12T11:40:50.050 回答
8

最赞成的答案可以改进。

让我参考 GNU Make 手册“设置变量”“风味”,并添加一些注释。

递归扩展变量

您指定的值是逐字安装的;如果它包含对其他变量的引用,则只要替换此变量(在扩展某些其他字符串的过程中),就会扩展这些引用。发生这种情况时,称为递归扩展

foo = $(bar)

catch :foo将扩展为$(bar) 每次 foo评估的值,可能导致不同的值。当然,您不能称其为“懒惰”!如果在午夜执行,这可能会让您大吃一惊:

# This variable is haunted!
WHEN = $(shell date -I)

something:
    touch $(WHEN).flag

# If this is executed on 00:00:00:000, $(WHEN) will have a different value!
something-else-later: something
    test -f $(WHEN).flag || echo "Boo!"

简单扩展变量

VARIABLE := value
VARIABLE ::= value

用 ':=' 或 '::=' 定义的变量只是扩展变量。

简单的扩展变量由使用 ':=' 或 '::=' [...] 的行定义。这两种形式在 GNU make 中是等价的;但是,POSIX 标准 [...] 2012 仅描述了 '::=' 形式。

一个简单扩展变量的值被扫描一次,当变量被定义时,扩展对其他变量和函数的任何引用。

没有太多要补充的。它立即被评估,包括递归扩展变量的递归扩展。

问题:如果VARIABLE指的是ANOTHER_VARIABLE

VARIABLE := $(ANOTHER_VARIABLE)-yohoho

并且ANOTHER_VARIABLE在此分配之前未定义,ANOTHER_VARIABLE将扩展为空值。

未设置时分配

FOO ?= bar

相当于

ifeq ($(origin FOO), undefined)
FOO = bar
endif

仅当根本没有设置变量时才$(origin FOO)等于。undefined

catch : 如果FOO在 makefile、shell 环境或命令行覆盖中设置为空字符串,则不会分配它bar

追加

VAR += bar

附加

当所讨论的变量以前没有定义过时,'+=' 的作用就像普通的 '=':它定义了一个递归扩展的变量。但是,当有先前的定义时,'+=' 的确切作用取决于您最初定义的变量的风格。

所以,这将打印foo bar

VAR = foo
# ... a mile of code
VAR += $(BAR)
BAR = bar
$(info $(VAR))

但这将打印foo

VAR := foo
# ... a mile of code
VAR += $(BAR)
BAR = bar
$(info $(VAR))

问题在于,根据之前分配的变量类型,其行为+=有所不同。VAR

多行值

将多行值分配给变量的语法是:

define VAR_NAME :=
line
line
endef

或者

define VAR_NAME =
line
line
endef

赋值运算符可以省略,然后它创建一个递归扩展变量。

define VAR_NAME
line
line
endef

endef删除之前的最后一个换行符。

奖励:shell 赋值运算符 '!='</h3>
 HASH != printf '\043'

是相同的

HASH := $(shell printf '\043')

不要使用它。$(shell)call 更具可读性,强烈建议不要在 makefile 中同时使用这两种方法。至少,$(shell)遵循 Joel 的建议,让错误的代码看起来很明显是错误的。

于 2020-07-31T06:49:21.233 回答