Makefile 中的 := 和 = 有什么区别?

发布于 2024-10-15 18:05:01 字数 47 浏览 7 评论 0原文

对于 Make 中的变量赋值,我看到 := 和 = 运算符。他们之间有什么区别?

For variable assignment in Make, I see := and = operator. What's the difference between them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

浅听莫相离 2024-10-22 18:05:01

简单赋值 :=

简单赋值表达式仅在第一次出现时计算一次。
例如,如果在第一次遇到时 CC :=${GCC} ${FLAGS} 被评估为 gcc -W 那么
每次出现 ${CC} 时,它都会被替换为 gcc -W

递归赋值 =

每次遇到变量时都会计算递归赋值表达式
在代码中。例如,像 CC = ${GCC} {FLAGS} 这样的语句仅在以下情况下才会被评估:
执行类似 ${CC} file.c 的操作。但是,如果变量 GCC 被重新分配,即
GCC=c++ 则重新赋值后,${CC} 将转换为 c++ -W

条件赋值 ?=

仅当变量没有值时,条件赋值才会为该变量赋值

附加 +=

假设 CC = gcc 那么附加运算符的使用方式类似于 CC += -w
那么 CC 现在的值是 gcc -W

有关更多信息,请查看这些 教程

Simple assignment :=

A simple assignment expression is evaluated only once, at the very first occurrence.
For example, if CC :=${GCC} ${FLAGS} during the first encounter is evaluated to gcc -W then
each time ${CC} occurs it will be replaced with gcc -W.

Recursive assignment =

A Recursive assignment expression is evaluated everytime the variable is encountered
in the code. For example, a statement like CC = ${GCC} {FLAGS} will be evaluated only when
an action like ${CC} file.c is executed. However, if the variable GCC is reassigned i.e
GCC=c++ then the ${CC} will be converted to c++ -W after the reassignment.

Conditional assignment ?=

Conditional assignment assigns a value to a variable only if it does not have a value

Appending +=

Assume that CC = gcc then the appending operator is used like CC += -w
then CC now has the value gcc -W

For more check out these tutorials

浮云落日 2024-10-22 18:05:01

GNU Make 文档中标题为 6.2 的部分对此进行了描述变量的两种风格

简而言之,用 := 定义的变量会扩展一次,但用 = 定义的变量每次使用时都会扩展。

This is described in the GNU Make documentation, in the section titled 6.2 The Two Flavors of Variables
.

In short, variables defined with := are expanded once, but variables defined with = are expanded whenever they are used.

酷炫老祖宗 2024-10-22 18:05:01

对我来说,在实践中看到它的最好方法是在这个 Makefile 片段中:

简单赋值

XX := $(shell date) # date will be executed once
tt:
    @echo $(XX)
    sleep 2
    @echo $(XX)

运行

make tt

将产生:(

sex 22 jan 2021 14:56:08 -03
sex 22 jan 2021 14:56:08 -03

相同值)

扩展赋值

XX = $(shell date) # date will be executed every time you use XX
tt:
    @echo $(XX)
    sleep 2
    @echo $(XX)

运行

make tt

将产生:

sex 22 jan 2021 14:56:08 -03
sex 22 jan 2021 14:56:10 -03

不同

For me, the best way to see it in practice is during this Makefile snippet:

Simple assignment

XX := $(shell date) # date will be executed once
tt:
    @echo $(XX)
    sleep 2
    @echo $(XX)

Running

make tt

Will produce:

sex 22 jan 2021 14:56:08 -03
sex 22 jan 2021 14:56:08 -03

( Same value )

Expanded assignment

XX = $(shell date) # date will be executed every time you use XX
tt:
    @echo $(XX)
    sleep 2
    @echo $(XX)

Running

make tt

Will produce:

sex 22 jan 2021 14:56:08 -03
sex 22 jan 2021 14:56:10 -03

Different values

离线来电— 2024-10-22 18:05:01

来自 http://www.gnu.org/software/make/manual/ make.html#Flavors

= 定义递归扩展变量。 := 定义简单扩展变量。

From http://www.gnu.org/software/make/manual/make.html#Flavors:

= defines a recursively-expanded variable. := defines a simply-expanded variable.

z祗昰~ 2024-10-22 18:05:01

这是一个老问题,但这个例子可以帮助我在我忘记时理解其中的区别。

使用以下 Makefile 运行 make 将立即退出:

a = $(shell sleep 3)

使用以下 Makefile 运行 make 将休眠 3 秒,然后退出:

a := $(shell sleep 3)

在前一个 Makefile 中,a< /code> 直到在 Makefile 中的其他地方使用时才被评估,而在后者中,即使没有使用,也会立即评估 a

This is an old question but this example helps me understand the difference whenever I forget.

Running make with the following Makefile will instantly exit:

a = $(shell sleep 3)

Running make with the following Makefile will sleep for 3 seconds, and then exit:

a := $(shell sleep 3)

In the former Makefile, a is not evaluated until it's used elsewhere in the Makefile, while in the latter a is evaluated immediately even though it's not used.

痴情 2024-10-22 18:05:01

递归赋值 = 每次使用时都会进行评估,但不是按照在配方命令中遇到它的顺序,而是运行任何配方命令之前进行评估。

基于以下示例:

default: target1 target2

target1 target2:
    @echo "Running at:           `gdate +%s.%N`"
    @echo "Simple assignment:    $(SIMPLE_ASSIGNMENT)"
    @echo "Recursive assignment: $(RECURSIVE_ASSIGNMENT)"
    sleep 1
    @echo "Running at:           `gdate +%s.%N`"
    @echo "Simple assignment:    $(SIMPLE_ASSIGNMENT)"
    @echo "Recursive assignment: $(RECURSIVE_ASSIGNMENT)"
    @echo


SIMPLE_ASSIGNMENT := $(shell gdate +%s.%N)
RECURSIVE_ASSIGNMENT = $(shell gdate +%s.%N)

输出:

❯ make
Running at:           1645056840.980488000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056840.958590000
sleep 1
Running at:           1645056842.008998000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056840.969616000

Running at:           1645056842.047367000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056842.027600000
sleep 1
Running at:           1645056843.076696000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056842.035901000

Recursive assignment = is evaluated everytime it is used, but not in the order of when it is encountered among the recipe commands, but rather before running any recipe command.

Based on the following example:

default: target1 target2

target1 target2:
    @echo "Running at:           `gdate +%s.%N`"
    @echo "Simple assignment:    $(SIMPLE_ASSIGNMENT)"
    @echo "Recursive assignment: $(RECURSIVE_ASSIGNMENT)"
    sleep 1
    @echo "Running at:           `gdate +%s.%N`"
    @echo "Simple assignment:    $(SIMPLE_ASSIGNMENT)"
    @echo "Recursive assignment: $(RECURSIVE_ASSIGNMENT)"
    @echo


SIMPLE_ASSIGNMENT := $(shell gdate +%s.%N)
RECURSIVE_ASSIGNMENT = $(shell gdate +%s.%N)

Outputs:

❯ make
Running at:           1645056840.980488000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056840.958590000
sleep 1
Running at:           1645056842.008998000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056840.969616000

Running at:           1645056842.047367000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056842.027600000
sleep 1
Running at:           1645056843.076696000
Simple assignment:    1645056840.949181000
Recursive assignment: 1645056842.035901000
风筝在阴天搁浅。 2024-10-22 18:05:01

= 称为递归扩展变量或惰性扩展变量。在下面的示例中,当 make 读取此行时

VAR1 = $(VAR1) + 100

,仅将右侧 VAR1 中的值存储到左侧 VAR1 中,而不进行扩展。当 make 尝试读取左侧定义的 $(VAR1) 时。这是不断重复并导致无限循环

VAR1 = 10
VAR2 = 20
VAR3 = 30

# Lazy initialization
VAR1 = $(VAR1) + 100

default:
    echo $(VAR1)

输出:

% make
Makefile:6: *** Recursive variable `VAR1' references itself (eventually).  Stop.

:= 称为扩展变量或

在 make 读取此行时即时,右侧的变量被扩展并将结果值保存到左侧手边。请参阅下面的程序输出

VAR1 = 10
VAR2 = 20
VAR3 = 30

# instant initialization
VAR1 := $(VAR1) + 100

default:
    echo $(VAR1)

% make
echo 10 + 100
10 + 100

输出:

% make
echo 10 + 100
10 + 100

编辑:
已经有很好的答案了。我在 Udemy 的 make 培训课程上偶然发现了这个概念,并给出了很好的例子。

= called recursive expanded variable or lazy expanded variable. in below example, when make read this line

VAR1 = $(VAR1) + 100

make just stored value from righthand side VAR1 into lefthand side VAR1 without expanding. When make tried to read $(VAR1) which is defined on left hand side. this is keep repeating and result into infinite loop

VAR1 = 10
VAR2 = 20
VAR3 = 30

# Lazy initialization
VAR1 = $(VAR1) + 100

default:
    echo $(VAR1)

Output:

% make
Makefile:6: *** Recursive variable `VAR1' references itself (eventually).  Stop.

:= called expanded variable or instant

when make read this line, variable on righthand side are expnaded and saved resulting value into left hand side. please see below program output

VAR1 = 10
VAR2 = 20
VAR3 = 30

# instant initialization
VAR1 := $(VAR1) + 100

default:
    echo $(VAR1)

% make
echo 10 + 100
10 + 100

Output:

% make
echo 10 + 100
10 + 100

EDIT:
There are already good answer. I came across about this concept on Udemy training course of make with good example.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文