:=
简单赋值表达式仅在第一次出现时进行计算。例如,如果在首次遇到时 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
了解更多,请查看这些教程
这在GNU Make文档的6.2变量的两种类型一章中有详细说明。
简而言之,使用:=
定义的变量只会被扩展一次,但使用=
定义的变量会在每次使用时被扩展。
make
的主要工作)比解析内部变量的开销大得多。 - Kirill BulyginXX := $(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
不同的值
//
不是有效的注释。 - Eric$(shell sleep 2)
而不是直接调用sleep 2
。两者之间的结果确实非常不同。你为什么选择了$(shell ...)
? - Ericshell sleep 2
,我认为只使用 sleep 2
就可以很好地工作。在创建这个答案时,我从一个 Makefile
中复制了这段代码,用于将其结果分配给一个变量,这就是使用 $(shell ...)
的原因,类似于:result:=$(find . -type f -name '*js'
。 - Edgard Leal来自http://www.gnu.org/software/make/manual/make.html#Flavors:
=
定义了一个递归扩展的变量。 :=
定义了一个简单扩展的变量。
虽然这是一个老问题,但是这个例子帮助我理解区别,特别是在我忘记时。
使用以下Makefile运行make
将立即退出:
a = $(shell sleep 3)
使用以下Makefile运行make
将会等待3秒钟,然后退出:
a := $(shell sleep 3)
a
时才会对其进行评估,而在后一个 Makefile 中,即使没有使用它,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
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.
:=
称为扩展变量或即时变量
当读取这行代码时,右侧的变量将被扩展并将结果值保存到左侧。请参阅下面的程序输出
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