🌈 个人主页:Zfox_
🔥 系列专栏:C++从入门到精通
目录
- [一: 🔥 make / Makefile背景介绍](#一: 🔥 make / Makefile背景介绍)
-
- [🥝 make是什么?](#🥝 make是什么?)
- [🥝 Makefile是干什么的?](#🥝 Makefile是干什么的?)
- [二: 🔥 Makefile的显式规则](#二: 🔥 Makefile的显式规则)
-
- [🥝 2.1 .PHONY的作用](#🥝 2.1 .PHONY的作用)
- [三: 🔥 依赖关系与依赖方法](#三: 🔥 依赖关系与依赖方法)
-
- [🥝 概念理清](#🥝 概念理清)
- [四: 🔥 Makefile小知识📚](#四: 🔥 Makefile小知识📚)
-
- [🥝 通配符](#🥝 通配符)
- [五: 🔥 Makefile取消回显](#五: 🔥 Makefile取消回显)
- [六: 🔥 共勉](#六: 🔥 共勉)
一: 🔥 make / Makefile背景介绍
💢 首先我们来介绍一下什么是
make/Makefile
,以及它们之间的关系。
🥝 make是什么?
make
是一个命令工具,是一个解释makefile
中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi 的 make,Visual C++的nmake,Linux下GNU的make。可见,Makefile都成为了一种在工程方面的编译方法。
🥝 Makefile是干什么的?
Makefile
是一个文件
。它是一个工程文件的编译规则,它记录了原始码如何编译的详细信息、描述了整个工程的编译链接等规则。Makefile
带来的好处就是------"自动化编译"
。一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率🚀。
🎯 先来看一下 Makefile
的【语法】:
cpp
target(目标文件):文件1 文件2(依赖文件列表) //依赖关系
<Tab>gcc -o 欲建立的执行文件 目标文件1 目标文件2 ///依赖方法
command
...
...
- target就是我们想要建立的信息,一般称作
目标文件
。而后面的依赖文件列表就是具有相关性的 object files,也就是目标文件所依赖的文件(可以是一个或多个,也可以没有)。
🎯 然后看一下 Makefile
的【规则】:
- 目标文件与依赖文件列表文件之间要使用冒号隔开
目标文件:依赖文件列表
。 - target可以是一个目标文件、执行文件,甚至可以是一个标签【后面会提到的伪目标】。
- 依赖方法前面必须加
Tab空格键
。 - 依赖方法以gcc为例,也可以是其他的shell指令【command】。
💢 【总结一下】:
make
是一条命令
,makefile
是一个文件
,两个搭配使用,完成项目自动化构建。
二: 🔥 Makefile的显式规则
💢 首先,在Makefile中,#代表着注释,这个是不会被编译进去的。
大家注意,在Makefile里,有一个很反人类的规定,指令前必须打一个 [Tab]
键,按四下空格会报错。
💢 越是接近目标文件的命令,就越是要写在前面。因为程序是按照递归的方式进行依赖文件查找的,看到第一行有一个没见过的依赖文件,就往下一行进行查找,以此类推。
但是有些同学反映,不按照这个顺序来写好像也不会报错,我觉得这可能是和版本有关系,不过保险起见,我建议大家还是按照规范来写Makefile。
举个例子:
cpp
hello:hello.o
gcc hello.o -o hello
hello.o:hello.s
gcc -c hello.s -o hello.o
hello.S:hello.i
gcc -S hello.i -o hello.s
hello.i:hello.c
gcc -E hello.c -o hello.i
-
假设当前文件夹中有
hello.c
和Makefile
两个文件,当我们在终端输入make
指令的时候,就会自动编译出hello.o,hello.s,hello.i
以及hello
可执行文件。 -
可是,我们又不想要这些不相关的文件,想对这些文件做一些操作,我们把这样的操作叫做伪目标,
标志位.PHONY:
在上述代码的最后面加上:
cpp
.PHONY:
clear:
rm hello.o hello.S hello.i
.PHONY:这是固定格式,不能变的,但是下面的clear是自己取的名字,你随便取什么名字都可以,但是clear比较直观。
这样,当我们执行make clear指令后,将只剩下hello.c 和 hello可执行文件。
🥝 2.1 .PHONY的作用
我们发现当我们重复make的时候,只有第一次make是有效的,那是因为gcc指令会自动去比较 ./process 和 process.c 等代码文件被修改的时间如果代码没有被修改,也就没有必要重复执行命令了,提高了效率。
💢 加上标志位.PHONY:的命令就可以被重复执行了。
PHONY
配置项的目标clean并不是其他文件生成的实际文件,使make命令会自动绕过隐含规则搜索过程,也就是说执行命令make clean会自动忽略名为"clean"文件的存在 ,因此声明.PHONY配置项会改善性能,并且不需要担心实际同名文件存在与否😮。- 【通俗一点说】:
.PHONY
修饰的目标clean并不是某个依赖项生成的实际文件,因此make命令不再去搜寻当前文件夹下是否有clean文件,这样少去做一些事,自然会改善性能,并且不用担心当前文件夹下是否有同名的文件。
💢 再来个复杂一点的例子:
cpp
# 目标文件:test
# 现有文件:program1.c program1.h program2.c program2.h main.c main.h
test:program1.o program2.o main.o
gcc program1.o program2.o main.o -o test
program1.o:program1.c
gcc -c program1.c -o program1.o
program2.o:program2.c
gcc -c program2.c -o program2.o
main.o:main.c
gcc -c main.c -o main.o
.PHONY:
clean_all:
rm program1.o program2.o main.o
然后回到命令行,我们来执行一下这个make指令,它就是自动在当前源文件的所在路径下搜寻Makefile,并解释里面命令。之后若是我们需要去编译任何文件,只需要在Makefile里面做一个添加即可,怎么样,是不是很方便。
到这里,Makefile就学会了,就可以用来做事情了,就是这么简单。
后面的内容无所谓你看不看了,放学了...
三: 🔥 依赖关系与依赖方法
通过小小的demo,想必你已经感受到了【自动化构建工具】的强大,我们来仔细看看Makefile中的指令为何要如此书写✍
🥝 概念理清
- 对于
process:process.c
,冒号左侧是目标文件,右侧是它的依赖文件,所以就可以说它们之间存在一种 【依赖关系】 ,只有 process.c 存在才可以有 process。 - 那要如何通过 process.c去生成 process 呢❓ 此时就需要使用到下面的这句 gcc指令
gcc -o process process.c
👉它叫做 【依赖方法】
四: 🔥 Makefile小知识📚
符号 | 含义 |
---|---|
= | 替换 |
%.o | 任意的.o文件 |
如果我们写TAR = test,就表示下面的代码中,我们可以用TAR代表test文件
🥝 通配符
符号 | 含义 |
---|---|
$^ | 所有依赖文件 |
$@ | 所有目标文件 |
$< | 所有依赖文件的第一个文件 |
即这个 $@ 和 $^,前者表示:左侧被编译的所有内容,即【目标文件】,后者表示:之后所有内容,即【依赖文件】。
此时,当我们再去make的时候,就可以发现这个特殊符号自动替换成了:两侧的【目标文件】和【依赖文件】。
五: 🔥 Makefile取消回显
写了这么多【
make
】,你是否感觉每次都会出现回显很麻烦呢?能不能像我们在敲普通指令的时候一样,直接给出结果呢?
- 这里我们就可以在执行的命令行前加上这个**
@
**
- 此时当我们在【
make
】和【make clean
】的时候就不会产生任何回显了,可以达到一样的效果。
六: 🔥 共勉
以上就是我对 【Linux】makefile自动化编译
的理解,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉