1. 程式人生 > >Makefile學習筆記一

Makefile學習筆記一

入職之前,在大學裡的程式設計還從來沒有接觸過Makefile,都是用已經整合好的軟體開發工具進行開發,只需要進行一些通過介面進行的配置,方能夠完成整個工程的編譯連結的過程,工作以後,發現需要根據Makefile來修改相關的設定,將整個編譯連結的過程變成可控的,所以慢慢學習了相關的知識,在這裡做些筆記和總結。
  我學習Makefile是參考電子工業出版社出版的《專業嵌入式軟體開發-全面走向高質高效程式設計》一書中的Makefile一章,我覺得對我這種小白來講挺好的。不過這本書已經停止出版了,可以上作者李雲前輩的部落格來找相關的內容,有需要的還可以評論中留言,我可以發給一下電子版的。
  1. 在Makefile中,.PHONY:目標,所構建的是假目標,make不會再將其作為一個檔案來進行處理。在Makefile中定義變數時,其右值可以為空,引用變數需要採用 (

) (變數名)或者 {變數名}。
2. 在Makefile中,“$”具有特殊的意思,想要用echo輸出“$”,則必須使用兩個連著的“$”,同時“[email protected]
”對bash shell也有特殊的意思,所以需要在“[email protected]”之前再加一個脫字元“\”。在Makefile中,存在幾個自動變數,[email protected]用於表示規則中的目標,當一個規則中有多個目標時,[email protected]所指的是其中任何造成規則命令被執行的目標。$^表示的是規則中的所有先決條件,$<表示規則中的第一個先決條件。(由於在後面的工作中,發現這個經常會遇到,但是對目標和先決條件概念不是很清楚,所以這裡再作一下介紹)
例如:
all:test
@echo “hello world”
test:
@echo “just for test!”
在這裡,我們所構建的就是all目標,但是all目標依賴於test目標,這個依賴目標又被成為all目標的先決條件。make後面不加任何目標的時候,預設執行第一個目標,所以在順序安排上,需要稍加註意。目標和先決條件之間表達的就是依賴關係,這種依賴關係指明在構建目標之前,必須保證先決條件先滿足,也就是說先決條件要先被構建。所以這裡會先列印 just for test!然後才會列印hello world!
3. 在Makefile中,有兩個特殊變數,一個是MAKE,一個是MAKECMDGOALS,一個代表當前Makefile的命令名是什麼,$(MAKE)的值就是”make”,這個在Makefile中需要執行別的Makefile時會用到,另一個是表示當前構建的目標名。比如make時,該值為空,make all時為all,make all test 時,值為all test。
4. 變數的類別有遞迴擴充套件變數和簡單擴充套件變數。只用一個”=”符號定義的變數稱為遞迴擴充套件變數。就是在Makefile中,直接用=號的話,可能會給人一種後面的程式在前面的程式之前執行的感覺。簡單擴充套件變數是用”:=”來定義的,但是對於這種變數,make只對其進行一次展開。?=表示條件賦值,當變數沒有被定義時就定義它,並且將右邊的值賦給它,若變數已經被定義了,則不改變其原值。+=實現追加賦值。
5. 在Makefile中還可以實現條件賦值:當變數沒有被定義時就定義它,並且將右邊的值賦值給它;如果變數已經定義了,則不改變其原值。條件賦值可用於為變數賦預設值。用
?=來實現。另外還可以利用+=來實現追加賦值。
6. 在Makefile中定義的變數,有可能會被覆蓋,因此可以使用override指令進行預防,格式為: override foo = x,然後後面就沒有辦法將foo進行覆蓋了。
7. 在Makefile中可以使用相應的函式來進行相應的操作。
(1) $(abspath _names)中的abspath函式用於將_names中的各路徑轉換為絕對路徑,並將轉換後的結果返回。
(2) $(addprefix _prefix, _names)中的addprefix函式被用於給名字列表_names中的每一個名字增加字首_prefix,並將增加了字首的名字列表返回。
(3) $(addsuffix _suffix,_names)中的addsuffix函式被用於給名字列表_names中的每一個名字增加字尾_suffix,並將增加了字尾_suffix的名字列表返回。
(4) $(eval _text)中的eval使得Makefile具有動態語言的特徵,eval使得make將再一次解析_text語句。
(5) $(filter _pattern,_text)函式被用於從一個名字列表_text中根據模式_pattern得到滿足需要的名字列表並返回。
(6) $(filter-out _pattern,_text)中的filter-out被用於從名字列表_text中根據模式_pattern濾除一部分名字,並將濾除後的列表返回。
(7) $(notdir _names)中的notdir被用來從路徑_names中抽取檔名,並將檔名返回。
(8) $(patsubst _pattern,_replacement,_text)中的patsubst函式被用來將名字列表_text中符合_pattern模式的名字替換為_replacement,並將替換後的名字列表返回。
(9) $(realpath _names)函式被用於獲取_names所對應的真實路徑名。
(10) $(strip _string)如果希望清除名字列表中的多餘空格,strip函式就是最終選擇。strip函式將_string中的多餘空格去除後返回。
(11) $(wildcard _pattern)中的wildcard是萬用字元函式,通過它可以得到當前工作目錄中滿足_pattern模式的檔案或著目錄名列表。
8. 編寫Makefile的第一步,不是一個猛子扎進去試著寫一個規則並對之除錯(一個規則是由目標、先決條件以及命令組成的),而應先採用面向依賴關係的思考方法勾勒出Makefile要表達怎樣的依賴關係,這一點至關重要。
9. gcc -c test.c將生成test.o的目標檔案
gcc -o app test.c將生成可執行程式app
gcc -c a.c -o a.o表示把原始檔a.c編譯成指定檔名為a.o的中間目標檔案(其實在這裡,你把-o a.o省掉,效果是一樣的,因為中間檔案預設與原始檔同名,只是字尾變化)。其實通過最後一行的命令,不過是更改了生成的.o檔案的名稱而已。
10. Makefile中的
foo = a.c b.c c.c
bar := $(foo:.c=.o)在賦值的同時就可以完成檔名的字尾替換。是把所有的.c檔案替換為.o,注意這裡的bar只是儲存的字元,並沒有對檔案的任何操作。