在 Makefile 中,我們的依賴關係可能會需要包含一系列的頭文件,比如,如果我們的 main.c 中有一句“ #include "defs.h" ”,那麼我們的依賴關係應該是:
main.o : main.c defs.h
但是,如果是一個比較大型的工程,你必需清楚哪些 C 文件包含了哪些頭文件,並且,你在加入或刪除頭文件時,也需要小心地修改 Makefile ,這是一個很沒有維護性的工作。爲了避免這種繁重而又容易出錯的事情,我們可以使用 C/C++ 編譯的一個功能。大多數的 C/C++ 編譯器都支持一個“ -M ”的選項,即自動找尋源文件中包含的頭文件,並生成一個依賴關係。
例如,如果我們執行下面的命令:
cc -M main.c
其輸出是:
main.o : main.c defs.h
於是由編譯器自動生成的依賴關係,這樣一來,你就不必再手動書寫若干文件的依賴關係,而由編譯器自動 生成了。需要提醒一句的是,如果你使用 GNU 的 C/C++ 編譯器,你得用“ -MM ”參數,不然,“ -M ”參數會把一些標準庫的頭文件也包含進來。
gcc -M main.c 的輸出是:
main.o: main.c defs.h /usr/include/stdio.h
/usr/include/features.h /
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h /
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h /
/usr/include/bits/types.h /usr/include/bits/pthreadtypes.h /
/usr/include/bits/sched.h /usr/include/libio.h /
/usr/include/_G_config.h /usr/include/wchar.h /
/usr/include/bits/wchar.h /usr/include/gconv.h /
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h /
/usr/include/bits/stdio_lim.h
gcc -MM main.c 的輸出則是:
main.o: main.c defs.h
那麼,編譯器的這個功能如何與我們的 Makefile 聯繫在一起呢。因爲這樣一來,我們的 Makefile 也要根據這些源文件重新生成,讓 Makefile 自已依賴於源文件?這個功能並不現實,不過我們可以有其它手段來迂迴地實現這一功能。 GNU 組織建議把編譯器爲每一個源文件的自動生成的依賴關係放到一個文件中,爲每一個“ name.c ”的文件都生成一個“ name.d ”的 Makefile 文件, [.d] 文件中就存放對應 [.c] 文件的依賴關係。於是,我們可以寫出 [.c] 文件和 [.d] 文件的依賴關係,並讓 make 自動更新或自成 [.d] 文件,並把其包含在我們的主 Makefile 中,這樣,我們就可以自動化地生成每個文件的依賴
關係了。這裏,我們給出了一個模式規則來產生 [.d] 文件:
%.d: %.c
@set -e; rm -f $@; /
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; /
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /
rm -f $@.$$$$
這個規則的意思是,所有的 [.d] 文件依賴於 [.c] 文件,“ rm -f $@ ”的意思是刪除所有的目標,也就是 [.d] 文件,第二行的意思是,爲每個依賴文件“ $< ”,也就是 [.c] 文件生成依賴文件,“ $@ ”表示模式“ %.d ”文件,如果有一個 C 文件是 name.c ,那麼“ % ”就是“ name ”,“ $$$$ ”意爲一個隨機編號,第二行生成的文件有可能是“ name.d.12345 ”,第三行使用 sed 命令做了一個替換,關於 sed 命令的用法請參看相關的使用文檔。第四行就是刪除臨時文件。
總而言之,這個模式要做的事就是在編譯器生成的依賴關係中加入 [.d] 文件的依賴,即把依賴關係:
main.o : main.c defs.h
轉成:
main.o main.d : main.c defs.h
於 _______ 是,我們的 [.d] 文件也會自動更新了,並會自動生成了,當然,你還可以在這個 [.d] 文件中加入的不只是依賴關係,包括生成的命令也可一併加入,讓每個 [.d] 文件都包含一個完賴的規則。一旦我們完成這個工作,接下來,我們就要把這些自動生成的規則放進我們 的主 Makefile 中。我們可以使用 Makefile 的“ include ”命令,來引入別的 Makefile 文件(前面講過),例如:
sources = foo.c bar.c
include $(sources:.c=.d)
上述語句中的“ $(sources:.c=.d) ”中的“ .c=.d ”的意思是做一個替換,把變量
$(sources) 所有 [.c] 的字串都替換成 [.d] ,關於這個“替換”的內容,在後面我會有更
爲詳細的講述。當然,你得注意次序,因爲 include 是 按次來載入文件,最先載入的 [.d]
文件中的目標會成爲默認目標。
原帖來源:http://blog.csdn.net/mf324/archive/2009/04/28/4132189.aspx