Makefile研究(二)—— 完整可移植性模板

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

一直想写一个很全很好移植的Makefile模板,我觉得一个完整makefile 应该包含如下内容。 

1、可以编译成 动态库.a  静态库.so  或者是直接编译成可执行文件。

2、编译可执行文件可以指定宏 ,自有添加头文件,指定链接的各种库

3、要能过自动生成依赖关系,能准确地捕捉到任何依赖文件的改动。

4、如果是嵌入式系统应该还要指定链接脚本(这里暂不考虑)

下面是我写的一个具备上面1-3点的makefile

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

对整个makefle 分析如下:

1、line   23-33

是当我们要将源代码编译成可执行文件还是静态库,还是动态库在这里配置就可以

DIR_OBJS 为目标文件输出目录,DIR_DEPS为依赖文件输出目录,DIR_INC为包含头文件的目录。

LINK_LIBS 为当生成可执行文件如果需要链接外面的库,则在这里指定库的名字。

DIR_LIBS 为库的路径,LIBS 为库的 libXX.so 或 libXX.a 格式的名字。

2、line   38 - 34

为gcc 编译相关

COPTION  为编译优化等选项

MACRO   为编译时定义的宏配置

3、line 44 - 109

这些都是根据前面是生成可执行文件还是库的对应的输出配置,以及目标依赖关系

4、line 19 - 121

生成可执行文件的语句

5、line 123 - 133

生成静动态库的语句

6、line 146 - 150

这可以是整个makefile 的关键所在,这是生成依赖文件的地方,有人会问编译代码不就是将.c --> .o ----> 可执行文件么,表面上是这样。

但实际上很多时候我们编译c但还包含了.h 或者是其他配置文件,当这时候.h和配置文件改变了,但当已经完整make后,但make却没检查到这种改变,导致修改后的文件无法编译进去,这时候只能make clean 才能make 。大工程中这个明显浪费很多时间。其实不能怪make不够只能,那是因将这些配置文件作为依赖关系包含进去。而makefile 只检查目标文件所依赖的文件的更新。

在gcc 中有一个MM 很好地解决这个问题,假如 test.c 除了包含了头文件还包含了test.h test1.h 那么

gcc -MM test.c

结果为 test.o : test.c test.h test1.h

sed 命令应用有点复杂但他的作用加上必要的路径,输出到test.dep文件中,这个方法在uboot 和 android ,Linux 编译系统中使用的。

这样一个比较完整的单目录结果makefile 就写好,我们可以根据自己的需要配置成是生成可执行文件还是库,很方便移植到不是很复杂的应用当中去。

原文地址:https://www.cnblogs.com/computer1-2-3/p/7637421.html