zoukankan      html  css  js  c++  java
  • 转载:大项目实用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/

  • 相关阅读:
    【2020-05-17】人生十三信条
    【2020-05-16】评价与骄傲
    【2020-05-15】每天都充满向上的激情
    【04NOIP普及组】火星人(信息学奥赛一本通 1929)(洛谷 1088)
    next_permutation(全排列算法)
    【03NOIP普及组】麦森数(信息学奥赛一本通 1925)(洛谷 1045)
    快速幂
    【03NOIP普及组】栈(信息学奥赛一本通 1924)(洛谷 1044)
    【06NOIP普及组】数列(信息学奥赛一本通 1937)(洛谷 1062)
    【00NOIP普及组】计算器的改良(信息学奥赛一本通 1910)(洛谷 1022)
  • 原文地址:https://www.cnblogs.com/sstudy-linux/p/4730542.html
Copyright © 2011-2022 走看看