2006年9月10日 星期日

mkdep

mkdep 可算是 make 的輔助工具。

通常,我們在 Makefile 裡寫下 source code 和產生出來的 binary code 的依存規則。當然也有不是 binary code 的場合,比方說用 Makefile 來產生 doxygen 或 latex 文件。原則是,有個 source -> target 的依存性。

mkdep 就我個人的看法,是比較特化給 C 語言用的。它接受原本給 cc 的 CFLAGS 和 SRCS 參數,藉由偷看 cc 的參數,找出 .c 檔和 .h 檔的相依性。它作了一部份 cpp parse 原始檔的前置指令的工作,但不多動原始檔,而是將用到的 header files 記錄在 .depend 裡,提供給 make 作為編譯程式時的額外參考。

source -> target 的相依性,是比較顯而易見的。有什麼樣的原始碼,就產生出什麼樣的 binary code。但對於 header files 來說就不那麼明顯。對於只用到系統一般提供函式庫的場合,header files 可能是永遠不會變的,因此不太需要考慮到這個問題。但如果是同時在修改 header files, 或是它會常常更新,那麼有個程式自動找出它的相依性,就很重要了。當 header files 改變時自動重新編譯,不僅僅是像 Makefile 一樣自動檢查相依性,以減少編譯的時間而已,也能減少因為 header files 版本不同,而遇到的奇奇怪怪問題。尤其是在抽象化得比較完整的 case, header files 可能是一層包一層,讓追問題更加困難。

有經驗寫過或用過 Makefile (也就是使用 'make' 這個指令)的人都知道,如果Makefile 裡的相依性規則沒有寫好,有時會遇到明明某個原始檔更新了,卻沒有重新編譯,以致於程式跑不出想要的結果。如果Makefile 裡有定義 clean: 或 distclean: 這類的 targets, 整個重新編譯過也許可以解決,但這會多花許多重複編譯的時間,而且你還是不知道問題是誰造成的。

同樣的問題發生在更隱誨不明的 header files 時,就更麻煩了。因為最明確的 #include 是寫在 .c 檔裡,不是 Makefile 。哪一天別的小組或是供應商更新了他們提供給你的函式庫 header files, 而沒有提醒你時,你就等著遇到各種奇奇怪怪的問題了。

因為這是在 header files 會更新時,才能顯現出它的好處,一般只是用現成函式庫開發程式,或是只編譯一次原始碼,產出程式來用,而不管程式到底寫什麼, 或到底需要改什麼的人來說,比較體會不到。但在同時修改函式庫或 header files 的人,能利用它就會很方便地減少許多問題和重複編譯的時間。所以現在能想到比較明顯的例子,就是在 FreeBSD 或 Linux 編譯 kernel 時。

FreeBSD 編譯 kernel 的標準用法,是 make depend all install。 Linux 是 make dep image 。這 depend 或 dep target, 就是在執行 mkdep 。當然後來它們的編譯步驟又被包裝得更容易,也許第一眼看不到這些 make 指令,但跟著Makefile 追蹤下去就會發現。

沒有留言:

張貼留言