简单的makefile文件三种写法学习笔记

一个简单的示例项目有如下几个部分

1,makefile文件

2,src的目录,src目录中存在app.c,app.h,main.c,lib.c和bar.c几个文件

若使用手工编译则

gcc -o appexp src/main.c  src/app.c src/bar.c src/lib.c 

若使用makefile文件,则可以写一个最简单的makefile文件

第一种 最简单makefile文件

appexp:main.o app.o bar.o lib.o 
	gcc -o appexp main.o app.o bar.o lib.o 

main.o:src/main.c src/lib.h src/app.h
	gcc -c -o main.o src/main.c 

app.o:src/app.c src/lib.h src/app.h
	gcc -c -o app.o src/app.c 

bar.o:src/bar.c src/lib.h
	gcc -c -o bar.o src/bar.c 

lib.o:src/lib.c src/lib.h
	gcc -c -o lib.o src/lib.c 

以上是最简单的makefile文件

makefile文件包括规则 和命令两部分形式如下

规则  

  (tap)命令     
其中规则分为两部分 目标:依赖关系

如上例中 appexp:main.o app.o bar.o lib.o 此规则表明 目标为appexp,生成该目标所依赖的的文件为 main.o app.o bar.o lib.o

完成该规则所需要的命令为 gcc -o appexp main.o app.o bar.o lib.o

make会依次去查询每一个.o文件,如果全部存在且不存在时间上的错位则执行该命令,否则进一步去查找不存在或者需要重新生成的.o文件的规则。

make会把这些规则链接到一起,最后生成一个依赖树。make只对修改过的依赖进行重新生成。

make 并不管命令是如何工作的,他只管执行所定义的命令, make会比较目标文件和依赖文件的修改日期,若依赖文件的修改日期比目标文件要新,或者目标文件不存在,则make就会重新生成目标文件。所以若main.o app.o bar.o lib.o中 lib.c修改过,则会重新生成lib.o,并且重新生成appexp,但是未做修改的其余三个.o文件不进行重新生成。

 

----------------------------------------------------------------------------------------------------------------------------------------------------------

若工程较为简单,则使用以上的makefile可以解决问题,但是当工程较为负责的时候,相互依赖关系写起来就很麻烦,所以在makefile文件中可以使用一些函数或者通配符来进行比对

第二种是使用模式匹配规则的makefile文件

也是经常见的一种如下

 SRC_FILES = main.c app.c bar.c lib.c 
 OBJ_FILES = $(patsubst %.c , %.o, ${SRC_FILES}) 

VPATH = src 

CFLAGS = -c -g 
LDFLAGS = -g 

appexp:${OBJ_FILES}
	gcc ${LDFLAGS} -o appexp &{OBJ_FILES}

%.o:%.c
	gcc &{CFLAGS} -o $@ $ 

clean :
	rm *o appexp 

MAIN_HDRS = lib.h app.h 
LIB_HDRS = lib.h

main.o : $(addprefix src/,${MAIN_HDRS})
app.o : $(addprefix src/, ${MAIN_HDRS})
bar.o : $(addprefix src/, ${LIB_HDRS})
lib.o : $(addprefix src/,${LIB_HDRS})

这种方法利用了模式匹配,第一个SRC_FILES 变量保存着 所有的.c文件 第二行中的OBJ_FILES 变量中使用了patsubst函数将所有的.c文件转换为同名的.o文件,

并且保存在OBJ_FILES 中。

其实仔细看也会发现 makefile文件还是严格按照规则来的。

目标为appexp 依赖关系为 ${OBJ_FILES}  无非是使用了变量,这里可以将OBJ_FILES想想成是c语言中的宏替换,在使用时替换为其表示的字符串,不过不同于宏的是他是可以进行一些函数操作的。

紧接着的命令语句 gcc ${LDFLAGS} -o appexp &{OBJ_FILES}  如果直接翻译就翻译成 gcc -g -o appexp main.o app.o bar.p lib.o 其实和最简单的一种makefile是相同的。

%.o:%.c

            gcc &{CFLAGS} -o $@ $

这个就比较有意思,这个也是完全符合makefile规则的,%.o是目标 %.c是依赖文件  然后 gcc &{CFLAGS} -o $@ $ 是生成目标的命令。

这里用了通配符,解释之后其实也就是类似于main.o:main.c  .......等等 和第一种makefile写法也是一致的。

在命令中 使用到了$@ 和$ 其中$@代表规则中:(冒号)左边的文件名,$代表:(冒号)右边的文件名,规则可以看成是 $@ : $ 的形式,这样命令也相似的解释成了第一种版本的情况。

最后的MAIN_HDRS 和LIB_HDRS声明了头文件,并且最后说明了四个.o文件对头文件的依赖关系 。

main.o : $(addprefix src/,${MAIN_HDRS}) 翻译出来就是 main.o 依赖于src/lib.h 和src/app.h

这种makefile文件的扩展性比第一种要强,但是还是需要手动确定头文件依赖关系。还有一种makefile写法可以对依赖关系进行自动跟踪。

-----------------------------------------------------------------------------------------------------------------------------------------------

第三种,使用依赖跟踪的makefile

 SRC_FILES = main.c app.c bar.c lib.c 
 OBJ_FILES = $(patsubst %.c , %.o, ${SRC_FILES}) 
 DEP_FILES = $(patsubst %.c , %.dep, ${SRC_FILES})

VPATH = src 

CFLAGS = -c -g 
LDFLAGS = -g 

appexp:${OBJ_FILES}
	gcc ${LDFLAGS} -o appexp &{OBJ_FILES}

%.o:%.c
	gcc &{CFLAGS} -o $@ $ 

clean :
	rm *o appexp 

include ${DEP_FILES}

%.dep:%.c 
	@set -e ;rm -f $@;\
	gcc -MM $(CFLAGS) $<> $@.$$$$ ; \
	sed 's,\($*\)\.o[ :]*,\1.o $@ :,g' < $@.$$$$ > $@ ; \
	rm -f $@.$$$$


和第二种差不多,只是多了一个DEP_FILES 用来记录相应的DEP文件,.dep文件用于保存为相应源文件自动生成的依赖规则。

include ${DEP_FILES} 建立了makefile和.dep文件之间的依赖关系,当该makefile执行时,他会先找到所需要的.dep文件,并且必须等所有的.dep文件都找到了才进行make的执行。

下面这一段将.c文件生成.dep文件,这点还没弄太明白.

%.dep:%.c
                @set -e ;rm -f $@;\    #先清理掉.dep文件
                 gcc -MM $(CFLAGS) $<> $@.$$$$ ; \     # 使用c编译器产生基本的#include依赖规则
                 sed 's,\($*\)\.o[ :]*,\1.o $@ :,g' < $@.$$$$ > $@ ; \   #使用sed命令处理上一行的输出,使.dep文件依赖于相应源文件的依赖,当文件改变时,.dep也重新生成
                rm -f $@.$$$$

上文生成的dep文件其实和手动写的是一样的

比如说生成的main.dep文件的内容如下:

main.o main.dep : src/main.c src/lib.c src/app.h

 

以上的方法大多适用于较小的项目,因为对大项目来说,有automake和autoconf工具,可以比较方便的自动生成makefile文件。不过要读懂它 还是要学会这些基本的知识。

-------------内容部分参考自《GUN/LINUX环境编程》

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值