CSDN博客

img Achilles_Sea

Makefile在多文件项目中的使用心得

发表于2008/9/30 11:35:00  1047人阅读

      昨天为了用Makefile来编译一个几十个源码文件的项目,研究了下Makefile的用法,发现Makefile原来是这么强大,一点心得写在这里。
      首先发现原来的Makefile写的有些问题,文件中对最终生成的目标的依赖项只设了所有的cpp文件,类似于这样:
  1. all:target_program
  2. target_program: XXX.cpp ......
  3.       g++ -o target_program   XXX.cpp ......
      这样写虽然很方便,但是有个问题就是当某个cpp文件依赖的头文件有修改后,make不会检测到,这可能会造成一些莫名奇妙的问题。
      所以我就按照书上的标准格式,参照每个cpp文件依赖的头文件,手写依赖项……终于写完了,并make成功。事后发现自己真是有愚公移山的精神 -_-!
这样做的缺点很明显,工作量太大,而且一旦代码有改动,makefile也可能需要跟着改,很麻烦。于是我查看了一下Eclipse生成的makefile,发现里面写得像甲古文一样跟本看不懂,但是有一点,其中没有涉及到具体的代码文件,所以一定有更简单的方法。
      于是我就到网上找,资料很多,看了不少高手写的功能超强大的Makefile,可惜就是看不懂,所以就东拼西凑,找些尽量简单的来终于完成了一个比较通用又比较简单的Makefile。
  1. all:mserver
  2. # compiler
  3. CC = g++
  4. # include files directory
  5. INCLUDE = -I include
  6. # source files directory
  7. SRCDIR = source
  8. # lib
  9. LIBS = -lpthread -lrt
  10. # options for debug
  11. CFLAGS = -g
  12. # options for release
  13. #CFLAGS = -O
  14. # get name list of all source file 
  15. SRCS = ${wildcard ${SRCDIR}/*.cpp}
  16. # get name list of all object file
  17. OBJS = ${SRCS:.cpp=.o}
  18. # get name list of all dependency file
  19. DEPENDS = ${SRCS:.cpp=.d}
  20. # executable file
  21. FINAL_PROG = mserver
  22. all:${FINAL_PROG}
  23. # 重定义cpp到o的转化规则
  24. .SUFFIXES:  .cpp
  25. .cpp.o:
  26.      ${CC}  -c ${INCLUDE} $< -o $@
  27. # 定义新的后缀.d,并定义从cpp到d的转化规则
  28. .SUFFIXES:  .d
  29. .cpp.d:
  30.      ${CC} -M ${INCLUDE} $< > $@
  31. # 目标文件的依赖关系与生成规则
  32. ${FINAL_PROG}:${OBJS}
  33.      ${CC} ${CFLAGS}  ${LIBS}  ${OBJS}  -o $@
  34. # 加入自动生的的所有cpp文件的依赖规则
  35. -include ${DEPENDS}
  36. clean:
  37.      -rm -rf ${DEPENDS}  ${OBJS}
(要复制代码的朋友请注意:由于这个编辑器不能输入tab,故用空格代替,代码中缩进的部分都是一个tab;
另外,如果中文注释影响make就删掉)


下面对这个Makefile进行解释:
首先文件中定义了一些依赖于具体项目文件结构的MACRO,如头文件的位置,源文件的位置,编译参数等。其中:
  1. SRCS = ${wildcard ${SRCDIR}/*.cpp
这句的作用是从源文件目录中获得一个所有 cpp文件名的列表
wildcard是make内部定义的函数,能够展开一个正则表达式成为一个字符列列表,空格后面是其仅有的一个参数,代码中表示了SRCDIR目录中的所有cpp文件,故
${wildcard ${SRCDIR}/*.cpp}能返回cpp文件列表,这样免去了手动输入的麻烦。
  1. OBJS = ${SRCS:.cpp=.o}
是一个所有.o文件名的列表,它利用现成的MACRO SRCS,将其中的.cpp换成.o,SRCS:.cpp=.o就是这个意思。
  1. DEPENDS = ${SRCS:.cpp=.d}
是一个所有.d文件名的列表,什么是.d文件呢?这是笔者自定义的一个文件,比如main.cpp会有一个对应的main.d,
里面存的是main.cpp中所依赖的头文件,但这个文件是怎么生成的呢,请往下看。
  1. .SUFFIXES:  .d
  2. .cpp.d:
  3.     ${CC} -M ${INCLUDE} $< > $@
这句定义了从cpp到d的转化规则,定义之后当make需要.d文件的时候,就会把cpp文件按规则自动转换成d文件,它事实上是利用了g++的一个功能 -M,这个参数可以让g++输出一个对应某个cpp文件所依赖的头文件列表,如果要生成main.cpp的依赖列表可以这样:
g++ -M  -I includeDir  main.cpp
大家可以试一下这个命令,当然这里我们要将输出结果导到.d文件中,所以就构成了如下命令:
g++ -M  -I includeDir  main.cpp > main.d
Makefile中的命令就是根据这个而来的,只不过用了MACRO代替一些变量,其中:
$<与$@都是make内部定义的MACRO,$<表示当前依赖规则的被依赖项,$@表示目标项,
在.cpp.d:的转换规则定义中.d文件依赖于.cpp,故$<表示main.cpp,$@表示main.d
这样一个完整的依赖关系就能够非常方便的自动建立。

第一篇文章,不容易啊,大家支持一下 : )
0 0

相关博文

我的热门文章

img
取 消
img