Makefile 必知必會
Makefile的根本任務是根據規則生成目標文件。
規則
一條規則包含三個:目標文件,目標文件依賴的文件,更新(或生成)目標文件的命令。
規則:
<目標文件>:<依賴文件>
<更新目標的命令>
PS:更新目標命令必須以tab開頭,這個有點噁心。
Example
hello.o: hello.chello.h
gcc -c hello.c -o hello.o
目標hello.o 依賴於hello.c,hello.h. 生成hello.o的命令時是“gcc -c hello.c -o hello.o”
僞目標
一般情況下目標文件是一個具體的文件,但有時候我們只需要一個標籤,如目標clean。
聲明僞目標:
.PHONY: <僞目標>
僞目標只是一個標籤,這意味着僞目標的時間戳總是最新的,結果就是makefile每次都會去執行更新僞目標的命令。
終極目標
makefile並不會更新所有規則中的目標,它只會更新終極目標以及終極目標依賴的目標。
默認情況下makefile的第一個目標是終極目標,而且大家約定俗成的總是將all作爲第一個目標。環境變量MAKECMDGOALS記錄着終極目標。
PS:你也可以在make的命令行參數中指定終極目標。如make clean表示以clean作爲終極目標。
多規則目標
Makefile中,一個文件可以作爲多個規則的目標,這種情形就是多規則目標。
多規則目標下,以這個文件爲目標的所有規則的依賴文件將會被合併成此一個依賴文件列表,但是命令不會合並,而且實際上,這多個規則中至多只能有一個規則定義了更新命令。
all:hello.o
all:hello.h
等價於 all: hello.o hello.h
什麼時候更新目標
如果目標不存在或者依賴文件中至少有一個文件的時間戳比目標新,則執行目標更新命令。
包含其他makefile
類似於C語言中的頭文件包含,makefile也可以包含其他makefile。
格式:
include<makefile>
與C語言不同的是,包含其他makefile不只是把其他makefile中的內容導入到當前makefile中,而且它還有一個附加行爲,具體參看下面makefile執行步驟:
1. 依次讀取變量“MAKEFILES”定義的makefile文件列表
2. 讀取工作目錄下的makefile文件(根據命名的查找順序“GNUmakefile”,“makefile”,“Makefile”,首先找到那個就讀取那個)
3. 依次讀取工作目錄makefile文件中使用指示符“include”包含的文件
4. 查找重建所有已讀取的makefile文件的規則
(如果存在一個目標是當前讀取的某一個makefile文件,則執行此規則重建此makefile文件, 完成以後從第一步開始重新執行)
自動生成頭文件依賴關係
C,C++的源文件編譯依賴於頭文件,手工維護這個頭文件依賴列表無疑是瑣碎而易錯。這裏可以利用gcc自帶命令自動產生依賴文件列表,然後利用include命令導入即可。
%.o: %.c
$(GCC) -MMD -MP -MF"$(@:%.o=%.d)"-MT"$@" -MT"$(@:%.o=%.d)" -o "$@""$<"
這個命令比較複雜,有興趣的同學可以自己私下搜索一下。這裏我只說一下結果:
如果我們要編譯 hello.o, 而hello.c中包含頭文件hello.h。那麼執行上面命令的結果是生成hello.d,其內容是
hello.o hello.d : hello.c hello.h
於是只要再加上include hello.d,自然而然地就有hello.o依賴關係。