一种可自动实现增量编译的Makefile模板

Makefile介绍

程序的生成可分为预处理 编译 汇编 链接这几个阶段,各个阶段的功能不再赘述。对于平时写的各种小程序,并不需要很精细的管理。如果某一处发生了改动,直接把所有文件把的所有阶段全都执行一遍。当工程比较小的时候怎么做没有问题,但一旦工程比较大,就需要选择性的进行编译、链接等操作,否则会消耗很多时间。当源码有改动时,只对改动所能影响到的文件进行重构,这就是增量编译的概念。
Makefile 可以简单的认为是一个工程文件的编译规则,描述了整个工程的编译和链接等规则。其中包含了那些文件需要编译,那些文件不需要编译,那些文件需要先编译,那些文件需要后编译,那些文件需要重建等等。编译整个工程需要涉及到的,在 Makefile 中都可以进行描述。换句话说,Makefile 可以使得我们的项目工程的编译变得自动化,不需要每次都手动输入一堆源文件和参数。
Makefile是Linux下进行多文件编程的必备技能。本篇博客给出了一种比较方便的Makefile方案,由于本人也是初学者,如果方案有任何不合理或者可改进之处,可进行指正,请大家多多支持。

设计要点

在编写程序的时候,所做的改动无非就是源文件和头文件的改动。如果改动了源文件,则对应的目标文件和可执行程序就需要重新生成。比较麻烦的是头文件的改动,一旦头文件改动,那么任何包含它的源文件亦需要重新生成。
那么如何知道头文件会影响哪些源文件,或者说源文件依赖于哪些头文件呢?很幸运的是,gcc编译器有-MM选项,可以自动的得出源文件的依赖文件。
在本博客的Makefile里,就是利用了该功能,把依赖关系写进文件中,在通过读取文件的方式读入Makefile里。
本案例的Makefile包含以下相关知识:

  • Makefile的运行原理
  • Makefile变量和函数的使用
  • Makefile通配符 * %
  • Makefile自动化变量 $@ $<
  • Makefile搜索路径 vpath
  • Makefile文件包含 -include
  • Makefile伪目标 .PHONY
  • GCC编译器的 -c -MM功能

使用方法

  • 创建文件夹,分别用于存放头文件、源文件、目标文件等。
  • 分别把头文件和源文件放入指定的目录中
  • 创建Makefile文件,把代码复制进去
  • 根据自己创建的目录,修改Makefile中的内容
  • 指定编译器以及语言标准等编译选项
  • 执行make命令
  • 修改源码,再次执行make命令

以源码分享中的Makefile为例,其文件目录结构为
与源码对应的文件结构
Makefile 就是含有源码的Makefile文件
obj文件夹 用于存放 目标文件.o 和 依赖文件 .d
src文件夹 用于存放C语言源文件.c
inc文件夹 用于存放C语言头文件.h
bin文件夹 用于存放生成的可执行文件

当然,文件目录 可执行文件名 编译器 等等都可以进行修改,把所有文件存放在一个目录 或者 用多个文件夹存放源文件等也可以,只要在Makefile文件里修改对应参数即可。

源码分享

#当前文件夹
CUR_DIR = .#$(shell pwd)
#源文件夹 可包含多个
SRC_DIR = $(CUR_DIR)/src
#头文件夹 可包含多个
INC_DIR = $(CUR_DIR)/inc
#可执行文件夹 
BIN_DIR = $(CUR_DIR)/bin
#中间文件夹 
OBJ_DIR = $(CUR_DIR)/obj
#依赖文件夹 
DEP_DIR = $(CUR_DIR)/obj
#可执行文件名
EXCU = main.out
#编译器: gcc g++
CC = gcc
#源文件后缀名: c cpp *
SUFFIX = c
#编译选项: 
#C常用标准: c89 c99 gnu90 gnu99 gnu11 
#C++常用标准: c++98 c++11 gnu++98 gnu++11
CFLAGS = -g -Wall -std=gnu99
CPATH = $(addprefix -I,$(INC_DIR))
#--------------------------------------------------------------------
#文件集合
SRCS = $(wildcard $(addsuffix /*.$(SUFFIX),$(SRC_DIR)))
OBJS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(basename $(notdir $(SRCS)))))
DEPS = $(addprefix $(DEP_DIR)/,$(addsuffix .d,$(basename $(notdir $(SRCS)))))
BINS = $(BIN_DIR)/$(EXCU)
#Makefile路径设置
vpath
vpath %.c $(SRC_DIR)
vpath %.h $(INC_DIR)
vpath %.o $(OBJ_DIR)#重要 用于寻找目标%.o
vpath %.d $(DEP_DIR)#重要 用于寻找目标%.d

#第一个目标
all:$(BINS)

#包含依赖文件 没有则不包含 继续执行
-include $(DEPS)#文件名为%.d 内部目标名为 %.o 没有路径

#链接 生成可执行文件 利用 %.o 的依赖信息
$(BINS):$(notdir $(OBJS))
	$(CC) $(OBJS) $(CFLAGS) $(CPATH) -o $(BINS) 

#生成.o和.d文件
 %.o:%.c
	$(CC) $< $(CFLAGS) $(CPATH) -c -o $(OBJ_DIR)/$@ 
	@$(CC) $< $(CFLAGS) $(CPATH) -MM -o $(DEP_DIR)/$(basename $(@F)).d 

#清理文件
.PHONY:clean
clean:
	rm -f $(BINS) $(OBJS) $(DEPS)

改进方向

由于本人的学识、时间和精力所限,对于静态库和动态库的支持还有待完善。在后续的改善中,可着手于对库文件使用和生成进行优化。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值