首页 > 技术文章 > makefile变量赋值方式及区别

adorkable 2020-08-28 13:36 原文

makefile中定义变量的值时常用到四种赋值符号,分别是"=",":=","?=","+="它们之间的区别如下:

延迟展开赋值:=

直接等号赋值是最简单的方式,等号左侧是变量,右侧是变量的值,但是不同于我们写代码时的顺序声明,makefile中等号右侧的变量可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。例如:

x = $(y)
y = hello

此时x的值是hello,可以这样理解:使用等号赋值的时候makefile在分析完整个文件后再把变量展开。

直接展开赋值::=

再说一下:=,:=与我们实际上更符合我们平时写代码的思维,也就是顺序声明变量,使用这种赋值方式,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量,makefile在读到这一行的时候就去确定这个变量的值而不是等全部分析完后把变量展开。举个例子:

x := hello
y := $(x) world

此时y的值是hello world,没什么好说的。但是如果是下面这样:

x := $(y) world
y := hello

此时x的值就不是hello world了,而是world,因为在x变量定义时y还没有定义,因此y还是个空变量,即什么都没有。

条件赋值:?=

这个很简单,如果变量没有被定义过,那么变量的值就是右侧的值,如果变量先前被定义过,那么这条语句将什么也不做,也就是说

x ?= hello

ifeq ($(origin x), undefined)
    x= hello
endif

是等价的。

追加赋值:+=

这个也很简单,就是在变量后面追加值:

x = hello
x += world

x变为hello world。


 举例说明直接展开赋值和延迟展开赋值的区别

1 DIR := /home/uname/project/output
2 FILES = $(shell find $(DIR) -type f)
3 
4 all: build1 build2 install
5     @echo "done"
6 
7 install:
8     $(foreach out, $(FILES), $(call xxx,$(strip $(out))))

假设DIR文件夹本来是空的,build1和build2过程会在DIR文件夹下产生文件(这里省略了build1和build2的具体内容),由于我们FILES变量使用的是延迟展开赋值,直到install过程的命令中才使用了这个变量,因此FILES变量会在这里进行展开,结果就是DIR下的所有文件。

如果FILES变量使用立即展开赋值,那么在一开始FILES就被展开了,此时还没有尽心build1、build2以及install的步骤,DIR下面是空的,所以FILES变量也为空。

推荐阅读