一.make/makefile简介
1.什么是make,makefile?
make
是一个构建C++项目的工具/命令;makefile
是一个包含编译命令的脚本文件。通过make工具解释makefile文件中的命令,进行我们的项目编译。
2.为什么要有make/makefile?
Linux环境下开发,工程源文件较少时,可使用gcc直接编译;但当工程源文件较多时,gcc直接编译复杂(比如命令较多,文件的编译先后顺序确定问题等)且不易于后期项目的维护,因此采用make/makefile做到自动化编译,有益于项目开发。
二.makefile文件规则
1.基本规则
target:prerequisites command
makefile文件书写基本规则:
就像做好一道菜道,需要有其依赖的食材,还得依赖厨师的好厨艺!
目标:target,要生成的目标文件,往往是程序的中间文件或者最终的文件,比如test.i,test.s,test.o,test
依赖:prerequisites,目标文件由哪些文件生成,往往有的一个或多个
命令:command,通过执行该命令从依赖文件得到目标文件,需要注意命令前必须有一个[tab键],可以有多个命令,但是必须每个命令独占一行!
makefile中的[tab键]不可省略,更不可用空格代替,[tab键]不等于4个空格也不等于8个空格,1个tab键实际是4个字符,只不过代表的是4个字符.
2.举一个例子
Makefile文件如下:
ps:
- makefile文件名也可叫:
Makefile
- makefile文件中注释用“
#
”
test:test.c #依赖关系 gcc test.c -o test #依赖方法 .PHONY:clean clean: rm -rf test
这个.PHOINY是什么东西?我待会会讲到
:wq!退出vim后我们怎么用好makefile文件呐?
3.伪目标
介绍伪目标前我们先讲一讲实目标的概念:
实目标:命令执行后真正要生成的文件名, test就是实目标
伪目标:命令执行后不会生成实际文件,常用于辅助操作, .PHONY是伪目标的标注符,clean是伪目标,不会生成实际名为clean的文件.
伪目标的特点:伪目标可以总是被执行[为什么后面讲]
4.其他规则
变量名 | 含义 |
$@ |
目标文件,可表示test |
$^ |
所有的依赖文件,可表示test.c |
$< |
第一个依赖文件 |
test:test.c @gcc $^ -o $@ .PHONY:clean clean: @rm -rf test
@: 不带@在命令行执行make的时候,会将所执行的命令回显到终端,带@则不回显
为什么在命令行执行的时候,执行第一组依赖关系和依赖方法的命令是make,执行第二组依赖关系和依赖方法的命令却是make clean?
实际上,第一我们默认第一组依赖关系和依赖方法也可以写全成: make test
只不过我们规定第一组可以省略test,只写make
三.文件三个时间问题-make程序
1.三个时间何时更新
我们知道: 文件=文件内容+文件属性
通过stat + 文件名可以查看文件的状态:
[li@VM-8-5-centos 1-7]$ stat test.c File: ‘test.c’ Size: 74 Blocks: 8 IO Block: 4096 regular file Device: fd01h/64769d Inode: 924282 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 1002/ li) Gid: ( 1002/ li) Access: 2023-01-07 18:48:21.189648157 +0800 Modify: 2023-01-07 18:48:17.476581743 +0800 Change: 2023-01-07 18:48:17.476581743 +0800 Birth: -
因为文件一定要被访问,才能完成文件内容的修改,所以Modify更新,Access一定也会更新
因为文件内容被修改,文件大小一定发生改变,所以Modify更新,Change一定也会更新
但是Access/Change改变并不会造成另外两个时间也改变
回顾一下文件属性:
Linux文件或目录的属性主要包括:文件或目录的节点、种类、权限模式、链接数量、所归属的用户和用户组、最近访问或修改的时间等内容。
-rw-rw-r-- 1 li li 62 Jan 7 18:47 Makefile -rwxrwxr-x 1 li li 8360 Jan 7 20:55 test -rw-rw-r-- 1 li li 74 Jan 7 18:48 test.c
2.touch的两个作用
我们知道touch命令可以创建一个文件,还有一个作用就是对现有文件更新这三个的时间为系统时间.
touch test//不带选项,atime,mtime,ctime都更新 touch test -a//atime更新 touch test -m//mtime更新 touch test -c//ctime更新
3.make程序如何知道依赖文件是否更新?
肯定是先有test.c再有test文件,这就意味着一开始, test.c的修改时间一定是比test的修改时间旧.
如果make程序发现test的最后一次修改时间居然比test.c的最后一次修改时间旧,那么说明test.c一定在test最后一次修改过后,又修改过,所以make的时候,就能将依赖方法执行成功,反之也成立!
到这里我们也能解释为什么.PHONY有一个特点:被.PHONY修饰的总是能被执行,那可能就是.PHONY修饰后不再通过比较test和test.c的修改时间来判断是否要重新编译!