1. 程式人生 > >makefile自動生成依賴關係

makefile自動生成依賴關係

手工編寫依賴關係不僅工作量大而且極易出現遺漏,更新也很難及時,修改源或標頭檔案後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

注意,雖然在Makefile中這個命令寫了四行,但其實是一條命令,make只建立一個Shell程序執行這條命令,這條命令分為5個子命令,用;號隔開,並且為了美觀,用續行符\拆成四行來寫。執行步驟為:

1)set-e命令設定當前Shell程序為這樣的狀態:如果它執行的任何一條命令的退出狀態非零則立刻終止,不再執行後續命令。@表示makefile執行這條命令時不顯示出來

2)把原來的.d檔案刪掉。

3)$<依賴的目標集(*.c), -MM:表示生成檔案依賴關係,$@:表示生成的目標檔案(*.d),$$:表示本身的ProcessID。注意,在Makefile$有特殊含義,如果要表示它的字面意思則需要寫兩個$,所以Makefile中的四個$傳給Shell變成兩個$,兩個$Shell中表示當前程序的id,一般用它給臨時檔案起名,以保證檔名唯一。

4)這個sed命令比較複雜,就不細講了,主要作用是查詢替換,並加入.d的依賴關係。

5)最後把臨時檔案刪掉。

不管是Makefile本身還是被它包含的檔案,只要有一個檔案在make過程中被更新了,make就會重新讀取整個Makefile以及被它包含的所有檔案,現在main.dstack.dmaze.d都生成了,就可以正常包含進來了,相當於在Makefile中添了下面規則:

main.omain.d : main.c s.h

s.os.d : s.c s.h

當源或標頭檔案修改時,如果依賴關係發生變化,執行makefile時將更新具有依賴關係的.d檔案,而.d檔案的更新又促使make重新讀取makefile檔案,把新的.d檔案包括進來,於是新的依賴關係被建立。

除了上面方法外,還可使用GCC-MMD-MP -MF -MT選項,如下,可起到同樣目的:

all:a

src=$(wildcard *.c)

obj:=$(patsubst %.c,%.o,$(src))

ifneq($(MAKECMDGOALS),clean)

-include$(src:.c=.d)

endif

a:$(obj)

gcc$(obj)-o $@

%.o:%.c

@echo'Buildingfile: $<'

@echo'Invoking:GCC C Compiler'

gcc-O0-g3 -Wall -c -fmessage-length=0 -MMD -MP-MF"$(@:%.o=%.d)"-MT"$(@:%.o=%.d)" -o "$@""$<"

@echo'Finishedbuilding: $<'

@echo''