5.10 Makefile 的使用
Gcc是可以编译文件,成千上万个文件都要编译的时候就头疼了,所以衍生出makefile。另外,参照Visual Studio中只去编译修改了的文件而不是所有文件都去修改,提高编译速度,节省时间,makefile要做就是学习VS的这种自动识别修改的文件并编译它。免责申明,应该不会侵权的吧。
objs := main.o sub.o
test : $(objs)
gcc -o test $^
# 需要判断是否存在依赖文件
# .main.o.d .sub.o.d
dep_files := $(foreach f, $(objs), .$(f).d)
dep_files := $(wildcard $(dep_files))
# 把依赖文件包含进来
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc -Wp,-MD,.$@.d -c -o $@ $<
clean:
rm *.o test -f
distclean:
rm $(dep_files) *.o test -f
理清楚是怎么一步一步演变过来的,用到的函数都是什么意思作用是什么???
make命令根据文件更新的时间戳来决定哪些文件需要重新编译,这使得可以避免编译已经编译过的、没有变化的程序,可以大大提高编译效率。
通用的格式是:
目标(target)…: 依赖(prerequiries)…
<tab>命令(command)
如果“依赖文件”比“目标文件”更加新,那么执行“命令”来重新生成“目标文件”。命令被执行的2个条件:依赖文件比目标文件新,或是目标文件还没生成。
5.10.1makefile改进分析
演示main.c、sub.c和sub.h,
第1版Makefile:
test : main.c sub.c sub.h
gcc -o test main.c sub.c
这版Makefile有什么缺点呢?在执行make命令时,会把所有的依赖文件(.c和.h)都编译一遍,而不是像VS那样只编译修改的文件,怎么完善呢?
第2版Makefile:
test : main.o sub.o
gcc -o test main.o sub.o
main.o : main.c
gcc -c -o main.o main.c # -c是只编译不链接
sub.o : sub.c
gcc -c -o sub.o sub.c
clean:
rm *.o test -f #强制删除所有.o文件,test文件
改进:用.o文件替换.c文件作依赖文件,比如修改了sub.c,只会去编译生成sub.o,而main.c不会去编译,提高效率。
不足:如果有很多的.c文件,需要些很多的.o文件,能不能使用什么符号替代所有的.c文件和对应生成的.o文件。
第3版Makefile:
test : main.o sub.o
gcc -o test main.o sub.o
%.o : %.c #使用%代替所有的文件
gcc -c -o $@ $< # $@代表所有的目标文件,$^代表所有的依赖文件,$< 第一个依赖文件
clean:
rm *.o test -f
改进:用%代替对应的文件,用$@代替所有的目标文件,用$^代替所有的依赖文件,$<表示第一个依赖文件,这样就不用把所有的.c文件都写出来了。
不足:好像是没有体现依赖.h,如果修改.h中的内容,make会漏掉.h中的内容,参照前面的内容看可以把.h加到依赖文件中啊,%.o : %.c %.h,说是不好加,不知道为什么。
第4版Makefile:
test : main.o sub.o
gcc -o test main.o sub.o
%.o : %.c
gcc -c -o $@ $<
sub.o : sub.h #只有目标和依赖,没有命令
clean:
rm *.o test -f
改进:添加sub.o和sub.h的依赖关系,并不做什么命令,只是将sub.h也加到sub.o的依赖文件中。
不足:如果.h文件很多,岂不是也得一个一个手动添加,也是很麻烦的。
第5版Makefile:
test : main.o sub.o
gcc -o test main.o sub.o
%.o : %.c
gcc -Wp,-MD,.$@.d -c -o $@ $<
clean:
rm *.o test -f
改进:添加-Wp,-MD,.$@.d,意思是.c文件生成依赖文件.main.o.d和.sub.o.d,打开.main.o.d如图x,看到其实就是一条封装的make指令,目标文件为sub.o,依赖文件是sub.c和各种.h(sub.h)头文件,它会自动把用到的.h头文件包含进来,这样就不用一个一个去手动添加头文件的包含了。
不足:需要判断是否存在这些依赖文件,。
第6版Makefile:
objs := main.o sub.o
test : $(objs )
gcc -o test $^
#生成依赖文件.main.o.d .sub.o.d
dep_files := $(foreach f, $(objs), .$(f).d)
#判断是否已经生成依赖文件
dep_files := $(wildcard $(dep_files))
#把依赖文件包含进来
ifneq($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc -Wp,-MD,.$@.d -c -o $@ $<
clean:
rm *.o test -f
disclean:
rm $(dep_files) *o test -f
改进:在原有的基础上有有所改进,用到2个函数,先说下2个函数。
A.$(foreach var,list,text),把参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式。
B.$(wildcard PATTERN…)在Makefile规则中,通配符会被自动展开。但在变量的定义和函数引用时,通配符将失效。这种情况下如果需要通配符有效,就需要使用函数“wildcard”,它的用法是:$(wildcard PATTERN…) 。
不足:不支持子目录文件。
5.10.2通用Makefile的使用
韦老师参考Linux内核的Makefile编写了一个通用的Makefile,它可以用来编译应用程序:
① 支持多个目录、多层目录、多个文件;
② 支持给所有文件设置编译选项;
③ 支持给某个目录设置编译选项;
④ 支持给某个文件单独设置编译选项;
⑤ 简单、好用。
自己总结了一个执行顺序图:
makefile的具体内容和解释可以看韦老师的视频和分析文档。