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

文章標籤
創作者介紹
創作者 wylokgo101 的頭像
wylokgo101

豆棚瓜架雨如絲 - WYLOKGO101

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