Makefile中=與:=的區別

在GNU make中,可以使用“=”和“:=”來定義變量,二者的區別主要在於展開時機。

1. 使用“:=”定義變量

  使用“:=”定義的變量稱爲“簡單展開變量(simply expanded variables)”,顧名思義,“:=”右邊的表達式如果包含對變量的引用,則這些對變量的引用會直接展開,得到一個確切的值,並賦給“:=”左邊的變量。這種定義和賦值的形式類似於C語言中對變量的賦值,舉例來說:

x := foo
y := $(x) bar
x := later
等價於:

y := foo bar
x := later
在 y := $(x) bar 處, x 的值爲 foo ,故 y 被賦值爲 foo bar ,隨後 x := later 更新了 x 的值,最終 x 的值爲 later , y 的值爲 foo bar 。

2.使用“=”定義變量

  使用“=”定義的變量稱爲“遞歸展開變量(recursively expanded variables)”,在使用“=”定義變量時,如果“=”右邊存在對其他變量或函數的引用,這些引用並不會立即展開。在實際使用到遞歸展開變量時,遞歸展開變量纔會展開,同時定義遞歸展開變量時使用的其他變量或函數的引用也會被展開,從而得到當前遞歸展開變量的值。在引用遞歸展開變量的地方,執行的是嚴格的文本替換過程,遞歸展開變量中的字符串原模原樣的出現在引用變量的地方,而遞歸展開變量中對其他變量的引用,只會在遞歸展開變量被展開的同時被展開。文字的描述比較複雜,舉例來說:

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:;echo $(foo)

將輸出 Huh? 。在 foo = $(bar) 處, foo 的定義使用了“=”,是一個遞歸展開變量,在這裏 bar 還沒有定義,實際上 bar 並也沒有在這裏定義 foo 時展開。在 bar = $(ugh) 處同理。而在 echo $(foo) 處,引用了foo ,這時 foo 被展開,發現 bar 的引用,進而展開 bar ,又發現了 ugh 的引用,再展開 ugh ,得到Huh? ,於是以此作爲 foo 的值進行輸出。

  實際上,遞歸展開變量的值是它在整個Makefile中最後被指定的值,如下面的例子:

foo = $(bar)
bar = $(ugh)
ugh := Huh?

all:;echo $(foo)

ugh := Ha!

將輸出 Ha!,注意 ugh := Huh? 和 ugh := Ha! 使用了“:=”。

  這裏涉及到GUN make的執行過程,GUN make的執行過程分爲兩個階段:第一階段讀取所有的makefile文件(包括“MAKIFILES”變量指定的、指示符“include”指定的、以及命令行選項“-f(–file)”指定的makefile文件),內建所有的變量、明確規則和隱含規則,並建立所有目標和依賴之間的依賴關係結構鏈表;第二階段根據第一階段已經建立的依賴關係結構鏈表決定哪些目標需要更新,並使用對應的規則來重建這些目標。

  如果變量和函數在make執行的第一階段中被展開,則稱此展開是“立即(Immediate)”的,此時所有的變量和函數被展開在需要構建的結構鏈表的對應規則中(此規則在建立鏈表是需要使用)。其他的展開稱之爲“延後(Deferred)”的。這些變量和函數不會被“立即”展開,而是直到後續某些規則須要使用時或者在make處理的第二階段它們纔會被展開。變量定義的解析過程爲:

IMMEDIATE = DEFERRED
IMMEDIATE ?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE += DEFERRED or IMMEDIATE
define IMMEDIATE
       DEFERRED
Endef
  回到剛纔的例子:
foo = $(bar)
bar = $(ugh)
ugh := Huh?

all:;echo $(foo)

ugh := Ha!

對於 ugh 這個簡單展開的變量,是立即(Immediate)展開的,會在make的第一階段立即展開;而對於foo 這個遞歸展開的變量,是延後(Deferred)展開的,在make的第二階段纔會展開,此時 ugh 已經展開完畢,得到了最終的值 Ha! ,所以在 echo $(foo) 處,輸出 foo 的值爲 Ha! 。

  最後留一個小問題,對於下面的例子:

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:;echo $(foo)

ugh = Ha!
echo $(foo) 將輸出什麼值?注意這裏 ugh 是遞歸展開變量。


更多說明可以查看GNU的相關文檔:

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

其中關於變量的部分在:

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

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

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









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章