Makefile自動生成頭文件依賴是很經常使用的功能,本文的目的是想盡可能詳細說明其中的原理和過程。html
首先給出一個本人在小項目中經常使用的Makefile模板,支持自動生成頭文件依賴。c++
makefileCC = gcc CFLAGS = -Wall -O INCLUDEFLAGS = LDFLAGS = OBJS = seq.o TARGETS = test_seq .PHONY:all all : $(TARGETS) test_seq:test_seq.o $(OBJS) $(CC) -o $@ $^ $(LDFLAGS) %.o:%.c $(CC) -o $@ -c $< $(CFLAGS) $(INCLUDEFLAGS) %.d:%.c @set -e; rm -f $@; $(CC) -MM $< $(INCLUDEFLAGS) > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ -include $(OBJS:.o=.d) .PHONY:clean clean: rm -f $(TARGETS) *.o *.d *.d.*
在進行下一步以前,首先須要瞭解make的執行步驟:正則表達式
從上面make的執行過程當中可看出,要動態生成依賴關係,只能利用第2步讀入其它Makefile的機制。那麼,咱們是否能夠先把生成的依賴關係保存到文件,而後再把該文件的內容包含進來?
答案是Yes! 只要利用include的機制。shell
include關鍵字是用於讀入其它Makefile文件。當該文件不存在時,make會尋找是否有生成它的規則,若是有,則執行其生成命令,而後再嘗試讀入。在include前加減號"-"能夠上make忽略其產生的錯誤,並不輸出任何錯誤信息。編程
便是說,咱們須要提供生成規則文件的規則。例如,咱們能夠這樣動態生成頭文件依賴關係:code
makefileseq.d : seq.c @echo 「seq.o seq.d : seq.c seq.h" > $@ -include seq.d
當make執行時,Makefile中的內容將是這樣子(指內存上的數據):htm
makefileseq.d : seq.c @echo 「seq.o seq.d : seq.c seq.h" > $@ seq.o seq.d : seq.c seq.h
特別注意的是,因爲對seq.c和seq.h的修改須要更新seq.d的內容(由於依賴關係可能已變化),所以seq.d也要在依賴關係的目標列表中。進程
基於上面的例子,如今能夠開始討論如何自動生成頭文件依賴。內存
大多數c/c++編譯器提供了-M選項,可自動尋找源文件依賴的頭文件,並生成依賴規則。對於gcc,須要使用-MM選項,不然它會把系統依賴的頭文件也包含進來。例如執行下面一個命令:文檔
shellgcc -MM seq.c
將輸出:
makefileseq.o : seq.c seq.h
但咱們須要結果是seq.d也要包含在目標列表中,因此還須要對它進行文本處理。所以,上面的例子可改成:
makefileseq.d : seq.c @set -e; \ gcc -MM $< > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ -include seq.d
第一個命令@set -e
。@關鍵字告訴make不輸出該行命令;set -e的做用是,當後面的命令的返回值非0時,當即退出。
那麼爲何要把幾個命令寫在」同一行「(是對於make來講,由於\的做用就是鏈接行),並用分號隔開每一個命令?由於在Makefile這樣作才能使上一個命令做用於下一個命令。這裏是想要set -e做用於後面的命令。
第二個命令gcc -MM $< > $@.$$$$
, 做用是根據源文件生成依賴關係,並保存到臨時文件中。內建變量$<
的值爲第一個依賴文件(那seq.c),$$$$
爲字符串"$$"
,因爲makefile中全部的$字符都是特殊字符(即便在單引號之中!),要獲得普通字符$,須要用$$
來轉義; 而$$
是shell的特殊變量,它的值爲當前進程號;使用進程號爲後綴的名稱建立臨時文件,是shell編程經常使用作法,這樣可保證文件惟一性。
第三個命令做用是將目標文件加入依賴關係的目錄列表中,並保存到目標文件。關於正則表達式部分就不說了,惟一要注意的是內建變量$*
,$*
的值爲第一個依賴文件去掉後綴的名稱(這裏便是seq)。
第四個命令是將該臨時文件刪除。
若是把內建變量都替換成其值後,實際內容是這樣子:
makefileseq.d : seq.c @set -e; \ gcc -MM seq.c > seq.d.$$$$; \ sed 's,\(seq\)\.o[ :]*,\1.o seq.d : ,g' < seq.d.$$$$ > seq.d; \ rm -f seq.d.$$$$ -include seq.d
最後,再把Makefile的模式匹配應用上,就完成自動生成頭文件依賴功能了:
makefile%.d : %.c @set -e; \ gcc -MM $@ > $@.$$$$; \ sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ -include seq.d
<跟我一塊兒寫Makefile> by 陳晧
GNU make官方文檔 http://www.gnu.org/software/make/manual/make.html