1、Makefile用來告訴make命令如何編譯和鏈接文件,規則是:
1) 如果這個工程沒有編譯過,那麼所有C文件都要編譯並被鏈接
2) 如果這個工程的某幾個C文件被修改,那麼我們只編譯被修改的C文件,並鏈接目標程序。
3) 如果這個工程的頭文件被改變了,那麼需要編譯引用了這幾個頭文件的C文件並鏈接目標程序。
2、注意:makefile文件中每行必須要以[table]鍵開始
3、可以使用include標識符,語法是:include <filename>
4、GNU的make工作時的執行步驟如下:
1) 讀入所有的makefile
2) 讀入被include指定的其他makefile
3) 初始化文件中的變量
4) 推導隱晦規則,並分析所有規則
5) 爲所有的目標文件創建依賴關係鏈
6) 根據依賴關係,決定哪些目標要重新生成
7) 執行生成命令
1-5爲第一階段:如果定義的變量被使用了,那麼make會把其展開在使用的位置。
5、在makefile編寫規則中可以使用的通配符:“*”,“?”,“[…]”。
6、特殊變量VPATH,在make尋找文件的依賴關係時,該變量把一個路徑告訴make,讓他自動尋找。(多個目錄之間使用“:”分割)。
7、vpath是make工具的一個關鍵字,比VPATH更靈活:
1)vpath<pattern> <dir>:爲符合模式<pattern>的文件指定搜索目錄
2)vpath<pattern>:清楚符合模式<pattern>的文件的所有目錄
3)vpath:清除所有已被設置好的文件搜索目錄
Vpath使用方法中的<pattern>需要包含“%”字符,表示匹配0或者若干字符(相當與*)。例子:$(objs): %.o: %.c
8、自動化變量:
“$<”:依賴目標中的第一個目標名字。
“$@”: 表示規則中的目標文件集。在模式規則中,如果有多個目標,那麼,"$@"就是匹配於目標中模式定義的集合。
“$%”: 僅當目標是函數庫文件中,表示規則中的目標成員名。例如,如果一個目標是"foo.a (bar.o)",那麼,"$%"就是"bar.o","$@"就是"foo.a"。如果目標不是函數庫文件(Unix下是[.a],Windows 下是[.lib]),那麼,其值爲空。
“$?”: 所有比目標新的依賴目標的集合,以空格分隔。
“$^”:所有的依賴目標的集合。以空格分隔。如果在依賴目標中有多個重複的,那個這個變量會去除重複的依賴目標,只保留一份。
“$+”:這個變量很像"$^",也是所有依賴目標的集合。只是它不去除重複的依賴目標。
“$*”:這個變量表示目標模式中"%"及其之前的部分。如果目標是"dir/a.foo.b",並且目標的模式是"a.%.b",那麼,"$*"的值就是"dir/a.foo"。
“$(@D)”:表示"$@"的目錄部分(不以斜槓作爲結尾),如果"$@"值是"dir/foo.o",那麼"$(@D)"
就是"dir",而如果"$@"中沒有包含斜槓的話,其值就是"."(當前目錄)。
“$(@F)”:表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那麼"$(@F)"就是"foo.o","$(@F)"相當於函數"$(notdir$@)"。
9、CFLAGS 表示用於 C 編譯器的選項,
CXXFLAGS 表示用於 C++ 編譯器的選項。這兩個變量實際上涵蓋了編譯和彙編兩個步驟。
CFLAGS: 指定頭文件(.h文件)的路徑,如:CFLAGS=-I/usr/include -I/path/include。同樣地,安裝一個包時會在安裝路徑下建立一個include目錄,當安裝過程中出現問題時,試着把以前安裝的包的include目錄加入到該變量中來。
LDFLAGS:gcc 等編譯器會用到的一些優化參數,也可以在裏面指定庫文件的位置。用法:LDFLAGS=-L/usr/lib -L/path/to/your/lib。每安裝一個包都幾乎一定的會在安裝目錄裏建立一個lib目錄。如果明明安裝了某個包,而安裝另一個包時,它愣是說找不到,可以抒那個包的lib路徑加入的LDFALGS中試一下。
LIBS:告訴鏈接器要鏈接哪些庫文件,如LIBS = -lpthread-liconv
10、參數-M:自動的生成頭文件依賴。GNU的c/c++編譯器使用的是-MM,否則會把一些標準庫的頭文件也包含進來。
11、make會把要執行的命令行在命令執行前輸出到屏幕上,用@字符在命令行前的話這個命令不被make顯示出來。Make –s參數是全面禁止命令的顯示。
12、如果要將變量傳遞到下一級,那麼使用export關鍵字聲明(unexport)。
13、在makefile中如果使用“=”爲變量賦值,可以嵌套賦值(可能產生遞歸出錯),比如:
A=$(b)
B=$(c)
C=”hello”
但是使用“:=”的話就不能這樣賦值了,前邊的變量不能使用後邊的變量,只能使用在前邊已經定義好的變量。
14、“+=”符號給變量追加值,例子:
objs=a.o b.o
objs +=
14、make的系統變量MAKELEVEL表示如果make有一個嵌套執行的動作,那麼這個變量會記錄當前Makefile的調用層數。
15、makefile中的字符串處理函數:
名稱 |
語法 |
功能 |
返回 |
字符串替換函數-subst |
$(subst <from>, <to>, <text>) |
把字符串<text>中的<from>字符串替換成<to> |
函數返回被替換過後的字符串 |
模式字符串替換函數-patsubst |
$(patsubst <pattern>, <repalcement>, <text>) |
查找<text>中的單詞是否符合模式<pattern>,如果匹配的話則以<repalcement>替換 |
函數返回被替換過後的字符串 |
去空格函數-strip |
$(strip <string>) |
去掉<string>字串中開頭和結尾的空字符 |
返回被去掉空格的字符串值 |
查找字符串函數—findstring |
$(findstring <find>,<in>) |
在字串<in>中查找<find>字串 |
如果找到,那麼返回<find>,否則返回空字符串 |
過濾函數—filter |
$(filter <pattern...>,<text>) |
以<pattern>模式過濾<text>字符串中的單詞,保留符合模式<pattern>的單詞。可以有多個模式。 |
返回符合模式<pattern>的字串 |
反過濾函數—filter-out |
$(filter-out <pattern...>,<text>) |
以<pattern>模式過濾<text>字符串中的單詞,去除符合模式<pattern>的單詞。可以有多個模式。 |
返回不符合模式<pattern>的字串 |
排序函數—sort |
$(sort <list>) |
給字符串<list>中的單詞排序(升序) |
返回排序後的字符串(sort 函數會去掉<list>中相同的單詞) |
取單詞函數—word |
$(word <n>,<text>) |
取字符串<text>中第<n>個單詞。(從一開始) |
返回字符串<text>中第<n>個單詞。如果<n>比<text>中的單詞數要大,那麼返 回空字符串。 |
取單詞串函數—wordlist |
$(wordlist <s>,<e>,<text>) |
從字符串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個數字。 |
返回字符串<text>中從<s>到<e>的單詞字串。如果<s>比<text>中的單詞數要大,那麼返回空字符串。如果<e>大於<text>的單詞數,那麼返回從<s>開始,到<text>結束的單詞串。 |
單詞個數統計函數—words |
$(words <text>) |
統計<text>中字符串中的單詞個數(如果我們要取<text>中最後的一個單詞,我們可以這樣:$(word $(words <te xt>),<text>))。 |
返回<text>中的單詞數 |
首單詞函數—firstword |
$(firstword <text>) |
取字符串<text>中的第一個單詞(這個函數可以用 word 函數來實現:$(word 1,<text>)) |
返回字符串<text>的第一個單詞。 |
16、字符串處理函數
名稱 |
語法 |
功能 |
返回 |
取目錄函數—dir |
$(dir <names...>) |
從文件名序列<names>中取出目錄部分。目錄部分是指最後一個反斜槓(“/”)之前的部分。如果沒有反斜槓,那麼返回“./”。 |
返回文件名序列<names>的目錄部分 |
取文件函數—notdir |
$(notdir <names...>) |
從文件名序列<names>中取出非目錄部分。非目錄部分是指最後一個反斜槓(“ /”)之後的部分。 |
返回文件名序列<names>的非目錄部分 |
取後綴函數—suffix |
$(suffix <names...>) |
從文件名序列<names>中取出各個文件名的後綴。 |
返回文件名序列<names>的後綴序列,如果文件沒有後綴,則返回空字串。 |
取前綴函數—basename |
$(basename <names...>) |
從文件名序列<names>中取出各個文件名的前綴部分。 |
返回文件名序列<names>的前綴序列,如果文件沒有前綴,則返回空字串。 |
加後綴函數—addsuffix |
$(addsuffix <suffix>,<names...>) |
把後綴<suffix>加到<names>中的每個單詞後面。 |
返回加過後綴的文件名序列。 |
加前綴函數—addprefix |
$(addprefix <prefix>,<names...>) |
把前綴<prefix>加到<names>中的每個單詞後面 |
返回加過前綴的文件名序列 |
連接函數—join |
$(join <list1>,<list2>) |
把<list2>中的單詞對應地加到<list1>的單詞後面。如果<list1>的單詞個數要比<list2>的多,那麼,<list1>中的多出來的單詞將保持原樣。如果<list2>的單詞個數要比<list1>多,那麼,<list2>多出來的單詞將被複制到<list2>中。 |
返回連接過後的字符串 |
是用來做循環用的函數-foreach |
$(foreach <var>,<list>,<text>) |
把參數<list>中的單詞逐一取出放到參數<var>所指定的變量中,然後再執行<text>所包含的表達式。每一次<text>會返回一個字符串,循環過程中,<text> 的所返回的每個字符串會以空格分隔,最後當整個循環結束時,<text>所返回的每個字符串所組成的整個字符串(以空格分隔)將會是 foreach 函數的返回值。 |
|
if 函數很像 GNU 的 make 所支持的條件語句—ifeq |
$(if <condition>,<then-part>) 或者 $(if <condition>,<then-part>,<else-part>) |
if 函數可以包含“else”部分,或是不含。即 if 函數的參數可以是兩個,也可以是三個。<condition>參數是 if 的表達式,如果其返回的爲非空字符串,那麼這個表達式就相當於返回真,於是,<then-part>會被計算,否則<else-part>會被計算。 |
而 if 函數的返回值是,如果<condition>爲真(非空字符串),那個<then-part>會是整個函數的返回值,如果<condition>爲假(空字符串),那麼<else-part>會是整個函數的返回值,此時如果<else-part>沒有被定義,那麼,整個函數返回空字串。 |
call 函數 |
$(call <expression>,<parm1>, <parm2>,<parm3>...) |
個可以用來創建新的參數化的函數。你可以寫一個非常複雜的表達式,這個表達式中,你可以定義許多參數,然後你可以用 call 函數來向這個表達式傳遞參數。 |
|
origin函數 |
$(origin <variable>) |
並不操作變量的值,他只是告訴你你的這個變量是哪裏來的 |
|
shell 函數 |
它的參數應該就是操作系統 Shell 的命令。它和反引號“`”是相同的功能。這就是說,shell 函數把執行操作系統命令後的輸出作爲函數返回。於是,我們可以用操作系統命令以及字符串處理命令 awk,sed 等等命令來生成一個變量 |
|
|
控制make 的函數 |
make 提供了一些函數來控制 make 的運行。通常,你需要檢測一些運行 Makefile 時的 運行時信息,並且根據這些信息來決定,你是讓 make 繼續執行,還是停止。 |
|
17、make的命令執行後有三個退出碼:
0-表示執行成功
1- 如果make運行時出現任何錯誤,返回1
2- 如果使用了make的-q選項,並且make使得一些目標不需要更新,那麼返回2.
18、GNU make 找尋默認的Makefile 的規則是在當前目錄下依次找三個文件“GNUmakefile”、“makefile”和“Makefile”。其按順序找這三個文件,一旦找到,就開始讀取這個文件並執行。也可以使用”-f”或者是”--file”指定make執行的文件。