makefile變量

makefile 變量與宏

變量和宏其實說的是同一東西。一個變量的內容是一個字符串,從一個變量名得到變量內容的過程叫作變量的擴展,用$()或者${}擴住變量名便可。而不想編程語言那樣,使用變量名就能引用變量的值。shell

變量的類型

make的變量有兩種:簡易變量和遞歸擴展的變量。變量的定義是一個賦值動做,把等號右邊的內容賦給左邊。這裏等號能夠有多種::=、=、?=,他們決定了怎樣賦值。等號兩邊的東西能夠只是字面值,或者含有變量。賦值時,變量名須要是明確的,等號左邊的內容當即擴展(沒有變量就保持不變),右邊的內容根據賦值符號決定什麼時候擴展。數據庫

簡易變量

:=或者::=賦值運算符定義的是一個簡易擴展的變量。一旦make讀入該變量的定義語句,賦值運算符右邊部分會馬上擴展,而擴展後的文本會被存儲成該變量的值。變量名和變量內容加入到數據庫。
MAKE_DEPEND := $(CC) -M
此變量通常被擴展爲
gcc -M
然而,若是CC變量還沒有定義,則擴展爲:
<space>-M
變量沒有定義不算錯誤。編程

遞歸變量

=定義的變量。或者define定義的變量。
make只會讀進賦值運算符後邊的部分,並將之存儲成該變量的值,但不會進行任何擴展的動做,擴展的動做會被延遲到該變量被使用的時候進行。編程語言

其餘賦值類型

make還提供了另外兩種賦值運算符:?=+=ide

?= 運算符稱爲附帶條件的變量賦值運算符。此運算符只會在變量的值尚不存在是進行復制動做。
+= 運算符稱爲附加運算符。此運算符會將文本附加到變量裏。對遞歸變量仍有用。
對於簡單變量,等效於
simple := $(simple) new stuff
然而,對於遞歸變量
recursive = $(recursive) new stuff
這種表達式是非法的,會被無限擴展。要想將某段文本附加到遞歸變量上,就須要附加運算符了。ui

工做目標與模式的專屬變量

make提供了工做目標的專屬變量。這些變量的定義會附加在工做目標上,且只有在該工做目標以及相應的必要條件被處理的時候,他們纔會發生做用spa

工做目標的專屬變量語法以下:命令行

target...: variable = value
target...: variable := value
target...: variable ?= value
target...: variable += value

若是在編譯某個源文件的時候須要單獨指定一個宏定義,然而該文件又在某個模式規則中:code

gui.o: CPPFLAGS += -DUSE_NEW_MALLOC=1
gui.o: gui.h

當make處理gui.o這個工做目標時,CPPFLAGS這個變量會附加-DUSE_NEW_MALLOC=1,當處理完gui.o這個目標以後,CPPFLAGS會恢復它原來的值。遞歸

變量的來源

文件

變量能夠被定義在makefile中,或是被makefile引入(include指令)

命令行

能夠直接在make命令行上定義或者從新定義變量: $ make CFLAG=-g CPPFLAGS='DBSD -DDEBUG'
每一個命令行參數中所包含的等號,都是一個變量賦值運算符。在命令行上,每一個變量賦值運算符的右邊部分必須是一個單獨的shell參數。若是變量的值含有空格,則必須爲參數加上括號或是引號。
命令行上變量的賦值將會覆蓋掉環境變量以及makefile中的賦值結果。若是要使makefile中的變量覆蓋命令行中的變量,能夠在makefile中的變量前加override指令。

環境

當make啓動時,全部來自環境的變量都會被定義爲make的變量。這些變量具備很是低的優先級,makefile文件或命令行參數的賦值結果都會覆蓋環境變量的值。可是,可使用--environment-overrides(或-e)命令行選項,讓環境變量覆蓋相應的makefile變量。
當make被遞歸調用時,有若干來自上層make的變量會經過環境傳遞給下層的make。默認只有原來就來自環境的變量會被導出到下層的環境中。可使用export指令導出任何變量。

自動建立

make會在執行一個規則的命令腳本以前當即建立自動變量。注意自動變量建立的時機。

在makefile中定義變量

variable := value

variable = value

variable ?= value

define variable =
...
...
endef
define variable :=
...
...
endef

define的特長是能夠定義多行內容的變量。

一個變量的值由賦值符號右邊除去前導空格的全部字符組成。跟在全部字以後的空格不會被刪除。這有時會致使問題。

宏是之前對變量的另外一種稱呼。
能夠經過define指令建立「封裝命令序列」,稱爲宏。在make中,宏只是用來定義變量的另外一種形式,此變量還能夠包含換行符。通常,將由define定義的變量稱爲宏,由賦值運算符定義的變量稱爲變量。

define後跟着變量名和換行,變量的主體是由跳格符開頭的命令行,最後以endef結尾。

define create-jar
    @echo Creating $@...
    $(RM) $(TMP_JAR_DIR)
    $(MKDIR) $(TMP_JAR_DIR)
    $(CP) -r $^ $(TMP_JAR_DIR)
    cd $(TMP_JAR_DIR) && $(JAR) $(JARFLAGS) $@ .
    $(JAR) -ufm $@ $(MANIFEST)
    $(RM) $(TMP_JAR_DIR)
endef

@的做用:make將每條命令交給shell執行以前都會打印出此條命令,在該命令以前加@可使make不這樣作。若是在命令中應用了一個宏,使用@將使整個宏擴展後的命令以前都加上@。

當make運行時,它會以兩個階段來完成他的工做。第一階段,make讀進makefile以及被引入的任何其餘makefile。這時,其中所定義的變量會被加載到make的內部數據庫,並創建依存圖。第二階段,make分析依存圖並判斷須要更新的目標,而後執行腳本。

當make在處理遞歸變量或者define指令的時候,會將變量裏的每一行或宏的主體存儲起來,包括換行符號,但不會予以擴展。宏定義的最後一個換行符不會做爲宏的一部分,不然,宏被擴展時會多一個換行。
當宏被擴展時,make會當即掃描被擴展的文本中是否存在宏或變量的引用,若是存在就予以擴展,如此遞歸下去。若是宏是在命令腳本里被擴展的,則宏的主體的每一行都會被插入一個跳格符。

下面是makefile中的元素什麼時候被擴展的原則:

  • 對於變量賦值,make會在第一階段讀取該行時,當即擴展賦值運算符左邊的部分。
  • =?=的右邊會被延後到他們被使用時擴展,而且在第二階段運行。
  • :=右邊的部分會被當即擴展
  • 若是+=的左邊部分本來被定義成一個簡單變量,+=的右邊就會被當即擴展,不然,求值動做就會延後。
  • 對於宏定義,宏的變量名會被當即擴展,宏的主體延後擴展。
  • 對於規則,工做目標和必要條件老是被當即擴展,而命令老是延後擴展。

延後擴展發生在它所在的表達式須要被擴展時,好比在規則的目標和必要條件中、在一個將要執行的命令中或者出如今簡易變量賦值的右邊等等。

OUTPUT_DIR := /tmp

$(OUTPUT_DIR)/very_big_file:
    $(free-space)

define free-space
    $(PRINTF) "Free disk space"
    $(DF) . | $(AWK) 'NR == 2 { print $$4 }'
endef

BIN := /usr/bin
PRINTF := $(BIN)/printf
DF := $(BIN)/df
AWK := $(BIN)/awk

說明:

第一階段:make逐行讀取makefile並將變量加入內部數據庫,創建依存圖。
OUTPUT_DIR是簡單變量,它的值就是普通的字面值(若是這裏有$引用的變量,將會進行擴展動做),放到數據庫中。
接下來是一條規則,規則的目標和條件都是當即擴展的,而命令是延後擴展的,保持不變。因此這條規則變爲:

/tmp/very_big_file:
    $(free-space)

以後是一個宏定義,宏名是當即擴展的,這裏只是字面值,不用擴展。宏體是延後擴展的,在使用該宏的時候才擴展。
最後4個簡易變量都是直接擴展的,將變量值加入到數據庫中。

第二階段:
按照後序遍歷規則樹進行規則的執行動做。這時要使用規則中的命令部分,對命令中的變量和宏進行擴展,並執行命令。

自動變量

自動變量是一種make在處理規則時自動賦值的變量。

變量名 描述
$@ 工做目標的文件名
$% 檔案文件成員結構中的文件名元素
$< 第一個必要條件的文件名
$? 時間戳在工做目標以後的全部必要條件,並以空格隔開。
$^ 全部必要條件的文件名,並以空格隔開。
$+ 如同$^,表明全部必要條件的文件名,並以空格隔開。不過$+包含重複的文件名。
$* 工做目標的主文件名。文件名由主文件名和擴展名構成。

說明: 檔案文件中個別的成員可做爲工做目標或必要條件。能夠經過archive(member)這樣的語法在檔案文件archive中指定名爲member的成員。若工做目標是foo.a(bar.o),則$%bar.o$@foo.a。當工做目標不是一個檔案文件時,$%是空的。

相關文章
相關標籤/搜索