makefile学习记录

本记录仅用于记录自己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.

makefile中的编译规则是:

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中\(反斜杠)是指换行的意思。

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的内容

包含显示规则,隐晦规则,变量定义,文件指示和注释

  1. 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
  2. 隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
  3. 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
  4. 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
  5.  注释。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<filename>

其表示,无论include过程中出现什么错误,都不要报错继续执行。和其它版本make兼容的相关命令是sinclude,其作用和这一个是一样的。

makefile的书写规则:

主要包含两个:1、依赖关系;2、生成目标的方法

在规则中使用通配符:

makefile支持三个通配符:“*”,“?”和“[...]”

波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是“~/test”,这就表示当前用户的$HOME目录下的test目录。而“~hchen/test”则表示用户hchen的宿主目录下的test目录。(这些都是Unix下的小知识了,make也支持)而在Windows或是MS-DOS下,用户没有宿主目录,那么波浪号所指的目录则根据环境变量“HOME”而定。

"*"
通配符代替了你一系列的文件,如“*.c”表示所以后缀为c的文件。一个需要我们注意的是,如果我们的文件名中有通配符,如:“*”,那么可以用转义字符“\”,如“\*”来表示真实的“*”字符,而不是任意长度的字符串。

makefile书写命令:

每条规则中的命令和操作系统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”。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值