make及Makefile學習筆記

make常用參數

-f or --file  指定Makefile
-I or --include-dir  指定include文件的搜索路徑。如果沒找到,會產生警告,完成Makefile的讀取後,
會再次嘗試查找,如果還是找不到,make將產生致命信息。
通配符  *  ?  [...]
-n or --just-print  只顯示命令,但不會執行命令,多用於調試Makefile
-s or --silent   全面禁止命令的顯示
-t or --touch    把目標文件的時間更新,但不更改目標文件。也就是說,make假裝編譯目標,但不是真正的編譯目標,只是把目標變爲已編譯過的狀態。
-C or --directory=<dir>  進入—C指定的目錄,然後執行make
-i or --ignore-errors   執行時忽略所有的錯誤
-k or --keep-going     出錯也不停止運行。如果生成一個目標失敗了,那麼依賴於其上的目標就不會被執行了。
-w or --print-directory      輸出運行Makefile之前和之後的信息。這個參數對應跟蹤嵌套式調用make時很有用。

Makefile常用命令

-   忽略後面命令執行時產生的錯誤,繼續執行
@   後面跟的命令將不被make顯示出來。

include foo.make a.mk $(bar)


vpath <pattern> <dir>:爲符合模式<pattern>的文件指定搜索目錄<dir>
vpath <pattern>:清除符合模式<pattern>的文件的搜索目錄
vpath:清除所有已被設置好了的文件搜索目錄

vpath使用方法中的<pattern>需要包含“%”字符,表示匹配零或若干字符。<dir>可用“:”指定多個搜索目錄,按先後順序搜索。

export:將變量傳遞到下級Makefile
unexport

override:如果有變量是通過make的命令行參數設置的,那麼Makefile中對這個變量的賦值會被忽略,使用override指示符可設置這類參數的值。
override <variable> = <value>
override <variable> := <value>
override <variable> += <more text>

make工作時的執行步驟

1、讀入所有的Makefile
2、讀入被include的其他Makefile
3、初始化文件中的變量
4、推導隱晦規則,並分析所有規則
5、爲所有的目標文件創建依賴關係鏈
6、根據依賴掛關係,決定哪些目標要重新生成
7、執行生成命令
1-5步爲第一個階段,6-7爲第二個階段。第一個階段中,如果定義的變量被使用了,那麼,make會把其展開在使用的位置。但make並不會完全馬上展開,make使用的是拖延戰術,如果變量出現在依賴關係的規則中,那麼僅當這條依賴被決定要使用了,變量纔會在其內部展開。


make命令執行後有三個退出碼:
0 —— 表示成功執行。
1 —— 如果make運行時出現任何錯誤,其返回1。
2 —— 如果你使用了make的“-q”選項,並且make使得一些目標不需要更新,那麼返回2。


自動頭文件依賴

對C/C++編譯器都支持“-M”的選項,即自動尋找源文件中包含的頭文件,並生成一個依賴關係。對GNU的C/C++編譯器,使用“-MM”參數,使用“-M”參數時會將一些標準庫的頭文件也包含進來。

定義命令包

define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

foo.c : foo.y
$(run-yacc)

變量定義

變量定義:   =   :=   +=   ?=
變量替換: 
foo := a.o b.o c.o
bar := $(foo:.o=.c)
bar := $(foo:%.o=%.c)

定義值爲空格的變量:
nullstring :=
space := $(nullstring) # end of the line


目標變量:作用範圍只在這條規則以及連帶規則中
<target ...> : <variable-assignment>
<target ...> : overide <variable-assignment>
<variable-assignment>可以使各種賦值表達式,如"="、":="、"+="、"?="

條件表達式

<conditional-directive>
<text-if-true>
endif


<conditional-directive>
<text-if-true>
else
<text-if-false>
endif

<conditional-directive>:ifeq, ifneq, ifdef, ifndef

函數

$(<function> <arguments> or ${<function> <arguments>}

$(subst <from>,<to>,<text> ) 
名稱:字符串替換函數——subst。
功能:把字串<text>中的<from>字符串替換成<to>。
返回:函數返回被替換過後的字符串。

$(patsubst <pattern>,<replacement>,<text> )
名稱:模式字符串替換函數——patsubst。功能:查找<test>中的單詞(單詞以“空格”、“Tab”或“回車”“換行”分隔)是否符合模式<pattern>,如果匹配的話,則以<replacement>替換。這裏,<pattern>可以包括通配符"%",表示任意長度的字串。如果<replacement>中也包含“%”,那麼,<replacement>中的這個“%”將是<pattern>中的那個“%”所代表的字串。(可以用“/”來轉義,以“/%”來表示真實含義的“%”字符)
返回:函數返回被替換過後的字符串。

$(strip <string> )
名稱:去空格函數——strip。
功能:去掉<string>字串中開頭和結尾的空字符。
返回:返回被去掉空格的字符串值。

$(findstring <find>,<in> )
名稱:查找字符串函數——findstring。
功能:在字串<in>中查找<find>字串。
返回:如果找到,那麼返回<find>,否則返回空字符串。

$(filter <pattern...>,<text> )
名稱:過濾函數——filter。
功能:以<pattern>模式過濾<text>字符串中的單詞,保留符合模式<pattern>的單詞。可以有多個模式。
返回:返回符合模式<pattern>的字串。

$(filter-out <pattern...>,<text> )
名稱:反過濾函數——filter-out。
功能:以<pattern>模式過濾<text>字符串中的單詞,去除符合模式<pattern>的單詞。可以有多個模式。
返回:返回不符合模式<pattern>的字串。

$(sort <list> )
名稱:排序函數——sort。
功能:給字符串<list>中的單詞排序(升序)。
返回:返回排序後的字符串。
示例:$(sort foo bar lose)返回“bar foo lose” 。
備註:sort函數會去掉<list>中相同的單詞。

$(word <n>,<text> )
名稱:取單詞函數——word。
功能:取字符串<text>中第<n>個單詞。(從一開始)
返回:返回字符串<text>中第<n>個單詞。如果<n>比<text>中的單詞數要大,那麼返回空字符串。
示例:$(word 2, foo bar baz)返回值是“bar”。

$(wordlist <s>,<e>,<text> ) 
名稱:取單詞串函數——wordlist。
功能:從字符串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個數字。返回:返回字符串<test>中從<s>到<e>的單詞字串,如果<s>比<test>中的單詞數要大,那麼返回空字符串。如果<e>大於<test>的單詞數,那麼返回從<s>開始,到<text>結束的單詞串。
示例: $(wordlist 2, 3, foo bar baz)返回值是“bar baz”。

$(words <text> )
名稱:單詞個數統計函數——words。
功能:統計<text>中字符串中的單詞個數。
返回:返回<text>中的單詞數。
示例:$(words, foo bar baz)返回值是“3”。
備註:如果我們要取<text>中最後的一個單詞,我們可以這樣:$(word $(words <text> ),<text> )。

$(firstword <text> )
名稱:首單詞函數——firstword。
功能:取字符串<text>中的第一個單詞。
返回:返回字符串<text>的第一個單詞。
示例:$(firstword foo bar)返回值是“foo”。
備註:這個函數可以用word函數來實現:$(word 1,<text> )。

$(dir <names...> ) 
名稱:取目錄函數——dir。
功能:從文件名序列<names>中取出目錄部分。目錄部分是指最後一個反斜槓(“/”)之前的部分。如果沒有反斜槓,那麼返回“./”。
返回:返回文件名序列<names>的目錄部分。
示例: $(dir src/foo.c hacks)返回值是“src/ ./”。

$(notdir <names...> ) 
名稱:取文件函數——notdir。
功能:從文件名序列<names>中取出非目錄部分。非目錄部分是指最後一個反斜槓(“/”)之後的部分。
返回:返回文件名序列<names>的非目錄部分。
示例: $(notdir src/foo.c hacks)返回值是“foo.c hacks”。

$(suffix <names...> ) 
名稱:取後綴函數——suffix。
功能:從文件名序列<names>中取出各個文件名的後綴。
返回:返回文件名序列<names>的後綴序列,如果文件沒有後綴,則返回空字串。
示例:$(suffix src/foo.c src-1.0/bar.c hacks)返回值是“.c .c”。


$(basename <names...> )
名稱:取前綴函數——basename。
功能:從文件名序列<names>中取出各個文件名的前綴部分。
返回:返回文件名序列<names>的前綴序列,如果文件沒有前綴,則返回空字串。
示例:$(basename src/foo.c src-1.0/bar.c hacks)返回值是“src/foo src-1.0/bar hacks”。

$(addsuffix <suffix>,<names...> ) 
名稱:加後綴函數——addsuffix。
功能:把後綴<suffix>加到<names>中的每個單詞後面。
返回:返回加過後綴的文件名序列。
示例:$(addsuffix .c,foo bar)返回值是“foo.c bar.c”。

$(addprefix <prefix>,<names...> ) 
名稱:加前綴函數——addprefix。
功能:把前綴<prefix>加到<names>中的每個單詞後面。
返回:返回加過前綴的文件名序列。
示例:$(addprefix src/,foo bar)返回值是“src/foo src/bar”。

$(join <list1>,<list2> )
名稱:連接函數——join。
功能:把<list2>中的單詞對應地加到<list1>的單詞後面。如果<list1>的單詞個數要比<list2>的多,那麼,<list1>中的多出來的單詞將保持原樣。如果<list2>的單詞個數要比<list1>多,那麼,<list2>多出來的單詞將被複制到<list2>中。
返回:返回連接過後的字符串。
示例:$(join aaa bbb , 111 222 333)返回值是“aaa111 bbb222 333”。

$(foreach <var>,<list>,<text> )
這個函數的意思是,把參數<list>中的單詞逐一取出放到參數<var>所指定的變量中,然後再執行<text>所包含的表達式。每一次<text>會返回一個字符串,循環過程中,<text>的所返回的每個字符串會以空格分隔,最後當整個循環結束時,<text>所返回的每個字符串所組成的整個字符串(以空格分隔)將會是foreach函數的返回值。
所以,<var>最好是一個變量名,<list>可以是一個表達式,而<text>中一般會使用<var>這個參數來依次枚舉<list>中的單詞

$(if <condition>,<then-part> )
$(if <condition>,<then-part>,<else-part> )

$(call <expression>,<parm1>,<parm2>,<parm3>...)

$(origin <variable> )
“undefined”:如果<variable>從來沒有定義過,origin函數返回這個值“undefined”。
“default”:如果<variable>是一個默認的定義,比如“CC”這個變量,這種變量我們將在後面講述。
“environment”:如果<variable>是一個環境變量,並且當Makefile被執行時,“-e”參數沒有被打開。
“file”:如果<variable>這個變量被定義在Makefile中。
“command line”:如果<variable>這個變量是被命令行定義的。
“override”:如果<variable>是被override指示符重新定義的。
“automatic”:如果<variable>是一個命令運行中的自動化變量。關於自動化變量將在後面講述。

shell函數
contents := $(shell cat foo)
files := $(shell echo *.c)

控制make的函數
$(error <text ...> )
$(warning <text ...> )

隱含規則使用的變量(命令相關)

AR:函數庫打包程序。默認命令是“ar”。 
AS:彙編語言編譯程序。默認命令是“as”。
CC:C語言編譯程序。默認命令是“cc”。
CXX:C++語言編譯程序。默認命令是“g++”。
CO:從 RCS文件中擴展文件程序。默認命令是“co”。
CPP:C程序的預處理器(輸出是標準輸出設備)。默認命令是“$(CC) –E”。
FC:Fortran 和 Ratfor 的編譯器和預處理程序。默認命令是“f77”。
GET:從SCCS文件中擴展文件的程序。默認命令是“get”。 
LEX:Lex方法分析器程序(針對於C或Ratfor)。默認命令是“lex”。
PC:Pascal語言編譯程序。默認命令是“pc”。
YACC:Yacc文法分析器(針對於C程序)。默認命令是“yacc”。
YACCR:Yacc文法分析器(針對於Ratfor程序)。默認命令是“yacc –r”。
MAKEINFO:轉換Texinfo源文件(.texi)到Info文件程序。默認命令是“makeinfo”。
TEX:從TeX源文件創建TeX DVI文件的程序。默認命令是“tex”。
TEXI2DVI:從Texinfo源文件創建軍TeX DVI 文件的程序。默認命令是“texi2dvi”。
WEAVE:轉換Web到TeX的程序。默認命令是“weave”。
CWEAVE:轉換C Web 到 TeX的程序。默認命令是“cweave”。
TANGLE:轉換Web到Pascal語言的程序。默認命令是“tangle”。
CTANGLE:轉換C Web 到 C。默認命令是“ctangle”。
RM:刪除文件命令。默認命令是“rm –f”。

隱含規則使用的變量(參數相關)

下面的這些變量都是相關上面的命令的參數。如果沒有指明其默認值,那麼其默認值都是空。
ARFLAGS:函數庫打包程序AR命令的參數。默認值是“rv”。
ASFLAGS:彙編語言編譯器參數。(當明顯地調用“.s”或“.S”文件時)。 
CFLAGS:語言編譯器參數。
CXXFLAGS:C++語言編譯器參數。
COFLAGS:RCS命令參數。 
CPPFLAGS :C預處理器參數。( C 和 Fortran 編譯器也會用到)。
FFLAGS:Fortran語言編譯器參數。
GFLAGS:SCCS “get”程序參數。
LDFLAGS:鏈接器參數。(如:“ld”)
LFLAGS:Lex文法分析器參數。
PFLAGS:Pascal語言編譯器參數。
RFLAGS:Ratfor 程序的Fortran 編譯器參數。
YFLAGS:Yacc文法分析器參數。

自動化變量

$@:表示規則中的目標文件集。在模式規則中,如果有多個目標,那麼,"$@"就是匹配於目標中模式定義的集合。
$%:僅當目標是函數庫文件中,表示規則中的目標成員名。例如,如果一個目標是"foo.a(bar.o)",那麼,"$%"就是"bar.o","$@"就是"foo.a"。如果目標不是函數庫文件(Unix下是[.a],Windows下是[.lib]),那麼,其值爲空。
$<:依賴目標中的第一個目標名字。如果依賴目標是以模式(即"%")定義的,那麼"$<"將是符合模式的一系列的文件集。注意,其是一個一個取出來的。
$?:所有比目標新的依賴目標的集合。以空格分隔。
$^:所有的依賴目標的集合。以空格分隔。如果在依賴目標中有多個重複的,那個這個變量會去除重複的依賴目標,只保留一份。
$+:這個變量很像"$^",也是所有依賴目標的集合。只是它不去除重複的依賴目標。$*:這個變量表示目標模式中"%"及其之前的部分。如果目標是"dir/a.foo.b",並且目標的模式是"a.%.b",那麼,"$*"的值就是"dir/a.foo"。這個變量對於構造有關聯的文件名是比較有較。如果目標中沒有模式的定義,那麼"$*"也就不能被推導出,但是,如果目標文件的後綴是make所識別的,那麼"$*"就是除了後綴的那一部分。例如:如果目標是"foo.c",因爲".c"是make所能識別的後綴名,所以,"$*"的值就是"foo"。這個特性是GNU make的,很有可能不兼容於其它版本的make,所以,你應該儘量避免使用"$*",除非是在隱含規則或是靜態模式中。如果目標中的後綴是make所不能識別的,那麼"$*"就是空值。

當你希望只對更新過的依賴文件進行操作時,"$?"在顯式規則中很有用,例如,假設有一個函數庫文件叫"lib",其由其它幾個object文件更新。那麼把object文件打包的比較有效率的Makefile規則是:
lib : foo.o bar.o lose.o win.o
ar r lib $?
在上述所列出來的自動量變量中。四個變量($@、$<、$%、$*)在擴展時只會有一個文件,而另三個的值是一個文件列表。這七個自動化變量還可以取得文件的目錄名或是在當前目錄下的符合模式的文件名,只需要搭配上"D"或"F"字樣。這是GNU make中老版本的特性,在新版本中,我們使用函數"dir"或"notdir"就可以做到了。"D"的含義就是Directory,就是目錄,"F"的含義就是File,就是文件。


參考

http://wiki.ubuntu.org.cn/%E8%B7%9F%E6%88%91%E4%B8%80%E8%B5%B7%E5%86%99Makefile

















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