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

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

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

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

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

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


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

# Generic Makefile for C/C++ Program
# Author: 
# Description: 
# This is an easily customizable makefile template. The purpose is to
# provide an instant building environment for C/C++ programs.
#
# It searches all the C/C++ source files in the specified directories,
# makes dependencies, compiles and links to form an executable.
#
# Besides its default ability to build C/C++ programs which use only
# standard C/C++ libraries, you can customize the Makefile to build
# those using other libraries. Once done, without any changes you can
# then build programs using the same or less libraries, even if source
# files are renamed, added or removed. Therefore, it is particularly
# convenient to use it to build codes for experimental or study use.
#
# GNU make is expected to use the Makefile. Other versions of makes
#

.PHONY : all clean

# Curstomer build output file directory and filename
EXES = 
DIR_EXES = 
DIR_OBJS = 
DIR_DEPS =
DIR_INCS = 

LINK_LIBS = 
LIBS_TYPE = dynamic  
#LIBS_TYPE = static
DIR_LIBS = 
LIBS = 

# Top directory  Makefile
CURDIR = $(shell pwd)

# The C program compiler
COPTION = -O2 
MACRO = -DDEBUGALL 
CFLAGS += -g -werror $(MACRO) $(COPTION)
CC = gcc
AR = ar
ARFLAGES = crv

# default execute output directory
ifeq ($(DIR_EXES),)
DIR_EXES = $(TOPDIR)/build/out
endif

# defaulet libaray creat directory
ifeq ($(DIR_LIBS),)
DIR_LIBS = $(TOPDIR)/build/libs
endif

# directory
DIRS = $(DIR_OBJS) $(DIR_DEPS) $(DIR_EXES) $(DIR_LIBS)

# include directory 
ifneq ($(DIR_INCS),"")
DIR_INCS := $(strip $(DIR_INCS))
DIR_INCS := $(addprefix -I,$(DIR_INCS))
endif

# build execute file 
ifneq ($(EXES),)
EXES := $(addprefix $(DIR_EXES)/,$(EXES))
RMS += $(EXES)
DIR_LIBS := $(strip $(DIR_LIBS))
DIR_LIBS := $(addprefix -L,$(DIR_LIBS))
endif

# build libaray file 
ifneq ($(LIBS),"")
LIBS := $(addprefix $(DIR_LIBS)/,$(LIBS))
RMS += $(LIBS)
endif

# default source code file directory
ifeq ($(DIR_SRCS),)
DIR_SRCS = .
endif 

# scan source code 
SRCS = $(wildcard $(DIR_SRCS)/*.c)
OBJS = $(patsubst %.c, %.o,$(notdir $(SRCS)))
OBJS := $(addprefix $(DIR_OBJS)/,$(OBJS))
RMS += $(OBJS) $(DIR_OBJS)

# dependant file 
DEPS = $(patsubst %.c, %.dep,$(notdir $(SRCS)))
DEPS := $(addprefix $(DIR_DEPS)/,$(DEPS))
RMS += $(DEPS) $(DIR_DEPS)

# build execute file 
ifneq ($(EXES),"")
all : $(EXES)
endif

# build library 
ifneq ($(LIBS),"")
all : $(LIBS)
endif

# link libs name 
ifneq ($(LINK_LIBS),"")
LINK_LIBS := $(strip $(LINK_LIBS))
LINK_LIBS := $(addprefix -l,$(LINK_LIBS))
endif

# include dependent files 
ifneq ($(MAKECMDGOALS), clean)
-include $(DEPS)
endif

$(DIRS):
	mkdir -p $@

# creat execute file
$(EXES) : $(DIR_OBJS) $(OBJS) $(DIR_EXES)
	$(CC) $(DIR_INCS) $(CFLAGES) -o $@ $(OBJS) $(DIR_LIBS) $(LINK_LIBS)

# creat libaray file
$(LIBS) : $(DIR_LIBS) $(DIR_OBJS) $(OBJS)
# library type is static
ifeq ($(LIB_TYPE),static)
	$(AR) $(ARFLAGS) $@ $(OBJS)
endif

# library type is dynamic
ifeq ($(LIB_TYPE),dynamic)
	$(CC) -shared -o $@ $(OBJS)
endif

# creat object file 
$(DIR_OBJS)/%.o : $(DIR_SRCS)/%.c
	@echo "source files:" $<
	@echo "object files:" $@
ifeq ($(LIB_TYPE),static)
	$(CC) $(DIR_INCS) $(CFLAGES) -o $@ -c $<
else
	$(CC) $(DIR_INCS) $(CFLAGES) -fPIC -o $@ -c $<
endif

# creat depandant file
$(DIR_DEPS)/%.dep : $(DIR_SRCS)/%.c $(DIR_DEPS)
	@echo "creating depend file ..." $@
	@set -e;\
	$(CC) $(DIR_INCS) -MM $< > $@.tmp;\
	sed 's,\($*\)\.o[ :]*,$(DIR_OBJS)/\1.o $@ : ,g' < $@.tmp > $@

clean:
	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 就写好,我们可以根据自己的需要配置成是生成可执行文件还是库,很方便移植到不是很复杂的应用当中去。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值