以Makefile為腳本的專案建置工具GNU make
網路上一堆Makefile教學,雖然都是一模一樣的基礎中的基礎
但足夠說明make運作機制,故在此不再贅述
反而Variable的運作鮮少被談
因為範例Variable大多都設定在Makefile最開頭
而且不會再作任何更動
所以大概看了幾次範例之後大多數人就覺得變數僅僅如此
GNU make的Variable與其說是變數
倒不如說與Macro (巨集) 比較像
當被參考之時,是直接將值展開至參考處中
指定什麼就展開什麼
當然依不同需要就會需要不同的展開方式
展開方式取決於用何方式進行設定
下面列出幾個指定方式,變數值指定完成之後
需要使用 (參考) 時,以$開頭,後接變數名稱
若不特別指定,變數名稱預設以一個字元
故若變數長度多於一個字元,以 () 包覆之
基本上變數名稱很少指定一個字元,因此一般習慣性加上括號
如:$(VAR),變數值前後之空白皆會被忽略
make在開始進行正式運作前,會先將所有變數進行值設定與展開
各種類的設定與展開是有順序性的,這裡尚無辦法說出簡單明確的規則
Recursively expansion,GNU官方給的稱呼
這個Recursive還沒想清楚到底是指哪方面
只知道以此方式指定的變數
變數值中所包含的其他變數將在被參考時才進行變數值展開動作
即是說,每次參考都會進行一次展開動作
VAR1 = This is variable 1
VAR2 = This is variable 2 $(VAR1)
all:
@echo $(VAR2)
VAR1 = THIS is variable 1!!!
|
shell下達 make後將產生
This is variable 2 THIS is variable 1!!!
解析
- @echo $(VAR2) → @echo This is variable 2 $(VAR1)
- 繼續展開 VAR1,此時VAR1 值為 This is variable 1!!!
- 最後結果: This is variable 2 THIS is variable 1 !!!
眼下雖然這個例子很固定,但事實上若展開形式變得複雜
尤其是配合make function的使用,每次展開是有可能會產生不一樣的結果
以此方式設定之變數,變數值在設定時即進行展開
VAR1 = This is variable 1
VAR2 := This is variable 2 $(VAR1)
VAR1 = THIS is variable 1!!!
all:
@echo $(VAR2)
|
shell下達 make後將產生
This is variable 2 This is variable 1
VAR ?= Some value
根據官方的說法與下列語句相同
ifeq($(origin VAR), undefined)
VAR = Some value
endif
|
因Makefile可以 include其它 Makefile
而其中可能以定義了一些變數,若不希望覆寫,而是在未定義時才定義其值
即可使用此方式
最常、亦最顯著的一個作用是達成 include once
即,當在一個Makefile在一 include chain中被 include多次
僅會被展開一次
將設定值附加於原有內容之後
此種方式等號右邊,為shell指令,如:
VAR != ls
VAR之變數值將被設定為shell指令執行之結果
不過目前自己測試的結果不知為何沒有作用
另一替代方案是使用make的 shell function,如:
VAR = $(shell ls)
依需要可使用 = 、 := 等不同的設定方式
Makefile的解析是以行為主指令進行執行
每遇到一個斷行符號就把讀取之文字作為一個指令執行
當然,若指令過長非得斷行時可使用跳脫字元 (\) 將斷行符號跳脫
make將自動忽略該跳行符號,將多行文字作為一個指令解析
VAR = a \
b
# 注意 \ 後必須直接接跳行,不得有其他任何符號
# 換成C語言字元列就像這樣 '\\', '\n'
|
因此使用變數設定,展開的內容基本上沒辦法包含跳行等特殊符號
並且其內之空白亦有可能被作精簡
若還是有辦法達到,一堆跳脫字元 (\) 也會讓Makefile變得紊亂
若是想讓文字原封不動展開,使用define會是一個好選擇
define語法如下:
define defname
任何文字內容... \
$(VAR)
$(0) $(1)
endef
|
define內容的展開需以 make之 call function進行,如
$(call defname, [arg1, [arg2, [arg3, [...]]]])
以 define與 endef 關鍵字作為展開文字的範圍
自 define行跳行之後,即為文字展開的起始點
若define區塊當中若有任何變數參考,在make開始運作時就會展開
但當中有比較特殊的變數 $(0), $(1), ...,在 define展開時才進行置換
代表 call function所傳入之參數
$(0) 即代表 call function的第一個參數,亦即 define名稱本身
$(1)、$(2)...則依序代表第二、第三...之參數
當在 shell下達make指令時,可在指令上下達 varname = value
讓 make運作時即擁有這些變數
若 Makefile當中即有對同名變數進行一或多項設定
make將會忽略Makefile中對該變數的任何設定
例如下列 Makefile,若 make時下達 make VAR1="Changed Content"
VAR1 = This variable 1
VAR1 += 2 3 4
all:
@echo $(VAR1)
|
將會輸出下列內容:
Changed Content
若希望原有的設定值可以不受影響,Makefile中必須使用override關鍵字
如:
override VAR1 = This variable 1
VAR1 += 2 3 4
all:
@echo $(VAR1)
|
VAR1將會與shell指令下達的變數一致
因此在這個範例下輸出將會依照原有設定內容輸出
另外有另一種應用是在使用者下達之變數上,加上預設的內容
Makefile當中可以再輸入其他 make指令
使用之Makefile可能是自己本身,亦可能是其他Makefile
此時最上層 (即最初運行的make) 設定之所有變數
將會預設在接下來之make (sub-make)中出現
但若 sub-make之Makefile中已有同名變數
上層之make之變數即會被忽略,即 sub-make的變數不會被覆寫
除非 sub-make指令中亦包含了變數設定
此時可對變數使用 export,內容將會複寫至以下之sub-make中
# Makefile export VAR1 = Top-make all: make -f Makefile2 |
# Makefile2
VAR1 = Sub-make
VAR1 += !!
all:
@echo $(VAR1)
|
Makefile當中是否使用 export將會影響 Makefile2的輸出結果
留言列表