[ linux-系统 ] 自动化构建工具makefile
00.引言
在软件开发中,构建是一个至关重要的步骤,它将源代码转换成可执行程序、库或者其他目标文件。然而,随着项目的复杂性增加,手动管理构建过程变得愈发困难。这就是为什么我们需要工具来自动化构建过程的原因之一。makefile就是这样的一种工具。
Makefile是一种文本文件,通常用于指定软件项目中的编译规则和依赖关系。Makefile文件通常由一个名为‘make’的构建工具简析和执行。简单地说,Makefile是一个文件,而make是执行文件的命令。
01.依赖关系与依赖方法
在Makefile中,目标由依赖关系和依赖方法组成。
我们先做一些准备工作,touch makefile ,然后vim 输入以下指令
依赖关系:code是目标文件,就是使用make指令所生成的文件,code.c是依赖文件,目标文件的形成依赖于这个文件,通过指定的命令实现构建。
依赖方法:是生成目标文件所执行的具体命令。
"gcc -o code code.c"是一个规则,指定了如何构建‘code’目标。
在Makefile中,可以使用‘$@’来表示目标文件,使用‘$^’来表示依赖文件
code: code.c
gcc -o $@ $^
这里执行指令后,指令是会显示在终端的
如果想隐藏指令,可以在前面加上‘@’
02make运行规则
makefile 在形成文件时会自顶而下扫描,默认只会形式第一个目标文件,执行该依赖关系的依赖方法
上下位置调换,发现确实是执行第一个目标文件clean
假设我们有以下文件依赖
hello: hello.o
hello.o: hello.s
hello.s: hello.i
hello.i: hello.c
使用 gcc
命令编译不同中间文件
在上述例子中,hello
是最终目标文件,它依赖于目标文件 hello.o
,而后者又进一步依赖于 hello.s
,如此递归下去直到源文件 hello.c
。
1.make 命令查找名为 Makefile 或 makefile 的文件。
2.读取文件并找到第一个目标文件,在本例中是 hello。
3.如果 hello 不存在,或其依赖文件中任何一个文件比 hello 更新,则生成 hello 文件。
4.递归检查每个依赖文件,按顺序进行必要的编译步骤。
5.如果出现错误,make 退出并报错。
6.如果依赖文件仍然不在,make 也将退出
03清理项目与伪目标
工程经常需要清理生成的中间文件和目标文件,Makefile 提供了方便的清理机制。通过定义伪目标,可以确保 make clean
总能执行对应的清理命令。
代码:
clean 没有依赖文件,也是存在依赖关系的,只不过这个 clean 没有依赖列表
.PHONY
用于标记 clean
为伪目标,无论当前目录下是否有 clean
文件或目标,make clean
命令都会执行。
make命令执行了一次就不能再执行了
看以下代码和运行结果可以得出结论 .PHONY总是被执行
如果没有.PHONY 为什么make一次就不能再make了?
提高效率!!
怎么做到的?
可执行程序的时间比源文件时间新,就不能再make了
stat 指令查看文件的三个时间(ACM)
Access Time (访问时间)
Modify Time (修改时间) -> 属性被修改
Change Time(更改时间) -> 内容被修改
Make 基于文件时间戳(modify time
)判断是否需要重新构建目标。如果目标文件的修改时间比其依赖文件新,则默认认为目标是最新的,不会重新执行命令。
如下图目标文件hello比依赖文件hello.c新,就不会重复执行make
这时候我们把依赖文件hello.c做一下修改,发现目标文件比依赖文件旧,就会执行make
综上:得出结论
make通过对比你的目标文件和依赖文件的更改时间 (modify time) 识别的新旧
目标文件比依赖文件新,就不会重新make
我们打开文件修改,Access 应不应该改变呢?我们读取 Access 变不变?
要变的!但是现在不会变!因为访问文件的频率是最高的,Modify 和 Change 是不得不变的,不变的化文件就不对了。但是我们大多数情况修改文件属性和修改文件内容是很低频的事情,但打开文件是非常高平的事情,Linux 后期内核对 Access 进行了优化,将文件打开访问,打开时间不会变化,累计一段时间后他才会变化。如果不这样,打开文件这种高频率的事情,一旦更新 Access 时间,就要将数据刷新到磁盘上,这实际上一个很没效率的事情
具体 Access 的调整策略取决于 Linux 的版本
补充:
变量允许在Makefile中定义和使用
在Makefile中可以使用‘#’符号添加注释