手工編寫依賴關系不僅工作量大而且極易出現遺漏,更新也很難及時,修改源或頭檔案後makefile可能忘記修改。為了解決這個問題,可以用gcc的-M選項自動生成目标檔案和源檔案的依賴關系。-M選項會把包含的系統頭檔案以及其所包含的其他系統頭檔案也找出來了,如果我們不需要輸出系統頭檔案的依賴關系時,可以用-MM選項。
下面我們以一個簡單的例子來說明如何自動生成依賴關系:
exm/
main.c
s.c
s.h
makefile檔案内容如下:
all:a
src=$(wildcard *.c)
obj:=$(patsubst %.c,%.o,$(src))
ifneq($(MAKECMDGOALS),clean)
-include$(src:.c=.d)
endif
a:$(obj)
gcc$(obj)-o $@
%.d:%.c
set-e;rm -f $@; \
gcc-MM$(CPPFLAGS) $< > $@.
; \
sed's,$∗\.o[:]*,\1.o $@ : ,g' < $@.
> $@; \
rm-f$@.
%.o:%.c
@echo'Buildingfile: $<'
@echo'Invoking:GCC C Compiler'
gcc-O0-g3 -Wall -c -o "$@" "$<"
@echo'Finishedbuilding: $<'
@echo''
其中wildcard作用就是将指定目錄下.c檔案全部找出,是以這裡src=main.cs.c
patsubst作用是把$(src)中的.c全部換為.o,于是obj=main.os.o
include$(src:.c=.d)相當于includemain.ds.d
由于此時這兩個檔案并不存在,是以會出現下面提示:
makefile:6:main.d:沒有那個檔案或目錄
makefile:6:s.d:沒有那個檔案或目錄
如果不想要這個提示,可以将include替換為-include
盡管一開始找不到.d檔案,是以make會報警告。但是make會把include的檔案名也當作目标來嘗試更新,而這些目标适用模式規則%.d:%c
<code>注意,雖然在</code>Makefile<code>中這個指令寫了四行,但其實是一條指令,</code>make<code>隻建立一個</code>Shell<code>程序執行這條指令,這條指令分為</code>5<code>個子指令,用</code>;<code>号隔開,并且為了美觀,用續行符</code>\<code>拆成四行來寫。執行步驟為:</code>
1)set-e<code>指令設定目前</code>Shell<code>程序為這樣的狀态:如果它執行的任何一條指令的退出狀态非零則立刻終止,不再執行後續指令。</code>@<code>表示</code>makefile<code>執行這條指令時不顯示出來</code>
2)把原來的.d<code>檔案</code>删掉。
3)$<依賴的目标集(即*.c), -MM:表示生成檔案依賴關系,$@:表示生成的目标檔案(即*.d),$$:表示本身的ProcessID。注意,在Makefile中$有特殊含義,如果要表示它的字面意思則需要寫兩個$,是以Makefile中的四個$傳給Shell變成兩個$,兩個$在Shell中表示目前程序的id,一般用它給臨時檔案起名,以保證檔案名唯一。
4)這個sed指令比較複雜,就不細講了,主要作用是查找替換,并加入.d的依賴關系。
5)最後把臨時檔案删掉。
<code>不管是</code>Makefile<code>本身還是被它包含的檔案,隻要有一個檔案在</code>make<code>過程中被更新了,</code>make<code>就會重新讀取整個</code>Makefile<code>以及被它包含的所有檔案,現在</code>main.d<code>、</code>stack.d<code>和</code>maze.d<code>都生成了,就可以正常包含進來了,相當于在</code>Makefile<code>中添了下面規則:</code>
<code>main.omain.d : main.c s.h</code>
<code>s.os.d : s.c s.h</code>
<code>當源或頭檔案修改時,如果依賴關系發生變化,執行</code>makefile<code>時将更新具有依賴關系的</code>.d<code>檔案,而</code>.d<code>檔案的更新又促使</code>make<code>重新讀取</code>makefile<code>檔案,把新的</code>.d<code>檔案包括進來,于是新的依賴關系被建立。</code>
除了上面方法外,還可使用GCC的-MMD-MP -MF -MT選項,如下,可起到同樣目的:
gcc-O0-g3 -Wall -c -fmessage-length=0 -MMD -MP-MF"$(@:%.o=%.d)"-MT"$(@:%.o=%.d)" -o "$@""$<"