对于 Make 中的变量赋值,我看到 := 和 = 运算符。他们之间有什么区别?
:=
简单的赋值表达式仅在第一次出现时计算一次。 例如,如果第一次遇到时的
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
有关更多信息,请查看这些教程
对我来说,在实践中看到它的最好方法是在这个 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
不同值
这是一个老问题,但这个例子可以帮助我在我忘记的时候理解其中的区别。
使用以下 Makefile 运行
make
将立即退出:
a = $(shell sleep 3)
使用以下 Makefile 运行
make
将休眠 3 秒,然后退出:
a := $(shell sleep 3)
在前一个 Makefile 中,直到在 Makefile 中的其他地方使用
a
才会被评估,而在后者中 a
即使没有被使用也会立即评估。
递归赋值
=
每次使用时都会进行评估,但不是按照在配方命令中遇到它的顺序,而是在之前运行任何配方命令。
基于以下示例:
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
=
称为递归扩展变量或惰性扩展变量。在下面的例子中,当 make 读取这一行时
VAR1 = $(VAR1) + 100
将右侧 VAR1 中刚刚存储的值放入左侧 VAR1 中,而不进行扩展。当 make 尝试读取左侧定义的 $(VAR1) 时。这是不断重复并导致无限循环
VAR1 = 10
VAR2 = 20
VAR3 = 30
# Lazy initialization
VAR1 = $(VAR1) + 100
default:
echo $(VAR1)
Makefile结果:
% 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
Makefile结果:
% make
echo 10 + 100
10 + 100
编辑: 已经有很好的答案了。我在 Udemy 的 make 培训课程上遇到了这个概念,并提供了很好的例子。