close

書籤
  1. 數值設定
  2. define
  3. override
  4. export

 

以Makefile為腳本的專案建置工具GNU make

網路上一堆Makefile教學,雖然都是一模一樣的基礎中的基礎

但足夠說明make運作機制,故在此不再贅述

反而Variable的運作鮮少被談

因為範例Variable大多都設定在Makefile最開頭

而且不會再作任何更動

所以大概看了幾次範例之後大多數人就覺得變數僅僅如此

 

GNU make的Variable與其說是變數

倒不如說與Macro (巨集) 比較像

當被參考之時,是直接將值展開至參考處中

指定什麼就展開什麼

當然依不同需要就會需要不同的展開方式

展開方式取決於用何方式進行設定

 

數值設定

下面列出幾個指定方式,變數值指定完成之後

需要使用 (參考) 時,以$開頭,後接變數名稱

若不特別指定,變數名稱預設以一個字元

故若變數長度多於一個字元,以 () 包覆之

基本上變數名稱很少指定一個字元,因此一般習慣性加上括號

如:$(VAR),變數值前後之空白皆會被忽略

make在開始進行正式運作前,會先將所有變數進行值設定與展開

各種類的設定與展開是有順序性的,這裡尚無辦法說出簡單明確的規則

 = (recursively expansion)

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!!!

解析

    1.      @echo $(VAR2)  → @echo This is variable 2 $(VAR1) 
    2.      繼續展開 VAR1,此時VAR1 值為 This is variable 1!!!
    3.      最後結果: This is variable 2 THIS is variable 1 !!!

眼下雖然這個例子很固定,但事實上若展開形式變得複雜

尤其是配合make function的使用,每次展開是有可能會產生不一樣的結果

 

 := (simply expansion)

以此方式設定之變數,變數值在設定時即進行展開

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

 ?= (set if not defined)

VAR ?= Some value

根據官方的說法與下列語句相同

ifeq($(origin VAR), undefined)
    VAR = Some value
endif

因Makefile可以 include其它 Makefile

而其中可能以定義了一些變數,若不希望覆寫,而是在未定義時才定義其值

即可使用此方式

最常、亦最顯著的一個作用是達成 include once

即,當在一個Makefile在一 include chain中被 include多次

僅會被展開一次

+= (append)

將設定值附加於原有內容之後

 != (shell output assign)

此種方式等號右邊,為shell指令,如:

VAR != ls

VAR之變數值將被設定為shell指令執行之結果

不過目前自己測試的結果不知為何沒有作用

另一替代方案是使用make的 shell function,如:

VAR = $(shell ls)

依需要可使用 = 、 := 等不同的設定方式

 

define

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)...則依序代表第二、第三...之參數

 

覆寫Override 

當在 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指令下達的變數一致

因此在這個範例下輸出將會依照原有設定內容輸出

另外有另一種應用是在使用者下達之變數上,加上預設的內容

 

export

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的輸出結果

arrow
arrow
    文章標籤
    make variable macro
    全站熱搜

    wylokgo101 發表在 痞客邦 留言(0) 人氣()