• Makefile研究(三) —— 实际应用


    转自:http://blog.csdn.net/jundic/article/details/17886637

    前面讲了Makefile 的简单语法和简单的应用模板,但在实际项目应用中比这个肯定复杂很多,但是我想说他的Makefile应用模式都是大同小异,只是代码量和工程复杂度大写而已。

    我觉得一个完整的工程目录应该这样:

    1、工程文件结构目录应该要非常清晰,并且模块化,各个模块下的Makefile 独立

    2、可以分别单独编译各个单独模块成.a 或.so

    3、在顶层目录下可以一次性生成可执行文件。

    现在我搭建了如下工程目录

    build为编译产生的结果文件,out 为可执行bin文件,libs为生成的库

    project 为工程文件夹,下面有module1 、module2 、module3三个模块,main.c 为主函数它将生成可执行文件,虚线框为编译时生成的文件夹或文件

    module2 module3和module1的文件结构相同图中没有画出来。

    现进行如下分工,module1 module2 将产生静态库到 build/libs/static 中,module3将产生动态库到 build/libs/dynamic 中,最后main.c 将调用这些库编译生成可执行文件到

    build/out 中。

    为了提高模块的复用性,我们会在顶层目录下,写一个rules.mk文件,事实上很多项目是这么做的比如uboot 。

    rules.mk 代码

      1 # rules .mk  
      2   
      3 # Generic Makefile for C/C++ Program  
      4 # Author:   
      5 # Description: # ------------  
      6 # This is an easily customizable makefile template. The purpose is to  
      7 # provide an instant building environment for C/C++ programs.  
      8 #  
      9 # It searches all the C/C++ source files in the specified directories,  
     10 # makes dependencies, compiles and links to form an executable.  
     11 #  
     12 # Besides its default ability to build C/C++ programs which use only  
     13 # standard C/C++ libraries, you can customize the Makefile to build  
     14 # those using other libraries. Once done, without any changes you can  
     15 # then build programs using the same or less libraries, even if source  
     16 # files are renamed, added or removed. Therefore, it is particularly  
     17 # convenient to use it to build codes for experimental or study use.  
     18 #  
     19 # GNU make is expected to use the Makefile. Other versions of makes  
     20 #  
     21   
     22 .PHONY : all clean  
     23   
     24 # Top directory  Makefile  
     25   
     26 # The C program compiler  
     27 CC = gcc  
     28 MACRO = DEBUGALL  
     29 CFLAGS += -g -werror -D$(MACRO)  
     30 AR = ar  
     31 ARFLAGES = crv  
     32   
     33 # default execute output directory  
     34 ifeq ($(DIR_EXES),)  
     35 DIR_EXES = $(TOPDIR)/build/out  
     36 endif  
     37   
     38 # defaulet libaray creat directory  
     39 ifeq ($(DIR_LIBS),)  
     40 DIR_LIBS = $(TOPDIR)/build/libs  
     41 endif  
     42   
     43 # directory  
     44 DIRS = $(DIR_OBJS) $(DIR_DEPS) $(DIR_EXES) $(DIR_LIBS)  
     45   
     46 # include directory   
     47 ifneq ($(DIR_INCS),"")  
     48 DIR_INCS := $(strip $(DIR_INCS))  
     49 DIR_INCS := $(addprefix -I,$(DIR_INCS))  
     50 endif  
     51   
     52 # when build execute file   
     53 ifneq ($(EXES),)  
     54 EXES := $(addprefix $(DIR_EXES)/,$(EXES))  
     55 RMS += $(EXES)  
     56 DIR_LIBS := $(strip $(DIR_LIBS))  
     57 DIR_LIBS := $(addprefix -L,$(DIR_LIBS))  
     58 endif  
     59   
     60 # when build static libaray file   
     61 ifneq ($(LIBS),"")  
     62 LIBS := $(addprefix $(DIR_LIBS)/,$(LIBS))  
     63 RMS += $(LIBS)  
     64 endif  
     65   
     66 # default source code file directory  
     67 ifeq ($(DIR_SRCS),)  
     68 DIR_SRCS = .  
     69 endif  
     70 SRCS = $(wildcard $(DIR_SRCS)/*.c)  
     71 OBJS = $(patsubst %.c, %.o,$(notdir $(SRCS)))  
     72 OBJS := $(addprefix $(DIR_OBJS)/,$(OBJS))  
     73 RMS += $(OBJS) $(DIR_OBJS)  
     74   
     75 DEPS = $(patsubst %.c, %.dep,$(notdir $(SRCS)))  
     76 DEPS := $(addprefix $(DIR_DEPS)/,$(DEPS))  
     77 RMS += $(DEPS) $(DIR_DEPS)  
     78   
     79 ifneq ($(EXES),"")  
     80 all : $(EXES)  
     81 endif  
     82   
     83 ifneq ($(LIBS),"")  
     84 all : $(LIBS)  
     85 endif  
     86   
     87 ifneq ($(LINK_LIBS),"")  
     88 LINK_LIBS := $(strip $(LINK_LIBS))  
     89 LINK_LIBS := $(addprefix -l,$(LINK_LIBS))  
     90 endif  
     91   
     92 # include dependent files   
     93 ifneq ($(MAKECMDGOALS), clean)  
     94 -include $(DEPS)  
     95 endif   
     96   
     97 $(DIRS):  
     98     mkdir -p $@  
     99   
    100 # creat execute file  
    101 $(EXES) : $(DIR_OBJS) $(OBJS) $(DIR_EXES)  
    102     $(CC) $(DIR_INCS) $(CFLAGES) -o $@ $(OBJS) $(DIR_LIBS) $(LINK_LIBS)  
    103   
    104 # creat libaray file  
    105 $(LIBS) : $(DIR_LIBS) $(DIR_OBJS) $(OBJS)  
    106 # library type is static  
    107 ifeq ($(LIB_TYPE),static)  
    108     $(AR) $(ARFLAGS) $@ $(OBJS)  
    109 endif  
    110   
    111 # library type is dynamic  
    112 ifeq ($(LIB_TYPE),dynamic)  
    113     $(CC) -shared -o $@ $(OBJS)  
    114 endif  
    115   
    116 # creat object file   
    117 $(DIR_OBJS)/%.o : $(DIR_SRCS)/%.c  
    118     @echo "source files:" $<  
    119     @echo "object files:" $@  
    120 ifeq ($(LIB_TYPE),static)  
    121     $(CC) $(DIR_INCS) $(CFLAGES) -o $@ -c $<  
    122 else  
    123     $(CC) $(DIR_INCS) $(CFLAGES) -fPIC -o $@ -c $<  
    124 endif  
    125   
    126 # creat depandant file  
    127 $(DIR_DEPS)/%.dep : $(DIR_SRCS)/%.c $(DIR_DEPS)  
    128     @echo "creating depend file ..." $@  
    129     @set -e;  
    130     $(CC) $(DIR_INCS) -MM $< > $@.tmp;  
    131     sed 's,$∗.o[ :]*,$(DIR_OBJS)/1.o $@ : ,g' < $@.tmp > $@  
    132 #   rm $@.tmp  
    133   
    134 clean:  
    135     rm -rf $(RMS)  

    这个makefile 没有什么好分析的和第二篇文章单目录工程makefile一样的。

    好了进入module1 下我们想把 module1编译成libmodule1.a 对应的Makefile 就很简单啦。

     1 # module1 Makefile      
     2 DIR_CUR = $(shell pwd)  
     3 DIR_SRCS = $(DIR_CUR)/src  
     4 DIR_INCS += $(DIR_CUR)/inc  
     5 DIR_OBJS = objs  
     6 DIR_DEPS = deps  
     7 DIR_LIBS = ../../build/libs/static  
     8 # library type an name  
     9 LIB_TYPE = static  
    10 LIBS = libmodule1.a  
    11 # LIB_TYPE = dynamic  
    12 # LIBS = libmodule1.so  
    13   
    14 include ../../rules.mk  

    这个makefile就是要配置输出文件路径和名字然后将顶层rules.mk包含就ok啦。

    同样的module2 目录下Makefile 也是一样的只要将LIBS 改为 libmodule2.a 即可。

    module3 的我们想把他编译成动态库 则对应为如下

     1 # module1 Makefile      
     2 DIR_CUR = $(shell pwd)  
     3 DIR_SRCS = $(DIR_CUR)/src  
     4 DIR_INCS += $(DIR_CUR)/inc  
     5 DIR_OBJS = objs  
     6 DIR_DEPS = deps  
     7 DIR_LIBS = ../../build/libs/static  
     8 # library type an name  
     9 #LIB_TYPE = static  
    10 #LIBS = libmodule3.a  
    11 LIB_TYPE = dynamic  
    12 LIBS = libmodule3.so  
    13   
    14 include ../../rules.mk  

    在project 中要编译main.c 又要链接前面生成的三个库 那对应的Makefile 如下:

     1 # Current directory  Makefile   
     2 CURDIR = $(shell pwd)  
     3   
     4 # executable file name  
     5 EXES = justest  
     6   
     7 # head file directories  
     8 DIR_INCS = module1/inc  
     9            module2/inc  
    10            module3/inc  
    11   
    12 # objs and dependant file directories  
    13 DIR_OBJS = objs  
    14 DIR_DEPS = deps  
    15   
    16 # static libraries   
    17 LINK_LIBS = module1 module2 module3  
    18   
    19 # library file directories  
    20 DIR_LIBS = $(TOPDIR)/build/libs/static  
    21            $(TOPDIR)/build/libs/dynamic  
    22   
    23 # include common rule makefile    
    24 include ../rules.mk  

    在这个makefile 只要配置生成的可执行文件的路径名,还有头文件目录,链接库的路径和名字就可以生成可执行文件了,这里也顶层的rules.mk。

    当然在实际应用中可以到各个模块中去执行make 但当想一次性生成可执行文件,则还需要一个顶层Makefile 。

     1 .PHONY: all clean  
     2   
     3 # sofeware version information  
     4 VERSION = 1  
     5 PROJECT = mk_demo  
     6 SUBLEVEL = 4  
     7 YEAL = 2013  
     8 RELEASE_VERSION = $(PROJECT).$(YEAL).$(VERSION).$(SUBLEVEL)  
     9   
    10 BUILD_DIRS = $(TOPDIR)/source/module1  
    11              $(TOPDIR)/source/module2  
    12              $(TOPDIR)/source/module3  
    13              $(TOPDIR)/source  
    14                
    15 all :  
    16 #   @shell(export TOPDIR=`pwd`)  
    17     @echo "version information:" $(RELEASE_VERSION)   
    18     @echo "building ..."  
    19     @set -e;  
    20     for dir in $(BUILD_DIRS);  
    21     do  
    22         cd $$dir && $(MAKE);  
    23     done  
    24     @echo ""  
    25     @echo "33[35m ~@^_^@~ 33[m"  
    26     @echo ""  
    27     @echo "Build Completed"  
    28   
    29 clean:  
    30     @echo "cleaning ...."  
    31     for dir in $(BUILD_DIRS);  
    32     do  
    33         cd $$dir && $(MAKE) clean;  
    34     done  
    35     rm -rf $(RMS)  
    36     @echo ""  
    37     @echo "Clean Completed"  
    38   
    39 version:  
    40     @echo $(TOPDIR)  
    41     @echo $(RELEASE_VERSION)  
    42     @echo $(BUILD_DIRS)  
    43     @echo $(RMS)  

    这里最关键的几句代码就是

    for dir in $(BUILD_DIRS)

    do

    cd $$dir && $(MAKE);

    done 

    在这里将进入各个模块目录下 执行make ,到这里一个稍微可以用工程makefile 工程实例,实现完了,其实只要模块划分好,还是很好理解的。我想说的时这种方法很常用,但不是唯一的,我有见过有些工程中也许并不需要每个模块都编译成库,或者说他要编译成库本身就是个很大的工程,一个模块的文件就特别多,目录结果就比较复杂这中该怎么写,先讲个思路,对应模块的Makefile 就搜索该目录下所以的Makefile 并包含进来。而子目录下的Makefile 将只将目录下需要编译的文件包含和路径包含经来就ok了,有时间也要总结下。

    至此非常感谢我参考的《驾驭Makefile》,《Makefile编程》,《GCC 中文手册》

  • 相关阅读:
    前后端渲染
    与你一起的日子
    Python 字符串转化成整形数组
    Python列出文件和目录
    Eclipse 导入Gson包
    java.lang.NoClassDefFoundError (Eclipse)
    成功的背后!(给所有IT人)
    事件与概率
    Servlet获取form表单上传文件及其他参数
    Servelt学习笔记之二——使用Servlet提取表单中的数据
  • 原文地址:https://www.cnblogs.com/computer1-2-3/p/7637443.html
Copyright © 2020-2023  润新知