學寫makefile(《跟我一起寫Makefile-陳皓》筆記)

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執行的文件。 


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