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變量也為空。