在閱讀大型工程C源碼時不可避免的須要瞭解makefile文件,它定義了源文件的編譯規則和連接規則,是閱讀與編寫源碼都必須瞭解的知識,本文經過學習陳皓寫的一份makefile中文教程,將其要點梳理以下,以備本身回顧之用。原始教程請參考陳皓博客或直接下載網友作好的PDF教程,直接百度便可。web
1、概念shell
一個工程中的源文件不計數,其按類型、功能、模塊分別放在若干個目錄中,makefile 定義了一系列的規則來指定,哪些文件須要先編譯,哪些文件須要後編譯,哪些文件須要從新編譯,甚至於進行更復雜的功能操做。express
make 是一個命令工具,是一個解釋 makefile 中指令的命令工具。數組
2、語法ide
2.1格式與組成函數
格式以下:工具
target ... : prerequisites ...
command
說明:這是一個文件的依賴關係,也就是說,target 這一個或多個的目標文件依賴於 prerequisites 中的文件,其生成規則定義在 command 中。說白一點就是說, prerequisites 中若是有一個以上的文件比 target 文件要新的話,command 所定義的命令就會被執行。這就是 Makefile 的規則。命令必須以tab開頭。學習
組成:測試
Makefile 裏主要包含了五個東西:顯式規則、隱晦規則、變量定義、文件指示和註釋。顯式規則就是咱們定義出來的,隱晦規則即自動推導規則(make 看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關係中),支持變量定義相似於宏替換,註釋提升可讀性,文件指示包括:引入其餘makefile文件,指定makefile的有效部分,定義一個多行命令。ui
2.2規則
2.2.1規則的語法
targets : prerequisites
command
...
或是這樣:
targets : prerequisites ; command
command
2.2.2 文件搜索
(1)當 make 須要去找尋文件的依賴關係時,你能夠在文件前加上路徑,但最好的方法是把一個路徑告訴 make,讓make 自動去找。特殊變量「VPATH」就是完成這個功能的(如:VPATH = src:../headers,目錄用冒號分隔),make在當前目錄找不到就到變量VPATH路徑下找。
(2)另外一個設置文件搜索路徑的方法是使用 make 的「vpath」關鍵字 (注意,它是全小寫的),格式爲:vpath <pattern> <directories>,表示在directories下搜索符合pattern模式的文件。其中pattern須要使用%符號,用於表示匹配0或若干個字符。
2.2.3 多目標與靜態模式
Makefile 的規則中的目標能夠不止一個,其支持多目標。固然,多個目標的生成規則的執行命令是同一個,不過好在咱們的可使用一個自動化變量「$@」,它表示目前規則中全部目標的集合。示例參見第三節例1.
靜態模式能夠更加容易地定義多目標的規則,語法以下
<targets ...>: <target-pattern>: <prereq-patterns ...>
<commands>
...
target-parrtern 指明瞭 targets 的模式,也就是的目標集模式。prereq-parrterns 是目標的依賴模式,它對 target-parrtern 造成的模式再進行一次依賴目標的定義。參見第三節例2。
2.2.4 自動生成依賴性
在添加刪除頭文件時,須要修改makefile文件內容,這是繁瑣且易錯的,因此大多數的C/C++編譯器都支持一個「-M」的選項,即自動找尋源文件中包含的頭文件,並生成一個依賴關係。而爲了將編譯器自動生成的依賴關係文件與makefile關聯起來,GNU 組織建議把編譯器爲每個源文件自動生成的依賴關係放到一個文件中,如爲「name.c」生成一個「name.d」的 Makefile 文件,[.d]文件中存放着對應[.c]文件的依賴關係,以後將.d文件包含在咱們的主 Makefile 中,從而自動化地生成每一個文件的依賴性。
產生[.d]文件的模式規則見第三節例3。
2.2.5命令的關聯
若是但願第二條命令在第一條命令的基礎上執行,那麼這兩條命令應該寫在同一行,用分號分隔,而不能寫在兩行。
2.2.6 隱含規則
「隱含規則」是一種慣例,若是咱們不明確地寫下規則,那麼,make 就會在這些內建的規則中尋找所須要的規則和命令。「隱含規則」會使用一些咱們系統變量,咱們能夠改變這些系統變量的值來定製隱含規則的運行時的參數;咱們還能夠經過「模式規則」的方式寫下本身的隱含規則。若是你確實不但願任何隱含規則推導,那麼,你就不要只寫出「依賴規則」,而不寫命令。
(1)隱含規則中所用到的變量
在隱含規則中的命令,基本上都是使用了一些預先設置的變量。一、你能夠在你的 makefile 中改變這些變量的值,二、或是在 make 的命令行中傳入這些值,三、或是在你的環境變量中設置這些值,固然,四、你也能夠利用 make 的「-R」或「--no–builtin-variables」參數來取消你所定義的變量對隱含規則的做用。
Make爲不一樣語言創建了不一樣的編譯連接隱含規則,而這些規則都有自身所用到的命令變量和命令參數變量,經過改變這些變量的值能夠改變隱含規則的執行方式。
下面列出常見隱含規則:
語言 |
推導規則 |
生成的命令 |
編譯C |
「<n>.o」目標的依賴目標會自動推導爲「<n>.c」 |
$(CC) –c $(CPPFLAGS) $(CFLAGS) |
編譯 C++ |
「<n>.o」的目標的依賴目標會自動推導爲「<n>.cc」或是「<n>.C」 |
$(CXX) –c (CPPFLAGS) $(CFLAGS) |
編譯 Pascal |
「<n>.o」的目標的依賴目標會自動推導爲「<n>.p」 |
$(PC) –c $(PFLAGS) |
編譯 Fortran /Ratfor |
「<n>.o」的目標的依賴目標會自動推導爲「<n>.r」或「<n>.F」或「<n>.f」 |
「.f」 「$(FC) –c $(FFLAGS)」 「.F」 「$(FC) –c $(FFLAGS) $(CPPFLAGS)」 「.f」 「$(FC) –c $(FFLAGS) $(RFLAGS)」 |
預處理 Fortran/Ratfor |
「<n>.f」的目標的依賴目標會自動推導爲「<n>.r」或「<n>.F」 |
「.F」 「$(FC) –F $(CPPFLAGS) $(FFLAGS)」 「.r」 「$(FC) –F $(FFLAGS) $(RFLAGS)」 |
編譯 Modula-2 |
「<n>.sym」的目標的依賴目標會自動推導爲「<n>.def」 「<n.o>」 的目標的依賴目標會自動推導爲 「<n>.mod」 |
$(M2C) $(M2FLAGS) $(DEFFLAGS)
$(M2C) $(M2FLAGS) $(MODFLAGS) |
彙編和彙編預處理 |
「<n>.o」 的目標的依賴目標會自動推導爲「<n>.s」 默認使用 C 預編譯器「cpp」 |
$(AS) $(ASFLAGS)
$(AS) $(ASFLAGS) |
連接 Object 文件 |
「<n>」目標依賴於「<n>.o」,經過運行 C 的編譯器來運行連接程序生成( 一 般 是 「ld」 ) |
$(CC) $(LDFLAGS) <n>.o $(LOADLIBES) $(LDLIBS) |
…… |
|
|
下面列出隱含規則中所用到的變量:包括命令變量和參數變量兩種
命令變量 |
說明 |
命令參數變量 |
說明(沒指明默認值爲空) |
AR |
函數庫打包程序 |
ARFLAGS |
AR 命令的參數。默認值是「rv」。 |
AS |
彙編語言編譯程序 |
ASFLAGS |
彙編語言編譯器參數。 |
CC |
C 語言編譯程序 |
CFLAGS |
C 語言編譯器參數。 |
CXX |
C++語言編譯程序 |
CXXFLAGS |
C++語言編譯器參數。 |
CO |
從 RCS 文件中擴展文件程序 |
COFLAGS |
RCS 命令參數。 |
CPP |
C 程序的預處理器 |
CPPFLAGS |
C /Pascal預處理器參數。 |
FC |
Fortran 和 Ratfor 的編譯器和預處理程序 |
FFLAGS |
Fortran 語言編譯器參數。 |
GET |
從 SCCS 文件中擴展文件的程序 |
GFLAGS |
SCCS 「get」程序參數。 |
PC |
Pascal 語言編譯程序 |
PFLAGS |
Pascal 語言編譯器參數。 |
LEX |
Lex 方法分析器程序(針對於 C 或 Ratfor) |
LFLAGS |
Lex 文法分析器參數。 |
YACC |
Yacc 文法分析器(針對於 C 程序) |
YFLAGS |
Yacc 文法分析器參數。 |
YACCR |
Yacc 文法分析器(針對於 Ratfor 程序) |
|
|
TEX |
從 TeX 源文件建立 TeX DVI 文件的程序 |
|
|
RM |
刪除文件命令 |
|
|
… |
|
LDFLAGS |
連接器參數。(如:「ld」) |
(2)模式規則
可使用模式規則來定義一個隱含規則。模式規則中,至少在規則的目標定義中要包含"%",不然,就是通常的規則。若是"%"定義在目標中,那麼,目標中的"%"的值決定了依賴目標中的"%"的值。示例以下:
%.tab.c %.tab.h: %.y
bison -d $<
說明:這條規則告訴 make 把全部的[.y]文件都以"bison -d <n>.y"執行,而後生成"<n>.tab.c"和"<n>.tab.h"文件。(其中,"<n>"表示一個任意字符串)。
(3)後綴規則
後綴規則是一個比較老式的定義隱含規則的方法。爲了和老版本的Makefile 兼容,GNU make 一樣兼容於這些東西。後綴規則有兩種方式:"雙後綴"和"單後綴"。
雙後綴規則定義了一對後綴:目標文件的後綴和依賴目標(源文件)的後綴。如".c.o"至關於"%o : %c"。單後綴規則只定義一個後綴,也就是源文件的後綴。如".c"至關於"% : %.c"。
後綴規則不容許任何的依賴文件,若是有依賴文件的話,那就不是後綴規則,那些後綴通通被認爲是文件名。
後綴規則中所定義的後綴應該是 make 所認識的,默 認 的 後 綴 列 表是:.out, .a, .ln, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h,.info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web, .sh, .elc, .el。而要讓 make知道一些特定的後綴,咱們可使用僞目標".SUFFIXES"來定義或是刪除,如:.SUFFIXES: .hack .win把後綴.hack 和.win 加入後綴列表中的末尾;.SUFFIXES: # 刪除默認的後綴;SUFFIXES: .c .o .h # 定義本身的後綴。
2.3變量
2.3.1 特殊符號及關鍵字
反斜槓(\):是換行符的意思,當一行過長不方便瀏覽時使用反斜槓換行;另外還有轉義的做用,例外是$,若是想要使用$,須要用$$表示。
橫槓(-):加在命令前,表示也許某些文件出現問題,但不要管,繼續作後面的事。
井號(#):註釋符,makefile只支持單行註釋。可以使用註釋符結合空變量定義一個空格變量:
nullstring :=
space := $(nullstring) # end of the line 其中,nullstring變量什麼都沒有,space爲空格變量。
通配符*,?,[]:*號表示任意字符,?號任意一個字符,[]表示範圍內的字符。
%:表示匹配0或若干字符,用於pattern模式中。
objects := $(wildcard *.o):在變量中使用通配符須要使用關鍵字wildcard指定,不然只會相似於宏替換,不會展開。
Include(filename):把其它makefile文件包含到當前位置,但命令前不能用tab開頭。
VPATH:makefile中的特殊變量,用於指定make對依賴文件的搜索路徑
vpath:make的關鍵字,全小寫。相似於VPATH,但更靈活
override:在makefile中設置make命令中指定的變量的值,當make命令中指定了該變量的值時,makefile中該變量值被忽略。
2.3.2 變量
(1)自定義變量
在 makefile 中咱們可使用變量。makefile 的變量也就是一個字符串,相似於C 語言中的宏。不過變量名能夠是任意大小寫,當定義了變量後,可使用 「$(變量名)」的方式來使用這個變量了,其實就相似於宏替換。
變量的命名能夠包含字符、數字,下劃線(能夠是數字開頭) ,但不該該含有「:」、「#」、「=」或是空字符(空格、回車等)。變量是大小寫敏感的, 推薦使用大小寫搭配的變量名,如:MakeFlags。這樣能夠避免和系統的變量衝突。
在變量賦值時,變量的值能夠是其餘變量的表達式,而其餘變量的定義能夠在文件的任何位置,即不要求其餘變量必定要預先定義。但在遞歸定義時將會出現無限循環,所以引入操做符「:=」來表示只使用預先定義的變量的值,從而避免變量遞歸定義時的無限循環。此外,變量的值能夠是嵌套的變量表達式,其賦值方式就是按宏替換的方式依次展開求值。
變量值替換:1「${var:a=b}」,其意思是,把變量「var」中全部以「a」字串「結尾」的「a」替換成「b」字串;2另一種變量替換的技術是以「靜態模式」(bar := $(foo:%.o=%.c))
變量做用域:makefile中定義的變量都是全局變量(除了自動化變量),也可定義做用於特定目標或模式的局部變量,格式爲:
目標/模式:變量賦值表達式
(2)自動化變量
這種變量會把模式中所定義的一系列的文件自動地挨個取出,直至全部的符合模式的文件都取完了。
$%:僅當目標是函數庫文件時,表示規則中的目標成員名。
$@:表示目前規則中全部的目標的集合
$<:依賴目標中的第一個目標名字。
$?:全部比目標新的依賴目標的集合。以空格分隔。
$^:全部的依賴目標的集合。以空格分隔。
$+:這個變量很像"$^",也是全部依賴目標的集合。只是它不去除重複的依賴目標。
$*:這 個 變 量 表 示 目 標 模 式 中 "%"及 其 之 前 的 部 分 。
這七個自動化變量還能夠取得文件的目錄名或是在當前目錄下的符合模式的文件名, 只須要搭配上"D"或"F"字樣。
(3)命令序列變量
能夠爲命令序列指定一個變量,便於重用。定義方式爲:
define 變量名
命令序列
endef
以後直接按變量引用方式($(變量名))引用便可。
(4)系統變量
MAKEFLAGS:保存make參數信息;
MAKELEVEL:保存了當前makefile在make嵌套執行的調用層數;
CFLAGS:環境變量,若系統環境中設置了該環境變量,則全部makefile文件均可以使用該變量設置的統一參數。若makefile文件中定義了該變量,將覆蓋環境變量中的值。
MAKECMDGOALS:make的環境變量,這個變量中存放所指定的終極目標的列表,若是在命令行上,你沒有指定目標,那麼,這個變量是空值。
2.3.3 僞目標
「僞目標」並非一個文件,只是一個標籤。爲了不和文件重名的這種狀況,咱們可使用一個特殊的標記「.PHONY」來顯示地指明一個目標是「僞目標」,如
.PHONY: clean
clean:
rm *.o temp
僞目標能夠做爲默認目標也能夠有依賴文件,藉由這個特性,咱們能夠一次性生成多個可執行文件。
2.4 表達式
2.4.1 賦值表達式
?=:用於變量定義,表示若是變量沒有被定義,則定義並賦值,若是定義了語句做廢。
+=:用於變量賦值時的追加,若是變量以前沒有定義過,那麼,「+=」會自動變成「=」,若是前面有變量定義,那麼「+=」會繼承於前次操做的賦值符(=或:=)。
2.4.2 條件表達式
格式爲: <conditional-directive> <text-if-true> else <text-if-false> endif
其中<conditional-directive>表示條件關鍵字。這個關鍵字有四個:ifeq、ifneq、ifdef、ifndef。
2.5 函數
2.5.1 調用語法
${<function> <arguments>}
說明:<function>就是函數名,make 支持的函數很少。<arguments>是函數的參數,參數間以逗號「,」分隔,而函數名和參數之間以「空格」分隔。
2.5.2 經常使用函數
類別 |
函數名 |
功能 |
說明 |
字符串函數 |
$(subst <from>,<to>,<text> ) |
把字串<text>中的<from>字符串替換成<to>。 |
函數返回被替換事後的字符串。 |
$(patsubst <pattern>,<replacement>,<text> ) |
查找<text>中的單詞是否符合模式<pattern>,匹配則以<replacement>替換。 |
若是<replacement>中也包含%,那麼這個「%」將是<pattern>中的那個「%」所表明的字串。 |
|
$(strip <string> ) |
去掉<string>字串中開頭和結尾的空字符。 |
函數返回被替換事後的字符串。 |
|
$(findstring <find>,<in> ) |
在字串<in>中查找<find>字串。 |
若是找到,返回<find>,不然返回空字符串。 |
|
$(filter <pattern...>,<text> ) |
以<pattern>模式過濾<text>字符串中的單詞,保留符合<pattern>的單詞。 |
能夠有多個模式。 |
|
$(filter-out <pattern...>,<text> ) |
以<pattern>模式過濾<text>字符串中的單詞,去除符合模式的單詞 |
能夠有多個模式。返回不符合模式<pattern>的字串。 |
|
$(sort <list> ) |
給字符串<list>中的單詞排序(升序) 。 |
sort 函數會去掉<list>中相同的單詞。 |
|
$(word <n>,<text> ) |
取字符串<text>中第<n>個單詞。 (從一開始) |
若是<n>比<text>中的單詞數要大,返回空字符串。 |
|
$(wordlist <s>,<e>,<text> ) |
從字符串<text>中取從<s>開始到<e>的單詞串。 |
若是<s>比<text>中的單詞數要大,返回空字符串。 |
|
$(words <text> ) |
統計<text>中字符串中的單詞個數。 |
取最後一個單詞: $(word $(words <text> ),<text> )。 |
|
$(firstword <text> ) |
取字符串<text>中的第一個單詞。 |
|
|
文件操做函數 |
$(dir <names...> ) |
從文件名序列<names>中取出目錄部分。目錄部分是指最後一個反斜槓(「/」)以前的部分。 |
若是沒有反斜槓,那麼返回「./」 |
$(notdir <names...> ) |
從文件名序列<names>中取出非目錄部分。 |
非目錄部分是指最後一個反斜槓(「/」)以後的部分。 |
|
$(suffix <names...> ) |
從文件名序列<names>中取出各個文件名的後綴。 |
若是文件沒有後綴,則返回空字串。 |
|
$(basename <names...> ) |
從文件名序列<names>中取出各個文件名的前綴部分。 |
|
|
$(addsuffix <suffix>,<names...> ) |
把後綴<suffix>加到<names>中的每一個單詞後面。 |
|
|
$(addprefix <prefix>,<names...> ) |
把前綴<prefix>加到<names>中的每一個單詞後面。 |
|
|
$(join <list1>,<list2> ) |
把<list2>中的單詞對應地加到<list1>的單詞後面。 |
若是<list1>的單詞個數多於<list2>,多出部分保持原樣。反之複製到1中。 |
|
循環 |
$(foreach <var>,<list>,<text> ) |
把<list>中的單詞逐一取出到<var>變量中,再執行<text>包含的表達式。 |
返回值爲text每次執行返回的字符串組合(以空格相隔) |
條件 |
$(if <condition>,<then-part>,<else-part> ) |
|
|
call |
$(call <expression>,<parm1>,<parm2>,<parm3>...) |
<expression>中的變量($(1),$(2)…)會 被 <parm1> , <parm2>…依 次 取 代 。 |
返回值爲<expression>的返回值 |
origin |
$(origin <variable> ) |
返回變量來源 |
返回值爲:undefined,default,environment,file,command line,override,automatic |
Shell函數 |
$(shell 命令) |
它的參數是操做系統Shell 的命令 |
返回值爲shell函數所執行的操做系統命令的輸出 |
控制make的函數 |
$(error <text ...> ) |
產生一個致命的錯誤,<text ...>是錯誤信息。 |
|
$(warning <text ...> ) |
輸出一段警告信息, make 繼續執行。 |
|
2.6 make
2.6.1 指定makefile和目標
(1)指定makefile
make 命令會在當前目錄下按順序找尋文件名爲「GNUmakefile」、「makefile」、「Makefile」的文件,找到了解釋這個文件。若找不到,將會依次到make命令-I參數指定目錄和<prefix>/include(通常是:/usr/local/bin 或/usr/include)目錄查找。若是要指定特定的 Makefile,可使用 make 的「-f」和「--file」參數,如:make -f Make.Linux。
(2)指定目標
通常來講,make 的最終目標是 makefile 中的第一個目標,而其它目標通常是由這個目標連帶出來的。而要指定其餘目標做爲最終目標,在 make 命令後直接跟目標的名字就能夠完成(如前面提到的「makeclean」形式),即便是僞目標和隱含目標均可以做爲最終目標。
GNU目標編寫習慣說明:
僞目標 |
功能 |
all |
全部目標的目標,其功能通常是編譯全部的目標。 |
clean |
刪除全部被 make 建立的文件。 |
Install |
安裝已編譯好的程序,就是把目標執行文件拷貝到指定的目標中去。 |
|
列出改變過的源文件。 |
tar |
把源程序打包備份,也就是一個tar文件。 |
dist |
建立一個壓縮文件,通常是把 tar 文件壓成Z文件或是gz文件。 |
TAGS |
更新全部的目標,以備完整地重編譯使用。 |
check、test |
測試 makefile 的流程。 |
2.6.2 make的參數
下面列舉了全部 GNU make 3.80 版的參數定義:
參數 |
功能 |
-b,-m |
忽略和其它版本 make 的兼容性。 |
-B,--always-make |
認爲全部的目標都須要更新(重編譯) 。 |
-C <dir>, --directory=<dir> |
指定讀取 makefile 的目錄。若是有多個「-C」參數,後面的路徑之前面的做爲相對路徑,並以最後目錄做被指定目錄。 |
—debug[=<options>] |
輸出 make 的調試信息,它有幾種不一樣的級別可供選擇。 |
-e, --environment-overrides |
指明環境變量的值覆蓋 makefile 中定義的變量的值。 |
-f=<file> |
指定須要執行的 makefile。 |
-h |
|
-i |
在執行時忽略全部的錯誤 |
-I <dir> |
指定一個被包含 makefile 的搜索目標。 |
-k |
出錯也不中止運行。 |
-l <load> |
指定 make 運行命令的負載。 |
-n |
僅輸出執行過程當中的命令序列 |
-o <file> |
不從新生成的指定的<file> |
-p |
輸出 makefile 中的全部數據,包括全部的規則和變量。 |
-q |
不運行命令,也不輸出。僅僅是檢查所指定的目標是否須要更新。 |
…… |
|
詳細參數信息能夠查看make幫助文檔。
2.6.3 使用make更新函數庫文件
函數庫文件也就是對 Object 文件(程序編譯的中間文件)打包生成的文件。能夠以以下格式指定函數庫文件及其組成:
${<function> <arguments>}
這不是一個命令,而是一個目標和依賴的定義。若是要指定多個 member,那就以空格分開,如:foolib(hack.o kludge.o)。
2.7其餘
(1)顯示命令:在makefile中的命令前加@符號,則該命令在make執行時將不被顯示在屏幕上;而在make命令中使用參數-n或--just-print,則只在屏幕顯示執行的命令序列,而不會執行命令,經常使用來調試。
(2)環境變量MAKEFILES:相似於include(filename),但環境變量MAKEFILES中的目標(即文件中的第一個標識符)不起做用,且不理會其中定義的文件的錯誤。建議不要使用該環境變量,容易出一些莫名的錯誤。
(3)make 是在讀取 Makefile 時就計算條件表達式的值,並根據條件表達式的值來選擇語句,因此,你最好不要把自動化變量(如「$@」等)放入條件表達式中,由於自動化變量是在運行時纔有的。
(4)make的嵌套執行:大型工程爲了利於模塊編譯和維護,一般會在每個模塊目錄中分別寫上makefile文件,而在總控makefile文件中指定模塊makefile的執行。而總控模塊中的變量能夠經過聲明export variable傳遞到下級的makefile中,但不會覆蓋下級makefile中的變量,直接使用export表示傳遞全部變量。其中變量SHELL和MAKEFLAGS老是會自動傳遞到下層makefile中,而MAKEFLAGS中保存了make參數信息,一旦定義了MAKEFLAGS變量,它將自動傳遞到下級makefile中(除了幾個參數:C,f,h,o,W),若不想傳遞make參數,能夠這樣:
subsystem:
cd subdir && $(MAKE) MAKEFLAGS=
(5)命令出錯:make會檢查每條命令執行後的返回值(),若是不正確則會終止該條規則的執行。1若是不但願命令出錯而終止規則運行,能夠在命令前加一個「-」表示忽略該命令出錯繼續執行後續命令;2也能夠指定make命令參數-i或—ignore-errors表示忽略全部命令的錯誤;3而若是一個規則的目標是.IGNORE,則表示該條規則的全部命令都忽略錯誤。4而若是指定make的參數-k或—keep-going,則表示命令出錯時終止對應規則而繼續執行其餘規則。
3、例子
例1 多目標示例1
bigoutput littleoutput : text.g
generate text.g -$(subst output,,$@) > $@
說明:其中,-$(subst output,,$@)中的「$」表示執行一個 Makefile 的函數,函數名爲 subst,後面的爲參數。這裏的這個函數是截取字符串的意思,「$@」表示目標的集合,就像一個數組,「$@」依次取出目標,並執於命令。
例2 多目標示例2
objects = foo.o bar.o all: $(objects) $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@
說明:上面的例子中,指明瞭咱們的目標從$object 中獲取,「%.o」代表要全部以「.o」結尾的目標,也就是「foo.o bar.o」,也就是變量$object 集合的模式,而依賴模式「%.c」則取模式「%.o」的「%」,也就是「foo bar」,併爲其加下「.c」的後綴,因而,咱們的依賴目標就是「foo.c bar.c」。而命令中的「$<」和「$@」則是自動化變量, 「$<」表示全部的依賴目標集(也就是「foo.c bar.c」) ,「$@」表示目標集(也就是「foo.o bar.o」)。
例3 生成.d文件(源文件的依賴關係文件)的模式規則:
%.d: %.c @set -e; rm -f $@; \ $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$
說明:這個規則的意思是,全部的[.d]文件依賴於[.c]文件,「rm -f $@」的意思是刪除全部的目標,也就是[.d]文件,第二行的意思是,爲每一個依賴文件「$<」, 也就是[.c]文件生成依賴文件, 「$@」表示模式「%.d」文件,若是有一個 C 文件是 name.c,那麼「%」就是「name」,「$$$$」意爲一個隨機編號,第二行生成的文件有多是「name.d.12345」,第三行使用sed 命令作了一個替換,關於 sed 命令的用法請參看相關的使用文檔。第四行就是刪除臨時文件。