自動生成依賴
在為一個程式編寫的makefile 檔中,常常需要寫許多僅僅是說明一些OBJ 檔依靠頭檔 的規則。例如,如果‘main.c’通過一條#include語句使用‘defs.h’,您需要寫入下的規則:
main.o: defs.h
您需要這條規則讓make 知道如果‘defs.h’一旦改變必須重新構造‘main.o’。由此您可以 明白對於一個較大的程式您需要在makefile檔中寫很多這樣的規則。而且一旦添加或去掉一 條#include語句您必須十分小心地更改makefile檔。 為避免這種煩惱,現代C編譯器根據原程式中的#include語句可以為您編寫這些規則。 如果需要使用這種功能,通常可在編譯根源程式時加入‘-M’開關,例如,下面的命令:
cc -M main.c
產生如下輸出:
main.o : main.c defs.h
這樣您就不必再親自寫這些規則,編譯器可以為您完成這些工作。
我們推薦使用自動生成依賴的習慣是把makefile檔和根源程式檔一一對應起來。如,對 每一個根源程式檔‘name.c’有一名為‘name.d’的makefile 檔和它對應,該makefile 檔中列出 了名為‘name.o’的OBJ檔所依賴的檔。這種方式的優點是僅在根源程式檔改變的情況下才有 必要重新掃描生成新的依賴。 這裏有一個根據C語言根源程式‘name.c’生成名為‘name.d’依賴檔的格式規則:
%.d: %.c
set -e; $(CC) -M $(CPPFLAGS) $< \
| sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \
[ -s $@ ] || rm -f $@
set命令作用主要是顯示系统中已經存在的shell變量,以及設置shell變量的新變量值。‘-e’開關是告訴shell 如果$(CC)命令運行失敗(非零狀態退出)立即退出。正常情況下,shell 退出時帶有最後一個命令在管道中的狀態(sed),因此make不能注意到編譯器產生的非零狀態。sed用法sed's/regularexpression/replacement/g'用replacement替換符合regularexpression的字串。 命令Sed 的作用是翻譯(例如):
main.o : main.c defs.h
到:
main.o main.d : main.c defs.h
這使每一個‘.d’檔和與之對應的‘.o’檔依靠相同的根源程式檔和頭檔,據此,Make 可以知道 如果任一個根源程式檔和頭檔發生變化,則必須重新構造依賴檔。 一旦您定義了重新構造‘.d’檔的規則,您可以使用使用include命令直接將它們讀入,例如:
include *.d