ChatGPT解决这个技术问题 Extra ChatGPT

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

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


C
Czechnology

简单的分配:=

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

递归赋值 =

每次在代码中遇到变量时都会计算递归赋值表达式。例如,只有在执行类似 ${CC} file.c 的操作时才会评估类似 CC = ${GCC} {FLAGS} 的语句。但是,如果变量 GCC 被重新赋值,即 GCC=c++,那么 ${CC} 将在重新赋值后转换为 c++ -W

条件赋值 ?=

条件赋值仅在变量没有值时才为其赋值

附加 +=

假设 CC = gcc 然后附加运算符像 CC += -w
一样使用,那么 CC 现在的值是 gcc -W

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


“一个简单的赋值表达式只在第一次出现时被评估一次”:要清楚,扩展/评估是在定义变量时完成的,而不是第一次使用它。
G
Greg Hewgill

这在 GNU Make 文档中标题为 6.2 The Two Flavors of Variables 的部分中进行了描述。

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


那么说 := 更有效是正确的吗?或者效率不是 Makefile 的真正因素?
@Ungeheuer 这不是问题,因为进程调用(make 的主要工作)的开销比这种内部变量解析要大得多。
x
xn.

对我来说,在实践中查看它的最佳方式是在这个 Makefile 片段中:

简单的分配

XX := $(shell date) // date will be executed once
tt:
    @echo $(XX)
    $(shell 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)
    $(shell sleep 2)
    @echo $(XX)

跑步

make tt

将产生:

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

不同的价值观


O
Oliver Charlesworth

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

= 定义了一个递归扩展的变量。 := 定义了一个简单扩展的变量。


A
Andrey Kaipov

这是一个老问题,但这个例子可以帮助我在忘记时理解差异。

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

a = $(shell sleep 3)

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

a := $(shell sleep 3)

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


U
Utsav Munendra

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

基于以下示例:

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