makefile 相關知識

基本介紹:

GNU的make工作時的執行步驟入下:
1. 讀入所有的Makefile。
2. 讀入被include的其它 Makefile。
3. 初始化文件中的變量。
4. 推導隱晦規則,並分析所有規則。
5. 爲所有的目標文件創建依賴關係鏈。
6. 根據依賴關係,決定哪些目標要重新生成。
7. 執行生成命令。
1-5步爲第一個階段,6-7爲第二個階段。第一個階段中,如果定義的變量被使用了,那麼make會把其展開在使用的位置。

如果變量出現在依賴關係的規則中,那麼僅當這條依賴被決定要使用了,變量纔會在其內部展開。

make的include 關鍵字

在Makefile使用include關鍵字可以把別的Makefile文件包含進來,這很像C語言的#include預編譯指令,被包含的文件會原樣的放在當前文件的包含位置。

make命令開始時會找尋include所指出的其它Makefile,並把其內容安置在當前的位置。就好像C/C++的#include指令一樣。如果文件都沒有指定絕對路徑或是相對路徑的話,make會在當前目錄下首先尋找,如果當前目錄下沒有找到,那麼make還會在其他目錄下找。如果有文件沒有找到的話,make會生成一條警告信息,但不會馬上出現致命錯誤。它會繼續載入其它的文件,一旦完成makefile的讀取,make會再重試這些沒有找到,或是不能讀取的文件,如果還是不行,make纔會出現一條致命信息。如果你想讓make不理那些無法讀取的文件,而繼續執行,你可以在include前加一個減號“-”。

-include<filename> 表示無論include過程中出現什麼錯誤都要繼續執行。和其它版本make兼容的相關命令是 sinclude 其作用也是表示出現找不到文件的情況下make 仍然繼續執行。 在命令前面加 - 表示在執行的過程中即使出現問題也要執行完命令。

此處需要例子進行演示。

make的自動推導

GNU的make可以自動推導文件以及文件依賴關係以及相應的編譯命令,於是我們就沒必要去在每一個[.o]文件後都寫上編譯命令。只要make看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關係中。如果make找到一個whatever.o,那麼whatever.c就會是whatever.o的依賴文件並且編譯命令 cc -c whatever.c 也會被推導出來。

此處需要例子進行演示。

文件搜尋

大的工程中有大量的源文件,通常的做法是把這許多的源文件分類並存放在不同的目錄中。所以當make需要去找尋文件的依賴關係時,你可以在文件前加上路徑,但最好的方法是把一個路徑告訴make讓make在自動去找。Makefile文件中的特殊變量“VPATH”就是完成這個功能的。如果沒有指明這個變量,make只會在當前的目錄中去找尋依賴文件和目標文件。如果定義了這個變量,那麼make就會在噹噹前目錄找不到的情況下,到所指定的目錄中去找尋文件了。
VPATH = src : ../headers

上面的的定義指定兩個目錄,“src”和“../headers”,目錄由“冒號”分隔。另一個設置文件搜索路徑的方法是使用make的“vpath”關鍵字(注意,它是全小寫的),這不是變量這是一個make的關鍵字,這和上面提到的那個VPATH變量很類似,但是它更爲靈活。它可以指定不同的文件在不同的搜索目錄中,這是一個很靈活的功能。

它的使用方法有三種:

1. vpath < pattern> < directories>         爲符合模式< pattern>的文件指定搜索目錄<directories>。

2. vpath < pattern>                                   清除符合模式< pattern>的文件的搜索目錄。

3. vpath                                                      清除所有已被設置好了的文件搜索目錄。

< pattern>需要包含“%”字符。“%”的意思是匹配零或若干字符,例如“%.h”表示所有以“.h”結尾的文件。< pattern>指定了要搜索的文件集,< directories>則指定了的文件集的搜索的目錄。例如:  vpath %.h ../headers   該語句表示 make在“../headers”目錄下搜索所有以“.h”結尾的文件(如果某文件在當前目錄沒有找到的話)。

僞目標

“.PHONY” 顯示地指明一個目標是僞目標。例如:

.PHONY : clean

 它”向make說明,clean 只是一個標籤,與源文件中是否有clean這個文件無關。 make 是按照規程中依賴文件的時間是否新於目標文件是時間

來決定是否執行生成規則的命令。 僞目標沒有對應的磁盤文件,所以當 執行 make clean 的時候,該條規則對應的命令總是要執行的。

當僞目標是Makefile中的默認目標( 第一個目標) 的時候, 當 執行 make  的時候 , $(targets) 會被生成。

targets := app1 app2 app3
.PHONY :  all
all : $(targets)
	xxxxx #shell cmds
app1 : app1.cpp
	$(CXX) $<  -o  $@
app2 : app2.cpp
	$(CXX) $<  -o  $@
app3 : app3.cpp
	$(CXX) $<  -o  $@

makefile 函數的使用

在Makefile中可以使用函數來處理變量,從而讓我們的命令或是規則更爲的靈活和具有智能。函數的返回值可以當做變量來使用。

函數調用,很像變量的使用,也是以“$”來標識的,其語法如下:
$(<function> <arguments> )

調試Makefile常用的函數

$(info TEXT )
可以輸出makefile中的宏定義,是我常用的Makefile 調試函數之一。
$(info  ******** CC = $(CC)) 輸出

********CC = cc

字符串處理類函數

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

例子:

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

例子:

$(words <text> )
名稱:單詞個數統計函數——words。
功能:統計<text>中字符串中的單詞個數。
返回:返回<text>中的單詞數。

例子:

$(word <n>,<text> )
名稱:取單詞函數——word。
功能:取字符串<text>中第<n>個單詞。(從一開始)
返回:返回字符串<text>中第<n>個單詞。如果<n>比<text>中的單詞數要大返回空字符串。
例子:

$(wordlist <s>,<e>,<text> )
名稱:取單詞串函數——wordlist。
功能:從字符串<text>中取從<s>開始到<e>的單詞串。<s>和<e>是一個數字。
返回:返回字符串<text>中從<s>到<e>的單詞字串。如果<s>比<text>中的單詞數要大返回空字符串。如果<e>大於<text>的單詞數返回從<s>開始到<text>結束的單詞串。

例子:

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

示例:

目錄操作相關的函數

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

shell函數

shell函數不同於除“wildcard”函數之外的其它函數。make可以使用它來和外部通信。
 函數功能:函數“shell”所實現的功能和shell中的引用(``)相同。實現了命令的擴展。意味着需要一個shell 命令作爲它的參數,而返回的結果是此命令在shell中的執行結果。make僅僅對它的回返結果進行處理;make將函數的返回結果中的所有換行符(“\n”)或者一對 “\n\r” 替換爲單空格並去掉末尾的回車符號(“\n”)或者 “\n\r” 。函數展開式時,它所調用的命令(它的參數)得到執行。除了對它的引用出現在規則的命令行中和遞歸的變量定義引用以外,大多數情況下,make在讀取Makefile時函數shell就被擴展。
 返回值:函數 “shell” 的參數在shell中的執行結果。
 函數說明:函數本身的返回值是其參數的執行結果,沒有進行任何處理。對結果的處理是由make進行的。當對函數的引用出現在規則的命令行中,命令行在執行時函數引用才被展開。展開過程函數參數的執行時在另外一個shell進程中完成的,因此對於出現在規則命令行的多級“shell”函數引用需要謹慎處理,否則會影響效率(每一級的“shell”函數的參數都會有各自的shell進程)。
示例1:
contents := $(shell cat foo)
將變量“contents”賦值爲文件“foo”的內容,文件中的行在變量中使用空格(而不是換行符)分割。
示例2:
files := $(shell echo *.c)
將變量“files”賦值爲當前目錄下所有.c文件的列表(文件名之間使用空格分割)。在shell中之行的命令是“echo *.c”,它會返回當前目錄下的所有.c文件列表。上例的執行結果和函數“$(wildcard *.c)”的結果相同。

參考資料

http://blog.csdn.net/ruglcc/article/details/7814546

http://www.yayu.org/book/gnu_make/  點擊打開鏈接


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