文章目录
- 🍈0. 前言
- 🍉1. 见见猪跑
- 🍊2. 依赖关系和依赖方法
- 🍋3. 清理
- 🍌4. 不可多次编译的原理
- 🍍4.1 原因
- 🍍4.2 stat命令
- 🍍4.3 验证
- 🥭5. 伪目标
- 🍎6. 取消回显
🍈0. 前言
我们使用gcc/g++编译代码时,每次都要输入一长串的指令,对于单个文件或者文件较少的时候,我们还能接受,可是当文件较多的时候,我们再一个一个编译,就会比较麻烦。Linux中make
命令加上Makefile
文件搭配使用,就可以完成项目的自动化构建。
🍉1. 见见猪跑
C代码
#include<stdio.h>
int main()
{
printf("hello linux\n");
printf("hello linux\n");
printf("hello linux\n");
return 0;
}
创建makefile文件
mkdir makefile
写入依赖关系、依赖方法
code:code.c
gcc -o code code.c
clean
rm -f code
执行make命令
这一套流程下来,就是简单的自动化编译与清理,这里要清楚的是make
是一个命令,而makefile
是一个文件。下面我们来讲解一下这其中原理。
🍊2. 依赖关系和依赖方法
打个比方:
期末考试考完了,在路上碰见了老师,你想求老师捞一捞。上前打招呼,“老师,我是你学生xxx”,这句话就是说明你和这个老师的关系,这个就是依赖关系。
答完招呼,你就说出了你的想法,“老师,捞一把,卷子我全部都写满了”,老师说“好的好的,我尽量,我尽量”。而这个向老师提出的需求就是依赖方法。
知道了这个概念,再来看一下其中的流程,将makefile
文件写的复杂一点
code:code.o
gcc -o code code.o
code.o : code.s
gcc -c code.s -o code.o
code.s : code.i
gcc -S code.i -o code.s
code.i : code.c
gcc -E code.c -o code.i
然后我们再执行make
指令:
我们发现,如果按顺序来执行的话,应该是先执行gcc -o code code.c
,但是这个输出的顺序并不是这样,而是反正输出的。
这里其实是因为code
依赖的是code.o
文件,而当前目录并没有这个文件,于是需要生成一个code.o
的文件,发现依赖文件中有生成code.o
的依赖关系和依赖方法,依次类推。这就很像递归的过程。
所以我们可以知道make
会自动的推导makefile
中的依赖关系,而这种过程是一种栈式的结构。
Tips:
即使我们调换了其中的顺序,也可以生成,就类似调用函数,不管这个函数在哪,只要能调到就行;
但是如果这其中缺少了环节,那么就不会生成了。
当然了,这只是演示,在实际操作的时候,就不要写这么复杂,能一步到位就一步到位。
🍋3. 清理
当项目不要的时候,需要进行清理。我们就可以到makefile
文件中写入清理的依赖关系和依赖方法:
clean:
rm -f code code.i code.o code.s
clean
不需要依赖其他的文件,依赖关系为空
执行make clean
指令,就删除了我们不需要的项目文件。
那为啥清理的时候需要make clean
呢?能不能也像创建可执行文件时,直接使用make
呢?
我们将makefile
文件稍微下一下,将clean
移到最前面来,然后再执行make
指令:
这样我们使用make
的时候,就默认变成了清理操作。
这是因为make
会自顶向下去扫描,将第一个依赖充当为默认操作。
🍌4. 不可多次编译的原理
🍍4.1 原因
当我们多次make
时,系统会提示我们code
是最新的,就不让我们继续make
了。
如果将code.c
文件修改一下,会发现又能重新make
了,但也是只能make
一次。
出现这种情况是因为编译器认为没有必要,既然文件没有发生改变,那就没有必要再编译一次,就算编译了,也是一样的,所以为了节省资源,编译器就会选择不编译,出发这个文件内容发生改变。
VS2022为例:
那这是如何做到的呢?
对于源文件生成可执行程序,那么肯定是先有源文件,再有可执行程序,在这种情况下,源文件的修改时间肯定是在可执行程序之前。
如果修改了源文件,那么源文件的修改时间肯定会比可执行程序要新。
所以,这需要比较源文件和可执行程序的最近修改时间就行。
🍍4.2 stat命令
stat
命令可以查看文件的详细信息,这里面就包含了文件的时间信息。
Access
:最近访问时间(打开、查看、修改),只要我们访问了该文件,就会被记录。
只要访问文件,
Access
就会改变,当多人协同操作的时候,有些文件可能会被频繁的访问,如果每次访问就修改时间,那么就每次都要去磁盘修改文件的属性,这就会十分影响效率。在较新的版本中,
Access
的更新策略发生了改变,会根据Modify
和Change
的改变或者采用计数器等方式改变。
-
Modify
:对文件内容继续修改的时间 -
Change
:文件属性改变的时间
文件内容改变的时候,文件属性肯定会改变;文件属性改变,不一定会改变文件内容
touch 文件名
如果没有该文件,则创建该文件;
如果有了这个文件,则更新所以最新时间。
🍍4.3 验证
了解了文件的时间关系,就能够解释前面的原因了,我们来验证一下
🥭5. 伪目标
如果我们不想受这个的约束,想执行就执行,可采用.PHONY
来修饰这个目标文件,让其是一个伪目标。
当然,这里不建议将我们的可执行操作设为伪目标,一般采用将清理操作设为伪目标。
🍎6. 取消回显
我们使用make
时,每次都会将对应的方法回显出来,如果不想要回显,我们可以将依赖方法前面加上@
。
另外,使用$@
(:
和$^
自动化变量,引用目标和依赖项。
以上就是make
的基本操作了,大伙可以根据项目的实际需求和复杂性来扩展和定制Makefile。
那本次的分享就到这里啦,如果要帮助的话希望点赞支持一下,我们下期再见,如果还有下期的话。