本记录仅用于记录自己makefile学习的知识点,侵权删!
跟我学makefile,极力推荐,神书!跟我一起写 Makefile(一)_《跟我一起写makefile》_haoel的博客-CSDN博客
makefile是为了自动化编译设计的,程序首先需要把源文件编译成中间代码文件,在win下为.obj文件,在unix下为.o文件,这个就是编译(compile)的过程,将大量的obj文件合成为执行文件就是链接过程(link)。
编译主要是负责语法的正确,函数与变量声明的正确,主要是告诉头文件所在位置(头文件中主要是申明,定义多在C/C++文件中,只要语法正确,编译器就可以编译出中间目标文件,一个源文件对应一个.o文件
链接时主要链接函数和全局变量,所以我们可以使用这个中间目标文件来连接我们的应用程序,连接器不管源文件,只管中间目标文件。在编译时,编译器只检测程序语法,和函数、变量是否被声明。如果函数未被声明,编译器会给出一个警告,但可以生成Object File。而在链接程序时,链接器会在所有的Object File中找寻函数的实现,如果找不到,那到就会报链接错误码(Linker Error),在VC下,这种错误一般是:Link 2001错误,意思说是说,链接器未能找到函数的实现。你需要指定函数的ObjectFile.
1、如果工程没有被编译过,那么所有的文件都要被编译并且链接
2、如果只是几个C文件被修改了,那么只编译修改的文件,并链接目标文件
3、如果工程的头文件被修改了,那么只要编译应用了这几个头文件的C文件并连接目标程序就行。
target... : prerequisites ...
command
...
...
其中target为目标文件,可以是object文件,也可以是执行文件,还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”中会介绍到。
prerequisite就是要生成那个target所需要的文件或者是目标文件
command就是make需要执行的命令(就是shell)命令
上面的规则意思就是文件的相对应的依赖关系,target的目标文件依赖于prerequisite中需要的文件,生成规则在command中,当prerequisite存在比target目标文件新的话,(主要看prerequisite中文件的时间戳),command就会被执行。
这里先介绍一下我觉得makefile中很重要的符号(参考下面这个博客):Makefile编译选项:CFLAGS、LDFLAGS、LIBS_趣多多代言人的博客-CSDN博客
CFLAGS:用于C编译器的选项
CXXFLAGS:表示用于C++编译器的选项
这两个变量涵盖了编译与汇编两个步骤;
CFLAGS = -Wall -werror -g -O
-Wall 允许gcc提供所有有用的报警信息
-werror 将所有报警信息转换为error
-w 关闭所有报警
-g 在可执行程序中包含标准调试信息
-I dir 在头文件搜索路径中添加dir目录
-L dir在库文件的搜索路径中添加dir目录
-On n表示优化级别的整数:0表示没有优化(优化的时候一般在嵌入式里面容易出现问题,比如最近在做的串口驱动和gcov测试覆盖率就不能用优化)1表示编译时使用默认优化。
-O0不做任何优化,默认的编译选项
-O1 对代码的分支、常量以及表达式等进行优化
-O2会尝试更多的寄存器优化,以及指令集的优化
下面在介绍一下makefile中经常用到的四种赋值方式
Makefile常用到的四种赋值方式(= := += ?=)说明_makefile 赋值_五彩缤纷的代码世界的博客-CSDN博客
符号= 表示最基本的赋值方式
符号:= 表示覆盖式赋值,会覆盖之前的值,也就是假如某变量在前面已经定义赋值过,将本次赋值作为最新的变量值。
符号+= 表示追加赋值,旧值保持不变,将新值追加在旧值后面
符号?= 表示当前面某变量已经定义赋值过的话就不执行本次定义赋值,否则执行本次赋值
在讲一讲makefile中的常见符号解析:
Makefile中的$@ $^等常见的符号解析_makefile $@_进阶牛牛的博客-CSDN博客
**$@**表示目标
**$^**表示所有的依赖
**$<**表示第一个依赖
-D就是在编译时将定义的宏传递到程序中
-o 生成指定的目标文件
-c将汇编文件生成一个二进制文件
-L指定库文件
-I编译时的头文件路径
-v查看gcc版本信息
在makefile中\(反斜杠)是指换行的意思。
make命令下:
1、make会在当前目录中寻找makefile或者Makefile文件
2找到以后会检索第一个目标文件(target),当第一个target不存在时,会把这个文件作为最终的目标文件
3、当第一个target不存在时或者target后面的.o文件时间戳比target文件的时间戳新时,会重新生成target文件。
4、如果target依赖的.o文件也存在时,那么makefile会继续寻找目标中.o文件的依赖性,也就是会一层一层的去寻找文件的依赖关系
.PHONY : clean clean : rm edit $(objects)-rm edit $(objects)
其中.PHONY表示clean是一个伪目标,而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”。
包含显示规则,隐晦规则,变量定义,文件指示和注释
- 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
- 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
- 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
- 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
- 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“\#”。
make命令开始时,会把找寻include所指出的其它Makefile,并把其内容安置在当前的位置。就好像C/C++的#include指令一样。如果文件都没有指定绝对路径或是相对路径的话,make会在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会在下面的几个目录下找:
1.如果make执行时,有“-I”或“--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。2.如果目录/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找。
-include
其表示,无论include过程中出现什么错误,都不要报错继续执行。和其它版本make兼容的相关命令是sinclude,其作用和这一个是一样的。
主要包含两个:1、依赖关系;2、生成目标的方法
在规则中使用通配符:
makefile支持三个通配符:“*”,“?”和“[...]”
波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是“~/test”,这就表示当前用户的$HOME目录下的test目录。而“~hchen/test”则表示用户hchen的宿主目录下的test目录。(这些都是Unix下的小知识了,make也支持)而在Windows或是MS-DOS下,用户没有宿主目录,那么波浪号所指的目录则根据环境变量“HOME”而定。
"*"
通配符代替了你一系列的文件,如“*.c”表示所以后缀为c的文件。一个需要我们注意的是,如果我们的文件名中有通配符,如:“*”,那么可以用转义字符“\”,如“\*”来表示真实的“*”字符,而不是任意长度的字符串。
每条规则中的命令和操作系统Shell的命令行是一致的。make会一按顺序一条一条的执行命令,每条命令的开头必须以[Tab]键开头,除非,命令是紧跟在依赖规则后面的分号后的。在命令行之间中的空格或是空行会被忽略,但是如果该空格或空行是以Tab键开头的,那么make会认为其是一个空命令。
make会将要执行的命令行输出到屏幕上,当用@字符在 命令行之前时,这个命令就不会被make显示出来
当依赖目标新于目标时,也就是当规则的目标需要被更新时,make会一条一条的执行其后的命令。需要注意的是,如果你要让上一条命令的结果应用在下一条命令时,你应该使用分号分隔这两条命令。比如你的第一条命令是cd命令,你希望第二条命令得在cd之后的基础上运行,那么你就不能把这两条命令写在两行上,而应该把这两条命令写在一行上,用分号分隔。如:
示例一:
exec:
cd /home/hchen
pwd
示例二:
exec:
cd /home/hchen; pwd
当我们执行“make exec”时,第一个例子中的cd没有作用,pwd会打印出当前的Makefile目录,而第二个例子中,cd就起作用了,pwd会打印出“/home/hchen”。