項目實用makefile

在上一篇文章“小項目實用makefile”中,已經說明了單個makefile管理層次目錄的侷限性。本文,主要總結一下項目中的一種實用makefile樹寫法,爲10來個人協作的中小型項目makefile編寫,提供參考。
        
        1. 需求
        從實用角度,makefile樹應該達到以下需求:
        1)自動加入編譯系統。新增目錄、文件後,能夠自動添加(理想),或只需少許修改,就能添加到整個項目編譯中。
        2)可讀性好,易於添加。新增目錄、文件,linux新人能自己看懂添加(理想),或只需口頭10s描述就能很好完成。
        3)模塊化。新增目錄、文件後的makefile,和其他目錄完全沒有關係(理想),或只需與最鄰近的前、後有關係。
      

        2. 實現
        2.1 自動加入編譯系統
        使用makefile遞歸執行,能夠解決此問題。以下腳本,能夠執行SUBDIRS指定的子目錄內的makefile。

[plain] view plaincopy
  1. makefile。  
  2. SUBDIRS = modual-a modual-b modual-c  
  3.      
  4. .PHONY: subdirs $(SUBDIRS)  
  5. subdirs: $(SUBDIRS)  
  6. $(SUBDIRS):  
  7.     $(MAKE) -C $@  

        說明:
        1)變量SUBDIRS,指定當前目錄下,要遞歸編譯的子目錄。
        2).PHONY及subdirs目標結構,能保證遞歸到子目錄中。
            
        2.2 可讀性好,易於添加;模塊化
        使用makefile的變量定義,其位置前後不敏感特性可以做到。示例腳本如下:

[plain] view plaincopy
  1. SUBDIRS = modual-a modual-b modual-c  
  2. OBJECTS = x.o y.o z.o  
  3.   
  4. all:subdirs ${OBJECTS}  
  5.   
  6. clean:cleansubdirs  
  7.     rm ${OBJECTS}  

        說明:
        1)變量OBJECTS,指定當前目錄的目標文件。新增一個文件z.cpp,在變量OBJECTS中,增加z.o即可。
        2)新增一個目錄dir-c,在變量SUBDIRS中,增加dir-c。然後參考本目錄中的makfile,在dir-c中,建立一個類似makfile即可。
        
        2.3 減少重複腳本
        實現中,將makefile中的共用變量,轉移到文件中,使用include包含,能夠達到函數效果,減少重複腳本,容易改變。

        
        
3. 實例
        示例項目目錄如下所示(點擊下載示例項目

[plain] view plaincopy
  1. project-test  
  2.   +-- makeconfig  
  3.   |     +-- make.global  
  4.   +-- src  
  5.   |     +-- module-a  
  6.   |     |     +-- test.cpp  
  7.   |     |     +-- Makefile  
  8.   |     +-- module-b  
  9.   |     |     +-- test.cpp  
  10.   |     |     +-- Makefile  
  11.   |     +-- main.cpp  
  12.   |     +-- Makefile  
  13.   +-- Makefile  

        說明:
        1)project-test/makeconfig/make.global,要包含的makefile共用變量。
        2)project-test/Makefile,頂層makefile,指定可執行目標,及源碼目錄。
        3)project-test/src/Makefile,子目錄的makeflile。目錄module-a、module-b的類似,每個目錄一個。
        
        3.1 project-test/makeconfig/make.global
        如下所示:

[plain] view plaincopy
  1. # compile macro  
  2. CC      = g++  
  3. CFLAGS      = -O2 -Wall  
  4. LDFLAGS = -lm   
  5. INCLUDES    = -I/usr/local/include  
  6.   
  7.   
  8. # recursive make  
  9. .PHONY: subdirs ${SUBDIRS} cleansubdirs  
  10. subdirs: ${SUBDIRS}  
  11. ${SUBDIRS}:  
  12.     ${MAKE} -C $@ all  
  13.   
  14.       
  15. # recursive make clean  
  16. cleansubdirs:  
  17.     @for dir in ${SUBDIRS}; do \  
  18.         ${MAKE} -C $$dir clean; \  
  19.     done  
  20.   
  21.       
  22. # dependence  
  23. %.o: %.cpp  
  24.     ${CC} ${CFLAGS} ${INCLUDES} -c $< -o $@  
  25. %.o: %.cc  
  26.     ${CC} ${CFLAGS} ${INCLUDES} -c $< -o $@    

        說明:
        1)包含4個區域,共用變量,遞歸make,遞歸makeclean,依賴關係。
        2)遞歸makeclean,使用了不打印的shell語法。原因是,如果和遞歸一樣寫,會造成目標重載警告。
        
        3.2 project-test/Makefile
        如下所示: 

[plain] view plaincopy
  1. # target, subdir, objects in current dir  
  2. TARGET      = test  
  3. SUBDIRS = src  
  4. OBJECTS =   
  5.   
  6.   
  7. all:subdirs ${OBJECTS}  
  8.     ${CC} -o ${TARGET} $$(find ./${SUBDIRS} -name '*.o') ${LDFLAGS} ${INCLUDES}  
  9.   
  10.   
  11. clean:cleansubdirs  
  12.     rm -f ${TARGET} ${OBJECTS}  
  13.   
  14.   
  15. # path of "make global scripts"  
  16. # NOTE, use absolute path. export once, use in all subdirs  
  17. export PROJECTPATH=${PWD}  
  18. export MAKEINCLUDE=${PROJECTPATH}/makeconfig/make.global  
  19.   
  20. # include "make global scripts"  
  21. include ${MAKEINCLUDE}  

        說明:
        1)使用shell語法,搜索出指定目錄的所有.o,鏈接爲執行目標文件。
        2)使用export,指定項目絕對路徑,指定共用變量,包含所有目錄共用的makefile變量。
        3)每個目標使用一個頂層的makefile,來執行make和makeclean的遞歸入口,共用makefile。
        
        3.3 project-test/src/Makefile
        如下所示:

[plain] view plaincopy
  1. # subdir and objects in current dir  
  2. SUBDIRS = module-a module-b  
  3. OBJECTS = main.o  
  4.   
  5.   
  6. all:subdirs ${OBJECTS}  
  7.   
  8.       
  9. clean:cleansubdirs  
  10.     rm -f ${OBJECTS}  
  11.       
  12. include ${MAKEINCLUDE}  

        說明:
        1)增加目錄,只用修改子目錄變量SUBDIRS;增加文件,修改當前目標文件變量OBJECTS。
        2)不同目錄下,源碼相同名字,但類、函數不相同,可以正常編譯。        
        
        
4. 專業makefile樹
        以上,只是一個項目最最普通的makefile樹。一個實現文件一個.o文件,不考慮庫生成,不考慮功能配置項,不考慮平臺兼容性。
        一些開源項目,考慮了各種平臺兼容性,及功能特性,通常使用了autoconf和automake,自動生成特殊頭文件和宏定義,來達到效果。使用以下3條命令,向用戶提供配置項設置,編譯,庫、頭文件、或目標文件安裝路徑。在複雜兼容項目中,非常實用。
        ./configure
        make
        make install
        還在繼續學習中。
        
        參考資料:
        1. GNU Make Manual:
http://www.gnu.org/software/make/manual/
        2. 同事J的makefile樹。

發佈了11 篇原創文章 · 獲贊 13 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章