makefile自動生成依賴

此文章是《GNU Make中文手冊》中的一個我覺得有必要記錄下來的章節,關於如何在makefile中自動生成依賴關係,感謝《GNU Make中文手冊》的作者。文章最後爲我自己的理解與補充的博文鏈接。

《GNU Make中文手冊》免費下載鏈接:

http://download.csdn.net/detail/gmpy_tiger/9568503

========================================================================================

4.14 自動產生依賴
       Makefile 中,有時需要書寫一些規則來描述一個.o 文件和頭文件的依賴關係。例如,如果在 main.c 中使用“#include defs.h”,那麼我們可能就需要一個像下邊那樣的規則來描述當頭文件“defs.h”被修改以後再次執行 make,目標“main.o”應該被重建。
       main.o: defs.h
       這樣,對於一個大型工程。就需要在 Makefile 中書寫很多條類似於這樣的規則。並且,當在源文件中加入或刪除頭文件後,也需要小心地去修改 Makefile。這是一件非常費力、費時並且危險(容易出錯誤)的工作。爲了避免這個討厭的問題,現代的 c 編譯器提供了通過查找源文件中的“#include”來自動產生這種依賴關係的功能。Gcc 通過“-M”選項來實現此功能,使用“-M”選項 gcc 將自動找尋源文件中包含的頭文件,並生成文件的依賴關係。例如,如果“main.c”只包含了頭文件“defs.h”,那麼在 Linxu 下執行下面的命令:

       gcc -M main.c
其輸出是:
       main.o : main.c defs.h

既然編譯器已經提供了自動產生依賴關係的功能,那麼我們就不需要去動手寫這些規則的依賴關係了。但是需要明確的是:如果在“main.c”中包含了標準庫的頭文件,使用 gcc 的“-M”選項時,其輸出結果中也包含對標準庫的頭文件的依賴關係描述。當不需要在依賴關係中考慮標準庫頭文件時,對於 gcc 需要使用“-MM”參數。

       在使用 gcc 自動產生依賴關係時,所產生的規則中明確的指明瞭目標是“main.o”。一次在通過.c 文件直接產生可執行文件時,作爲中間過程文件的“main.o”在使用完之後將不會被刪除。
       在舊版本的 make 中,使用編譯器此項功能通常的做法是:在 Makefile 中書寫一個僞目標“depend”的規則來定義自動產生依賴關係文件的命令。輸入“make depend”將生成一個稱爲“depend”的文件,其中包含了所有源文件的依賴規則描述。Makefile 中使用“include”指示符包含這個文件。
       在新版本的 make 中,推薦的方式是爲每一個源文件產生一個描述其依賴關係的makefile 文件。對於一個源文件“NAME.c”,對應的這個 makefile 文件爲“NAME.d”。“NAME.d”中描述了文件“NAME.o”所要依賴的所有頭文件。採用這種方式,只有源文件在修改之後纔會重新使用命令生成新的依賴關係描述文件“NAME.o”。
       我們可以使用如下的模式規則來自動生成每一個.c 文件對應的.d 文件:

            %.d: %.c
                         $(CC) -M $(CPPFLAGS) $< > [email protected]; \
                         sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < [email protected] > $@; \

                         rm -f [email protected]

       此規則的含義是:所有的.d 文件依賴於同名的.c 文件。
       第一行;使用 c 編譯器自自動生成依賴文件($<)的頭文件的依賴關係,並輸出成爲一個臨時文件,“XXXX”表示當前進程號。如果$(CC)爲 GNU 的 c 編譯工具,產生的依賴關係的規則中,依賴頭文件包括了所有的使用的系統頭文件和用戶定義的頭文件。如果需要生成的依賴描述文件不包含系統頭文件,可使用“-MM”代替“-M”。
       第二行;使用 sed 處理第二行已產生的那個臨時文件並生成此規則的目標文件。這裏 sed 完成了如下的轉換過程。例如對已一個.c 源文件。將編譯器產生的依賴關係:
        main.o : main.c defs.h
轉成:
        main.o main.d : main.c defs.h
        這樣就將.d 加入到了規則的目標中,其和對應的.o 文件文件一樣依賴於對應的.c 源文件和源文件所包含的頭文件。當.c 源文件或者頭文件被改變之後規則將會被執行,相應的.d文件同樣會被更新。
       第三行;刪除臨時文件。

       使用上例的規則就可以建立一個描述目標文件依賴關係的.d 文件。我們可以在Makefile 中使用 include 指示符將描述將這個文件包含進來。在執行 make 時,Makefile所包含的所有.d 文件就會被自動創建或者更新。Makefile 中對當前目錄下.d 文件處理可以參考如下:

       sources = foo.c bar.c
       include $(sources:.c=.d)

      例子中,變量“sources”定義了當前目錄下的需要編譯的源文件。變量引用置換“$(sources : .c=.d)”的功能是根據變量“source”指定的.c 文件自動產生對應的.d 文件,並在當前 Makefile 文件中包含這些.d 文件。.d 文件和其它的 makefile 文件一樣,make在執行時讀取並試圖重建它們。其實這些.d 文件也是一些可被 make 解析的 makefile 文件。
需要注意的是 include 指示符的書寫順序,因爲在這些.d 文件中已經存在規則。當一個 Makefile 使用指示符 include 這些.d 文件時,應該注意它應該出現在終極目標之後,以免.d 文件中的規則被是 Makefile 的終極規則。關於這個前面我們已經有了比較詳細的討論。

========================================================================================

我個人比較詳細的理解博文鏈接:

http://blog.csdn.net/gmpy_tiger/article/details/51849474

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章