Makefile Summary

一個工程在用make來執行時,需要一個命名爲Makefile的特殊文件。這個文件告訴make需要作什麼,該如何做。其主要用來進行工程編譯和程序鏈接以至於最後的執行。目的是用來實現程序的自動化編譯。所以說使用make工具來構建和管理一個屬於自己的工程,是一項基本要求。
一個簡單的Makefile一般是由“規則”組成。規則描述在什麼情況下、如何重建規則的目標文件。以下示例:
TARGET... :PREREQUISITES...
COMMAND
...
...
target:規則的目標。通常是最後需要生成的文件名或者爲了實現這個目的而必需的中間過程文件名。[[BR]] 另外,也可以是一個make執行的動作名稱。如僞目標“clean”。
prerequisites:規則的依賴。生成規則目標所需要的文件名列表。[[BR]] command: 規則的命令行。規則所要執行的動作。每個命令行必須以[tab]字符開始。

一、Makefile的規則

1. make如何更新規則

默認情形,make執行的是Makefile的第一個規則,此規則的第一個目標稱爲“終極目標”。
make更新規則時主要是根據文件的時間戳來執行動作:
(1)目標文件不存在,使用描述規則創建它;
(2)目標文件存在,如果它所依賴的文件任何一個比目標文件更新,根據規則重新編譯它;
(3)目標文件存在,且比任何一個依賴文件更新,則什麼都不做。

2. makefile的內容

在一個完整的makefile中,包含了5個東西:
(1)顯示規則:描述何種情況下如何更新一個或者多個目標文件。需要給出明確的目標文件,依賴文件列表以及更新目標文件所需的命令(有些規則也許只描述文件之間的依賴關係)。
(2)隱含規則:它是make根據一類目標文件(文件後綴)而自動推導出來的規則。
(3)變量定義:使用一個字符或字符串代表一段文本串。
(4)makefile指示符:指明在make程序讀取makefile文件過程中所要執行的一個動作。
(5)註釋 : #字符後的內容作爲註釋內容處理,如果跟(\),那麼下一行也被作爲註釋行。
(\#)是對#的轉義。

3.makefile文件的命名

默認情況,make會在工作目錄下查找文件名順序爲:GNUmakefile、makefile、Makefile.
make -f NAME 或make --file=NAME 可指定文件NAME作爲執行make時讀取的makefile文件。

4.包含其他makefile文件

關鍵字“include”指示符告訴make暫停當前的Makefile而去讀取“include”指定的一個或者多個文件。完成之後再繼續當前Makefile的讀取。其書寫要佔獨立一行。但不要以[tab]字符開始。
-include 告訴make,忽略由於包含文件不存在或者無法創建時候的錯誤提示。
MAKEFILES 變量
如果當前環境定義了一個“MAKEFILES”環境變量,make執行時首先將此變量的值作爲需要讀入的makefile文件。多個文件用空格分隔。
5.make的執行過程

(1) 依次讀取變量“MAKEFILES”定義的 makefile 文件列表
(2) 讀取工作目錄下的 makefile 文件(根據命名的查找順序“GNUmakefile、makefile、Makefile“,首次找到哪個就讀取哪個。
(3) 依次讀取工作目錄 makefile 文件中使用指示符“include”包含的文件
(4) 查找重建所有已讀取的 makefile 文件的規則
(5) 初始化變量值並展開那些需要立即展開的變量和函數並根據預設條件確定執行分支
(6) 根據“終極目標”以及其他目標的依賴關係建立依賴關係鏈表
(7) 執行除“終極目標”以外的所有的目標的規則(規則中如果依賴文件中任一個文件的時間戳比目標文件新,則使用規則所定義的命令重建目標文件)
(8) 執行“終極目標”所在的規則。

6.makefile的目錄搜尋

在一個較大工程中,一般源代碼和二進制文件安排在不同的目錄來進行區分管理。這種情況下,我們可以用make提供的目錄搜索依賴文件的功能來進行自動化編譯和鏈接。
(1)一般搜索:變量VPATH
通過變量“VPATH”可以指定依賴文件的搜索路徑,當規則的依賴文件在當前目錄不存在時,make會在此變量指定的目錄下去尋找這些依賴文件。
並且,"VPATH"變量所指定的是MAKEFILE中所有文件的搜索路徑,包括了規則的依賴文件和目標文件。
定義變量“VPATH”時,使用空格或者冒號(:)將多個需要搜索的目錄分開。make搜索目錄的順序是按照變量“VPATH”定義中的目錄順序進行的。
當前目錄永遠是第一搜索目錄.
vpath全小寫,是make的一個關鍵字,它所實現的功能和上一小節提到的“VPATH”變量類似, 但更加靈活。它有三種使用方法:
(2)選擇性搜索
1. vpath PATTERN DIRECTORIES
爲所有符合模式”PATTERN“的文件指定搜索目錄“DIRECTORIES”,多個目錄使用空格或者冒號分開。
2.vpath PATTERN
清除之前爲符合模式“PATTERN”的文件設置的搜索路徑。
3.vpath
清除所有已被設置的文件搜索路徑。
PATTERN需要包含模式字符“%”,意思是匹配一個或者多個字符,“%.h”表示所有以“.h”結尾的文件。如果沒有%,那就是一個明確的文件名,那就給定了此文件的所在目錄。
(3)目錄搜索機制
make在解析Makefile文件執行規則時對文件路徑保存或廢棄根據一定的算法:
1.如果規則的目標文件不存在於在makefile文件所在的目錄, 那麼就執行目錄搜尋;
2.如果目錄搜尋成功,且指定的目錄下存在此規則的目標(也就是不需要被創建)。那麼搜索到的完整路徑名被保存。
3.對於規則中的所有依賴文件使用相同的方法處理。
4.依賴文件處理後,make程序就可以決定規則的目標是否需要重建,兩種情況分別如下處理:
a)規則的目標不需要重建:通過目錄搜索得到的所有完整的依賴文件路徑名有效,規則的目標文件的完整路徑名同樣有效。
b)規則的目標需要重建: 通過目錄搜索得到的目標文件的完整路徑名無效。規則中的目標文件將會在工作目錄下重建,而不是在目錄搜尋時得到的目錄。
注意:依賴文件的完整路徑名是不會失效的。否則無法重建目標。
如果重建目標的時候,不改變目標文件生成的路徑,使用GPATH。
(4) 命令行和搜索目錄
爲了保證依賴文件在其他目錄下被發現時規則的命令能夠正確執行。
我們採用自動化變量
$^:代表所有通過目錄搜索得到的依賴文件的完整路徑名(目錄 + 一般文件名);
$@:代表規則的目標
$<:代表規則中通過目錄搜索得到的依賴文件列表的第一個依賴文件

for example:foo.o : foo.c
cc -c $(CFLAGS) $^ -o $@
(5)庫文件和搜索目錄
Makefile中程序鏈接的靜態庫、共享庫同樣也可以通過搜索目錄得到。
書寫規則的依賴時指定一個類似“-INAME”的依賴文件名,INAME --> libNAME.so
搜索庫文件的順序:1.make執行規則時會在當前目錄下搜索一個名爲“libNAME.so”文件;
2.當前目錄下不存在,繼續搜索使用"VPATH"or "vpath"指定的搜索目錄。
3.還是不存在,將搜索系統庫文件存在的默認目錄,順序是"./lib" "/usr/lib"和“/usr/local/lib”
如果libNAME.so動態庫通過以上搜索未找到,可以按照搜索順序查找名爲“libNAME.a”的文件。
除此之外,可以通過編譯選項來指定搜索靜態鏈接庫還是動態鏈接庫。
7. Makefile 僞目標
僞目標是這樣的一個目標,它不代表一個真正的文件名,在執行make時可以指定這個目標來執行其所在規則定義的命令。
也可以將之稱爲一個標籤。使用僞目標有兩點原因:
(1)避免在Makefile中定義的只執行命令的目標和工作目錄下的實際文件出現名字衝突。
(2)提高執行make時的效率,特別是對於一些大型的工程來說,編譯的效率是個值得關注的問題。
將一個目標聲明爲僞目標的方法是將它作爲特殊僞目標.PHONY的依賴。
!.PHONY:clean
執行時輸入make clean,命令會被執行。而且不會去試圖查找隱含規則來創建它。保證了make的執行效率。
對多個目錄進行make的實現方式可以是:在一個規則的命令行中使用shell循環來完成:
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
當一個僞目標沒有作爲任何目標的依賴時,可以通過make的命令行來明確指定它爲make的終極目標,來執行它所在規則所定義的命令。
如make clean。
在一個Makefile中,一個僞目標可以有自己的依賴(可以是文件或是僞目標);在一個目錄下需要創建多個可執行程序,可以
將所有程序的重建規則在一個Makefile中描述,Makefile的第一個目標是終極目標,約定的做法是使用一個稱爲all的僞目標作爲
終極目標,它的依賴文件是那些需要創建的程序。
另外:RM 是make存在的一個內嵌隱含變量,被定義爲:“RM = rm -f",因此可以用$(RM)來代替“rm",避免一些不必要的麻煩。

8.雙冒號規則
雙冒號規則就是使用“::” 代替普通規則的“:“得到的規則。當同一個文件作爲多個規則的目標時,雙冒號規則的處理和普通規則的處理過
程完全不同。雙冒號規則允許在多個規則中爲同一個目標指定不通的重建目標的命令。
在Makefile中,一個目標可以出現在多個規則中。但是這些規則必須是同一類型的規則,要麼都是普通規則,要麼都是雙冒號
規則。而不允許一個目標同時出現在兩種不同類型的規則中。他們的不同點在於:
(1)雙冒號規則中,當依賴文件比目標文件更新時,規則將會被執行。對於一個沒有依賴而只有命令行的雙冒號規則,當引用
此目標時,規則的命令將會被無條件執行。而普通規則,當規則的目標文件存在時,此規則的命令永遠不會被執行。
(2)當同一個文件作爲多個雙冒號規則的目標時,這些不同的規則會被獨立處理。而不是像普通規則那樣合併所有的依賴到一個
目標文件。意味着這些規則的處理像多個不通的普通規則一樣。多個雙冒號規則中的每一個依賴文件被改變後,make只執行此規則定義的
命令,而其他的以這個文件作爲目標的雙冒號規則將不會被執行。
9.自動產生依賴
gcc -M 選項 可以自動查找源文件中包含的頭文件,並生成文件的依賴關係。
for example: maic.c include defs.h
run command: gcc -M main.c
output : main.o:main.c defs.h
而且也包含對標準庫的頭文件的依賴關係描述。
當不需要在依賴關係中考慮標準庫頭文件時,對gcc需要使用“-MM"參數。二、規則的命令
1. 規則的命令
(1).規則命令由一些shell命令行組成,它們被一條一條的執行。除了第一條緊跟在依賴列表之後使用分號隔開的命令以外,其他的每
一行命令行必須以【TAB】字符開始。多個命令行之間可以有空行和註釋行。
空行:就是不包含任何字符的一行。
空命令行:以tab鍵開始,而其後沒有命令的行,此行不是空行,是空命令行。
2.命令的回顯
如果規則的命令行以字符@開始,make執行這個命令時,就不會回顯這個將要被執行的命令。
make -n or "--just-print" 那麼make執行時,只顯示所要執行的命令,但不會真正的去執行這些命令。
make -s or "--silent" 禁止所有執行命令的顯示。好像所有命令均使用@開始一樣。
3.命令的執行
當目標需要重建時,規則的命令將會被執行,如果是多行命令,那麼每一行命令將在一個獨立的子shell進程中被執行。多行命令之間的執行
是相互獨立的,相互之間不存在依賴。
在makefile中,書寫在同一行的多個命令屬於一個完整的shell命令行,書寫在獨立行的一條命令是一個獨立的shell命令行。
如果希望把一個完整的shell命令行書寫在多行,需要使用(\)來對於多行的命令進行連接。
make對所有命令的解析使用環境變量 “SHELL“所指定的那個程序,在GNU make中,默認的程序是"/bin/sh".
4.命令的並行執行
make支持同時執行多條命令。make -j or --job選項來告訴make在同一時刻可以允許多條命令同時執行。默認j=1
5.命令執行的錯誤
規則中的命令運行結束後,make會檢測命令執行的返回狀態,如果返回成功,啓動另外一個子shell來執行下一條命令。規則中所有命令
執行完成之後,這個規則就執行完成了。如果某個命令出現錯誤返回非0,make就會放棄對當前規則後續命令的執行。
一般情況下,規則中命令的執行失敗並不代表規則執行的錯誤。
在命令之前加一個減號”-“,來告訴make忽略此命令的執行失敗。也可在make執行時,使用選項-ior --ignore-errors,make將忽略
所有規則中命令執行的錯誤。也可以使用-k or --keep-going來通知make,出現錯誤時,不立即退出。而是繼續後續命令的執行。
通常情況下,執行失敗的命令一旦改變了所在規則的目標文件,就不是一個被正確重建的文件,推薦做法是make執行失敗時,修改錯誤
之後執行make clean,來明確刪除第一次錯誤重建的所有目標。
6.幾個make變量
MAKE,使用make遞歸調用時,在命令行中應該使用變量MAKE,來代替直接使用make。
兩個特殊的變量“SHELL“”MAKEFLAGS“,他們在整個make的執行過程中始終自動的傳遞給所有的子make,除非使用unexport對他們進行
聲明。對其他的變量,需要使用export聲明,纔會傳遞給子make。
不帶任何參數的export指示符: export 含義是此Makefile中定義的所有變量傳遞給子make過程。
MAKELEVEL 代表了調用的深度。
有幾個特殊的命令行選項不會傳遞給MAKEFLAGS變量,他們是-C -f -o -W
7.自動化變量
define 可以定義一組命令,同時使用一個變量來代表這一組命令;
變量可以用來代表一個文件名列表,編譯選項列表,程序運行選項參數列表等等
變量名大小寫敏感的
具有特殊字符的幾個變量稱他們是 自動化變量。
$@ 表示規則的目標文件名,在多目標模式規則中,它代表的是哪個觸發規則被執行的目標文件名
$% 當規則的目標文件是一個靜態庫文件時,代表靜態庫的一個成員名,如果目標不是靜態庫,其值爲空。
$< 代表規則的第一個依賴文件名。如果目標文件使用隱含規則來重建,代表由隱含規則加入的第一個依賴文件
$? 所有比目標文件更新的依賴文件列表,空格分割;如果目標是靜態庫文件名,代表的是庫成員
$^ 規則的所有依賴文件列表,使用空格分割。如果是靜態庫文件,代表的是所有庫成員名
$+ 類似$^,但是它保留了依賴文件中重複出現的文件,主要用在程序鏈接時,庫的交叉引用場合
$* 在模式規則和靜態模式規則中,代表莖,莖是目標模式中 % 所代表的部分,也包含目錄。
for example:文件“dir/a.foo.b",當目標的模式爲 “a.%.b"時,$*的值爲dir/a.foo
$$ 引用$ 這個符號
8,變量的引用
make的變量(MAKEFILE中定義的,或者是make的環境變量)的引用使用$(VAR),無論VAR是單字符還是多字符變量名
出現在規則中的shell變量,引用使用$tmp格式
出現在命令行中的make變量我們同樣使用$(CMDVAR)格式來引用

9.如何定義空格
nullstring :=
space := $(nullstring) # end of the line
變量space表示一個空格
10.定義變量的方式
變量的定義是通過“=”(遞歸方式)”:=“(靜態方式)”+=“(追加方式)來實現的。
:= 定義的變量 爲直接展開式變量,直接展開式的變量如果其值中存在其他變量或者函數的引用,在定義時這些引用將會被替換展開。
= 遞歸展開式變量,此變量的引用,是嚴格的文本替換過程,如果變量中存在對其他變量的引用,在變量定義時,變量值中的引用不會被
替換展開,而是變量在引用它的地方替換展開的同時,它引用的變量纔會被一同替換展開。
+= 追加變量值 在一個變量定義之後的其他一個地方,可以對其值進行追加,這是非常有用的。
?= 條件賦值的賦值操作符 ?=. FOO?=bar 含義是如果之前FOO沒有被賦值的情況下,纔會對FOO賦值。FOO = bar
11. override 指示符
如果通過命令行定義了一個變量,那麼它將替代在Makefile中出現的同名變量定義。如果不希望替換makefile中的變量定義,需要使用
指示符override來對變量進行聲明
12 define多行定義
類似於c語言中的define,可以對一個變量進行多行定義。以指示符define開始,endif結束,所要定義的變量名字和指示符define在
同一行,空格分開,指示符所在行的下一行開始一直到endif所在行上一個行直接的若干行,都是變量值。
三、makefile的條件執行1.條件判斷基本語法
for example:
ifeq($(CC),gcc)
$(CC) -o foo $() $()
else
$(CC) -o foo $() $()
endif
2.ifeq :判斷參數是否相等
ifeq (ARG1, ARG2)'[[BR]] ifeq 'ARG1' 'ARG2''
ifeq "ARG1" "ARG2"'[[BR]] ifeq "ARG1" 'ARG2''
ifeq 'ARG1' "ARG2"'[[BR]]3.ifneq :判斷參數是否不相等[[BR]] ifneq (ARG1, ARG2)'
ifneq 'ARG1' 'ARG2!''[[BR]] ifneq "ARG1" "ARG2"'
ifneq "ARG1" 'ARG2!''[[BR]] ifneq 'ARG1' "ARG2"'
4.ifdef :判斷一個變量是否已經定義
ifdef VARIABLE-NAME5.ifndef: 判斷一個變量是否沒有定義,與ifdef實現的功能相反四、makefile的內嵌函數GNU make 的函數提供了處理文件名、變量、文本和命令的方法,使用函數使得Makefile的書寫更加靈活健壯。1.函數的調用語法
$開始的表示一個引用,語法格式如下
$(FUNCTION ARGUMENTS)
or ${FUNCTION ARGUMENTS}
FUNCTION 是需要調用的函數名,應該是make的內嵌函數名。用戶自己定義的函數需要通過make的call函數來間接調用。
ARGUMENTS 是函數的參數,參數和函數名直接使用若干空格或者tab字符分割,多個參數之間使用逗號分割
$開頭,使用成對的圓括號或花括號把函數名和參數括起來,推薦變量引用和函數引用使用統一的圓括號
2.字符串替換函數—$(subst FROM,TO,TEXT)
$(subst ee,EE,feet on the street)結果爲字符串“fEEt on the strEEt"
3.模式替換函數-- $(patsubst PATTERN,REPLACEMENT,TEXT)
$(patsubst %.c,%.o,x.c.c bar.c) 結果爲 x.c.o bar.o
4.去空格函數 $(strip STRINT)
STR =a b c
LOSTR = $(strip $(STR))
結果爲 a b c5.查找字符串函數 $(findstring FIND,IN)
$(findstring a,a b c)
$(findstring a,b c)
第一個函數結果是字“a”;第二個值爲空字符。

6.過濾函數 $(filter PATTERN...,TEXT)
sources := foo.c bar.c baz.s ugh.h
$(filter %.c %.s,$(sources))
函數返回值爲 foo.c bar.c baz.s
7.反過濾函數 $(filter-out PATTERN...,TEXT)
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
$(filter-out $(mains),$(objects))
函數返回值爲 foo.o bar.o
8.排序函數 $(sort LIST)
$(sort foo bar lose foo)
返回值 bar foo lose
9.取單詞函數 $(word N,TEXT)
$(word 2, foo bar baz)
返回值爲 bar
10.取字串函數 $(wordlist S,E,TEXT)
$(wordlist 2, 3, foo bar baz)
返回值是: bar baz
11.統計單詞數目函數 $(words TEXT)
$(words, foo bar)
返回值是2
12.取首單詞函數 $(firstword NAMES...)
$(firstword foo bar yes)
返回值是foo
13.取目錄函數 $(dir NAMES...)
$(dir src/foo.c hacks)
返回值爲 src/ ./
14.取文件名函數 $(notdir NAMES...)
$(notdir src/foo.c hacks)
返回值爲 foo.c hacks15.取後綴函數 $(suffix NAMES...)
$(suffix src/foo.c src-1.0/bar.c hacks)
返回值爲“.c .c”
16.取前綴函數 $(basename NAMES...)
$(basename src/foo.c src-1.0/bar.c /home/jack/.font.cache-1 hacks)
返回值爲:“src/foo src-1.0/bar /home/jack/.font hacks”
17.加後綴函數 $(addsuffix SUFFIX,NAMES...)
$(addsuffix .c,foo bar)
返回值爲“foo.c bar.c”
18.加前綴函數 $(addprefix PREFIX,NAMES...)
$(addprefix src/,foo bar)
返回值爲“src/foo src/bar”
19.單詞連接函數 $(join LIST1,LIST2)
$(join a b , .c .o)
返回值爲:“a.c b.o”
$(join a b c , .c .o)
返回值爲:“a.c b.o c”
20.獲取匹配模式文件名函數 $(wildcard PATTERN)
$(wildcard *.c)
返回值爲當前目錄下所有.c 源文件列表。
21.foreach 函數 是一個循環函數,類似於shell中的for語句
$(foreach VAR,LIST,TEXT)
函數功能:首先展開變量VAR和LIST的引用,執行時把LIST中使用空格分割的單詞依次取出賦值給變量VAR,然後執行TEXT表達式。
重複直到LIST的最後一個單詞
dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
TEXT 表達式爲“$(wildcard $(dir)/*)”,第一次執行時將展開爲“$(wildcard a/*)”;第二次將展開爲“$(wildcard b/*)”
依次類推。
22.if函數
提供了一個在函數上下文中實現條件判斷的功能
$(if CONDITION,THEN-PART[,ELSE-PART])
$(if $(SRC_DIR) $(SRC_DIR),/home/src)
函數結果是:如果SRC_DIR變量值不爲空,則將變量SRC_DIR指定的目錄作爲一個子目錄;否則將目錄/home/src作爲一個子目錄
23.call函數
call函數是唯一一個可以創建定製化參數函數的引用函數。使用這個函數可以實現對用戶自己定義函數的引用。
我們可以將一個變量定義爲一個複雜的表達式,用call函數根據不同的參數對它進行展開來獲得不同的結果。
$(call VARIABLE,PARAM,PARAM,...)
函數功能:執行時,將它的參數“PARAM“依次賦值給臨時變量$(1) $(2)...這些臨時變量定義在VARIABLE的值中,call函數對參數
的數目沒有限制,也可以沒有參數,沒有參數值的call沒有任何實際存在的意義。執行時變量VARIABLE被展開爲在函數上下文有效的臨時
變量,變量定義中的$(1)作爲第一個參數,並將參數中的第一個參數賦值給它;變量中的$(2)一樣被賦值爲第二個參數值。
$(0)代表變量VARIABLE本身。之後對變量VARIABLE表達式計算值。
reverse = $(2) $(1)
foo = $(call reverse,a,b)
變量foo的值爲 ba,這裏變量reverse中的參數定義順序可以根據需要來調整,並不是需要按照 $(1) $(2) $(3)這樣的順序來定義。
24.value函數
$(value VARIABLE)
函數功能:不對變量VARIABLE進行任何展開操作,直接返回變量VARIABLE的值,這裏VARIABLE是一個變量名,一般不包含$,除非計算的
變量名。
返回值:變量VARIABLE所定義的文本值,如果變量定義爲遞歸展開式,其中包含對其他變量或者函數的引用,那麼函數不對這些引用進行
展開。函數的返回值是包含有引用值。
# sample Makefile
FOO = $PATH
all:
@echo $(FOO)
@echo $(value FOO)
執行make,結果爲:第一行爲ATH,因爲變量FOO定義爲$PATH,所以展開爲ATH $P爲空。
第二行纔是我們需要顯示的環境變量PATH 的值。value函數得到變量FOO的值$PATH25.eval函數
函數功能:函數“eval”是一個比較特殊的函數。使用它可以在Makefile中構造一個可變的規則結構關係(依賴關係鏈),其中可以
使用其它變量和函數。函數“eval”對它的參數進行展開,展開的結果作爲Makefile的一部分,make可以對展開內容進行語法解析。
展開的結果可以包含一個新變量、目標、隱含規則或者是明確規則等。也就是說此函數的功能主要是:根據其參數的關係、結構,對
它們進行替換展開。
返回值:函數“eval”的返回值時空,也可以說沒有返回值。
函數說明:“eval”函數執行時會對它的參數進行兩次展開。第一次展開過程發是由函數本身完成的,第二次是函數展開後的結果被
作爲Makefile內容時由make解析時展開的。明確這一過程對於使用“eval”函數非常重要。理解了函數“eval”二次展開的過程後。
實際使用時,如果在函數的展開結果中存在引用(格式爲:$(x)),那麼在函數的參數中應該使用“$$”來代替“$”。因爲這一點,
所以通常它的參數中會使用函數“value”來取一個變量的文本值。
26.origin函數
函數origin和其他函數不同,函數origin的動作不是操作變量,它只是獲取此變量相關的信息,告訴我們這個變量的出處。
函數語法:$(origin VARIABLE)
函數功能:函數origin查詢參數 VARIABLE(一個變量名)的出處。
函數說明:VARIABLE是一個變量名而不是一個變量的引用。因此通常它不包含$(計算的變量名例外)
返回值: 返回VARIABLE 的定義方式。用字符串表示
函數的返回情況有以下幾種:

1. undefined 變量“VARIABLE”沒有被定義。

2. default 變量“VARIABLE”是一個默認定義(內嵌變量)。如“CC”、“MAKE”、“RM”等變量。
如果在Makefile中重新定義這些變量,函數返回值將相應發生變化。

3. environment 變量“VARIABLE”是一個系統環境變量,並且make沒有使用命令行選項“-e”
(Makefile中不存在同名的變量定義,此變量沒有被替代)。
4. environment override 變量“VARIABLE”是一個系統環境變量,並且make使用了命令行選項“-e”。
Makefile中存在一個同名的變量定義,使用“make -e”時環境變量值替代了文件中的變量定義。
5. file 變量“VARIABLE”在某一個makefile文件中定義。
6. command line 變量“VARIABLE”在命令行中定義。
7. override 變量“VARIABLE”在makefile文件中定義並使用“override”指示符聲明。
8. automatic 變量“VARIABLE”是自動化變量。27.shell 函數
shell函數不同於除“wildcard”函數之外的其它函數。make可以使用它來和外部通信
函數功能:函數“shell”所實現的功能和shell中的引用(``)相同。實現對命令的擴展。這就意味着需要一個shell 命令作爲此
函數的參數,函數的返回結果是此命令在shell中的執行結果。make僅僅對它的回返結果進行處理;make將函數返回結果中的所有
換行符(“\n”)或者一對“\n\r”替換爲單空格;並去掉末尾的回車符號(“\n”)或者“\n\r”。進行函數展開式時,它所調用的
命令(它的參數)得到執行。除對它的引用出現在規則的命令行和遞歸變量的定義中以外,其它決大多數情況下,make是在讀取
解析Makefile時完成對函數shell的展開。
返回值:函數“shell”的參數(一個shell命令)在shell環境中的執行結果。
函數說明:函數本身的返回值是其參數的執行結果,沒有進行任何處理。對結果的處理是由make進行的。當對函數的引用出現在規則
的命令行中,命令行在執行時函數才被展開。展開時函數參數(shell命令)的執行是在另外一個shell進程中完成的,因此需要對
出現在規則命令行的多級“shell”函數引用需要謹慎處理,否則會影響效率(每一級的“shell”函數的參數都會有各自的shell進程)。

contents := $(shell cat foo)
將變量“contents”賦值爲文件“foo”的內容,文件中的換行符在變量中使用空格代替。
28,make的控制函數
$(error TEXT...)
函數功能:產生致命錯誤,並提示“TEXT…”信息給用戶,並退出make的執行。需要說明的是:“error”函數是在函數展開式
(函數被調用時)才提示信息並結束make進程。因此如果函數出現在命令中或者一個遞歸的變量定義中時,在讀取Makefile時
不會出現錯誤。而只有包含“error”函數引用的命令被執行,或者定義中引用此函數的遞歸變量被展開時,纔會提示致命信息“TEXT…”
同時退出make。
返回值:空
函數說明:“error”函數一般不出現在直接展開式的變量定義中,否則在make讀取Makefile時將會提示致命錯誤。
29. $(warning TEXT…)
功能:函數“warning”類似於函數“error”,區別在於它不會導致致命錯誤(make不退出),而只是提示“TEXT…”,make的
執行過程繼續。
返回值:空
函數說明:用法和“error”類似,展開過程相同。
五、make的執行
1.目標就是make最終所要重建的Makefile某個規則的目標,它的重建,會觸發它的依賴或者依賴的依賴文件被重建的過程。可以使用make TARGET_NAME 如make clean,
可以把這個目標指定爲終極目標。使用這種方式,我們也可以同時指定多個終極目標
2.指定編譯或者創建那些正常編譯過程不能生成的文件,這些文件在Makefile中存在重建規則,但是他們沒有出現在默認終極目標的目標依賴中。
3.在Makefile中,使用變量CFLAGS來指定編譯參數,例如:CFLAGS=-g cc-c $(CFLAGS) foo.c
4.指定執行一個由僞目標定義的若干條命令或者一個空目標文件。部分標準的僞目標和空目標命名
all:作爲Makefile的頂層目標,一般此目標作爲默認的終極目標
clean:這個僞目標定義了一組命令,這些命令的功能是刪除所有由make創建的文件。
print:打印楚所有被更改的源文件列表
dist:爲源文件創建發佈的壓縮包,可以使各種壓縮方式的發佈包
check test:對Makefile最後生成的文件進行檢查
以上這些並不是GNU make規定的,可以在Makefile中定義任何命名的僞目標,但以上這些作爲一個約定。絕大多數程序員遵循這種約定。
5.make 的命令行選項make所支持的命令行選項如下:
-b
-m
忽略提供其他版本make的兼容性
-B
--always-make
強制重建所有規則的目標,不根據規則的依賴描述決定是否重建目標文件。
-C DIR
--directory=DIR
在讀取Makefile之前,進入目錄DIR,就是切換工作目錄到DIR之後進行make。
存在多個-C選項時,make的最終工作目錄是第一個目錄的相對路徑 make -C / -C etc等價於 make -C /etc
-d
make在執行過程中打印出所有的調試信息。包括make認爲那些文件需要重建,那些文件需要比較它們最後修改時間,比較結果等等
--dubug【=OPTIONS】
make執行時輸出調試信息。可以使用OPTIONS 控制調試信息級別。默認是OPTIONS=b,OPTIONS可能值爲以下這些,首字母有效
a(all) 輸出所有類型的調試信息,等效於-d選項
b(basic)輸出基本調試信息。包含那些目標過期是否重建成功過期目標文件
v(verbose) basic級別以上的輸出信息。包含解析的makefile文件名,不需要重建文件等。
i(implicit)輸出所有使用到的隱含規則描述。此選項目默認打開basic級別的調試信息
j(jobs) 輸出所有執行命令的子進程,包含命令執行的PID等
m(makefile) 輸出make讀取makefile,更新makefile,執行makefile的信息
-e(--environment-overrides)使用系統環境變量的定義覆蓋Makefile中的同名變量定義
-f=FILE
--file=FILE 指定FILE爲make執行的makefile 文件。
-h --help 打印幫助信息
-i --ignore-errors 執行過程中忽略規則命令執行的錯誤
-I DIR
--include-dir=DIR 指定被包含makefile文件的搜索目錄。
-j --jobs 指定可同時執行的命令數目
-K --keeping 執行命令錯誤時不終止make的執行,make盡最大可能的執行所有的命令,直到出現致命錯誤才終止。
除此之外,還有很多選項幫助我們得到所需要的信息,我們可以通過man手冊查看。

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