总结第一遍阅读跟我一起写Makefile-陈皓,及结合项目Makefile,进一步深入理解Makefile

学习目标:

1、熟悉程序的编译和链接流程
2、熟悉Makefile的工作方式
3、对Makefile的语法规则、常用函数、常用参数有一定了解
4、结合对Makefile的理论理解阅读公司项目Makefile,总结Makefile的编写框架

学习内容:

一、程序的编译和链接流程

1、首先是编译,编译器将源文件编译成中间代码文件(Object文件),即".c"源文件编译成".o"目标文件,编译器在编译过程中只关心函数、变量在头文件中的声明和源文件语法是否正确,通常在编译时使用"CFLAGS"环境变量包含源文件有关的头文件;
2、编译完成后得到大量的Object文件,这时就需要链接器将大量的Object文件链接成为可执行文件,在链接过程中只关心函数的实现即函数在Object File中的实现位置,可是如果大量的源文件就会生成大量的Object文件,函数实现的找寻就会变得极不方便,这时我们就要给Object文件打个包成为".a"文件,即我们所说的静态库;

二、熟悉Makefile的工作方式
GNU 的 make 工作时的执行步骤入下:(想来其它的 make 也是类似)
1、读入所有的 Makefile。
2、读入被 include 的其它 Makefile。
3、初始化文件中的变量(相当于编译的展开宏)。
4、推导隐晦规则,并分析所有规则(自动推导)。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。

三、熟悉Makefile的语法规则、常用函数、常用参数
1、正所谓无规不成方圆,Makefile自然也有自己的规则,首先是最终的目标文件,一般是我们要执行的可执行文件,那我们怎么生成这个最终的目标文件呢,Makefile很巧妙的引出依赖关系,即我要生成这个目标文件需要依赖文件,那如果这个依赖文件也不存在呢?没关系,我们可以通过命令生成这个依赖文件,这个命令就是我们上述说到的编译和链接了,这就很简单的连成一条线了,即相当于main.o:main.c 由编译器将.c文件编译成为.o文件,main:main.o,链接器将.o文件链接成为目标文件;

2、依赖关系的实质上就是目标文件是由哪些文件更新的;

3、Makefile中使用变量$(object)使用这个变量

4、.PHONY:clean 表示clean是一个“伪目标”,如果直接clean: 放在第一位 就会变成make的默认目标,通常是all放在第一位,作为make默认目标;

5、显式规则:目标文件:依赖文件

6、隐晦规则:由于make自动推导功能,可以简约地书写Makefile,如已知目标文件".o",则可以省略写依赖文件.c,因为make可以自动推导Main.o依赖Main.c;

7、文件指示符号:类似C语言的include头文件、还有根据某些情况指定有效情况类似#if #else等、还有就是定义多行的命令如XXX|XXX|XXXX|;

9、Makefile命令中,必须要以【Tab】键开始,以便Makefile识别哪一个是命令

10、最好使用"Makefile"文件名、若要指定特定的Makefile、可以使用"-f"参数 如:make -f Make.Linux

11、-include $(DEP) make会包含DEP所在的目录,即包含依赖文件.d,并且-表示即使无法读取这个目录,不会报错继续执行;

12、objects := $(wildcard *.o) object的值是所有.o文件名的集合即 Main.o mq.o Cjson.o等

13、特殊变量"VPATH"类似Linux的环境变量,若在当前目录没有找到依赖文件或者目标文件,则会去VPATH定义的路径去寻找 如:VPATH = src:…/headers

14、关键字vapth 更灵活,可以搜寻目录下特定的文件 如:vpath %.c ajb_module_uart

15、若要生成多个可执行文件,可以使用伪目标特性:总是被执行的,即.PHONY:all all:prog1 prog2 prog3 all总是会被执行,即三个依赖文件也总是被重新生成

16、可以通过.PHONY: cleanall cleanobj cleandiff 达到清除不同文件类型的目的

17、静态模式:$(object):%.o:%.c 指明我们的目标从object变量中获取,目标模式%.o表示只取.o结尾的目标表示foo.o bar.o是目标,依赖模式%.c表示依赖目标是foo.c bar.c

18、$<表示依赖目标集 $@表示生成目标集

19、$(filter %.o,$(files)) 表示调用filter函数过滤,只留下%.o内容 因此可以结合静态模式实现不同类型的目标文件由.c---->.o

20、-MM 是编译器支持的一个选项,自动找寻源文件的包含的头文件,并且生成依赖关系 如cc -MM main.c 输出:main.o:main.c defs.h
而-M会把标准库的头文件也包含进来生成依赖关系

21、$(sources:.c=.d)中的.c=.d意思是将sources里面的所有[.c]子串都替换成【.d】;

22、显示命令时@字符在命令行前,可以隐藏命令、而带入参数“-n”可以显示命令,不执行命令

23、分号后命令才执行生效,即下条命令要在当前命令结果时生效,要加分号;

24、变量值得替换:“ ( v a r : . d = . o ) ” 将 v a r 中 所 有 以 . d 结 尾 的 子 串 替 换 为 . o 结 尾 类 似 的 静 态 模 式 也 是 “ (var:.d=.o)” 将var中所有以.d结尾的子串替换为.o结尾 类似的静态模式 也是“ (var:.d=.o)var.d.o(var:%.d=%.o)”

25、$(subst ( s p a c e ) , (space), (space),(comma),$(foo)) 将foo中的空格替换为逗号

26、$(patsubst %.c,%.o,x.c.c bar.c) x.c.c bar.c -------->x.c.o bar.o;

27、去空格函数strip 去掉子串的开头和结尾的空格;

28、$(foreach ,, ) 将list中的单词逐一取出并且放到临时变量var中后执行text的规则

29、调用隐含规则:已知【.o】的依赖文件是【.c】,那么将使用C的编译命令"cc -c [.o] $(CFLAGS)" 来生成[.o]目标,而不必用户明写;

30、模式规则:一旦依赖目标中的%确定后,make会被要求去匹配当前目录下所有的文件名,一旦找到则执行对应规则生成目标文件

31、$< 依赖目标中的第一个目标名

32、使用-MM选项生成文件的依赖关系 保存在.d文件中,生成的.d依赖文件包含.o目标文件的依赖关系,如:main.o:main.c cJson.h等,一旦增加.h文件或者减少.h文件都不用在Makefile中修改make会将旧的.d删掉重新生成新的依赖关系写入.d文件,编译得到新的.o文件,不用自己手动修改
33、-MT指定依赖规则中的目标;

四、结合阅读公司项目Makefile,总结Makefile的编写框架

1、#第一步是写好真正的Makefile->config.mk 指定好整个工程项目的源文件路径(即每个模块的路径 如 MODULE_NET=$(PWD)/src/ajb_module_net)、库文件(包括第三方库、动态库、静态库)、需要编译模块的变量、库文件变量、头文件变量、CFLAGS编译器参数、LDFLAGS链接器参数、编译器的名字、最终目标文件的路径、打印的字体格式等

2、#第二步是将外部的共享文件COMMON中的源文件,如mq.c等源文件 编译为.o、.d文件存放在OBJ文件中;主要是调用patsubst、foreach函数和Makefile的编译链接规则根据依赖关系生成.o和.d文件,并且包含依赖文件.d到Makefile中;
注意:
既然生成了依赖关系那么就需要存放在一个地方,这时就会通过-MF -MM生成依赖文件列表,而这个列表又能以-include 或者include 的形式添加到Makefile中

编译选项:
-MM 代表编译器会找寻源文件的头文件,并且生成依赖关系
-MF 指定存放的文件名
-MT 指定依赖关系的目标

如:
DEP := $(patsubst %.o,%.d, $(OBJ))
-include $(DEP)
$(OBJ_DIR)/%.d: %.c
$(PRINTF) “DEP @ " ; @"; @";(CC) ( C F L A G S ) − M M − M F " (CFLAGS) -MM -MF" (CFLAGS)MMMF"@” -MT"$(@:.d=.o)" $<

例如生成的依赖关系:main.d main.o = main.c cJson.h

①:MM生成依赖关系;
②:"(OBJ_DIR)/%.d"则是依赖关系存放的文件名;
③:"(OBJ_DIR)/%.o"则是依赖关系的目标;
④:$(CFLAGS)编译器的选项 指定头文件的路径
⑤:-include $(DEP)则是将这个依赖文件列表存放在Makefile中,以便下次更新;

3、#第三步是处理Src内部的模块,与上述同理,编译获得.o、.d文件放在OBJ文件中

4、最终是将OBJ目录下的所有.o文件和库文件(包括动态库、静态库、线程动态库和一些优化参数) 通过链接成为TARGET

整篇文档的编写参考了陈皓老师的跟我一起写Makefile(仅阅读了一遍,相信以后也要回头再看几遍才能深入领悟一些东西)和公司项目Makefile,并结合了自己对Makefile的理解,以及自己的学习历程。因为自己本身对Makefile并没有深入的了解,平时也只会敲命令make 、make clean、 make distclean 并不了解其中的运行原理,是直到有一个新项目需要移植语音模块、所以通过两天阅读和结合项目的Makefile,才初步对Makefile有一个更进一步的理解,那么一定会有很多地方存在表达问题,语言歧义或是错误。因些,我迫切地得等待各位给我指证和建议,以及任何的反馈、并且也希望大家能动手去实践,即使初始不能自己写出一个完好的Makefile也能完成一些小任务去修改Makefile里面的一些东西,通过打印去体验脚本的乐趣;

跟我一起 Makefile 作者:陈皓 整理:祝冬华 来源网络,希望能与大家分享这份学习资料,资源分数也设置了最低值,如有侵权,请联系我删除文件。 第一部分、概述 (6) 第二部分、关于程序的编译和链接 (6) 第三部分、Makefile 介绍 (7) 一、Makefile的规则 (7) 二、一个示例 (8) 三、make是如何工作的 (9) 四、makefile中使用变量 (10) 五、让make自动推导 (11) 六、另类风格的makefile (12) 七、清空目标文件的规则 (13) 第四部分、Makefile 总述 (13) 一、Makefile里有什么? (13) 1、显式规则。 (14) 2、隐晦规则。 (14) 3、变量的定义。 (14) 4、文件指示。 (14) 5、注释。 (14) 二、Makefile的文件名 (15) 三、引用其它的Makefile (15) 四、环境变量 MAKEFILES (16) 五、make的工作方式 (16) 第五部分、书规则 (17) 一、规则举例 (17) 二、规则的语法 (17) 三、在规则中使用通配符 (18) 四、文件搜寻 (19) 五、伪目标 (20) 六、多目标 (22) 七、静态模式 (22) 八、自动生成依赖性 (24) 第六部分书命令 (25) 一、显示命令 (26) 二、命令执行 (26) 三、命令出错 (27) 四、嵌套执行make (28) 五、定义命令包 (30) 第七部分使用变量 (30) 一、变量的基础 (31) 二、变量中的变量 (32) 三、变量高级用法 (34) 四、追加变量值 (37) 五、override 指示符 (37) 六、多行变量 (38) 八、目标变量 (39) 九、模式变量 (40) 第八部分使用条件判断 (40) 一、示例 (40) 二、语法 (42) 第九部分使用函数 (43) 一、函数的调用语法 (44) 二、字符串处理函数 (44) 1、subst (44) 2、patsubst (45) 3、strip (45) 4、findstring (46) 5、filter (46) 6、filter-out (46) 7、sort (47) 8、word (47) 9、wordlist (47) 10、words (47) 11、firstword (48) 12、字符串函数实例 (48) 三、文件名操作函数 (48) 1、dir (48) 2、notdir (48) 3、suffix (49) 4、basename (49) 5、addsuffix (49) 6、addprefix (49) 7、join (50) 四、foreach 函数 (50) 五、if 函数 (50) 六、call函数 (51) 七、origin函数 (51) “undefined” (52) “default” (52) “file” (52) “command line” (52) “override” (52) “automatic” (52) 八、shell函数 (53) 九、控制make的函数 (53) 1、error (53) 2、warning (54) 第十部分 make 的运行 (54) 二、指定Makefile (54) 三、指定目标 (55) “all” (56) “clean” (56) “install” (56) “print” (56) “tar” (56) “dist” (56) “TAGS” (56) “check”和“test” (56) 四、检查规则 (57) 五、make的参数 (57) 第十一部分隐含规则 (61) 一、使用隐含规则 (61) 二、隐含规则一览 (62) 1、编译C程序的隐含规则 (63) 2、编译C++程序的隐含规则 (63) 3、编译Pascal程序的隐含规则 (63) 4、编译Fortran/Ratfor程序的隐含规则 (63) 5、预处理Fortran/Ratfor程序的隐含规则 (63) 6、编译Modula-2程序的隐含规则 (63) 7、汇编和汇编预处理的隐含规则 (64) 8、链接Object文件的隐含规则 (64) 9、Yacc C程序时的隐含规则 (64) 10、Lex C程序时的隐含规则 (64) 11、Lex Ratfor程序时的隐含规则 (65) 12、从C程序、Yacc文件或Lex文件创建Lint库的隐含规则 (65) 三、隐含规则使用的变量 (65) 1、关于命令的变量。 (65) 2、关于命令参数的变量 (66) 四、隐含规则链 (67) 五、定义模式规则 (68) 1、模式规则介绍 (68) 2、模式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值