一.前言
前文讲到Linux的基本指令和权限,但是在我们常见的项目编译中肯定会有很多代码文件 ,指挥使用指令是不够的,所以本篇章着重来讲解一下如何使用Make/Makefile来实现项目的自动化构建
在Linux中编译C语言代码,a.out是从
test.c经过预编译 到**test.i**test.i经过编译 到**test.s**test.s经过汇编 到**test.o**test.o经过链接 到**a.out**
我们平常做做练习还可以接受,但是到了大型工程,可是有上千条上万条代码, 若是一次编译完成之后又修改了源代码,接着又想进行编译,此时便需要重新敲入指令,那会使得工作量变得很大。可是在VS中,我们可以无限地修改自己的代码,然后随时编译运行,不需要考虑这些复杂的原理
那Linux 中有没有这样的一站式操作呢,那就是【make/Makefile】
二.make/makefile介绍
🥝Makefile是干什么的?
- Makefile 是一个**
文件**。它是一个工程文件的编译规则,它记录了原始码如何编译的详细信息、描述了整个工程的编译链接等规则。
- Makefile 带来的好处就是------"自动化编译"。一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率🚀
target(目标文件):文件1 文件2(依赖文件列表) //依赖关系
<Tab>gcc -o 欲建立的执行文件 目标文件1 目标文件2 ///依赖方法
command
...
...
- target就是我们想要建立的信息,一般称作**
目标文件** 。而后面的**依赖文件列表** 就是具有相关性的 object files,也就是目标文件所依赖的文件(可以是一个或多个,也可以没有)
cpp
目标:你想要生成的文件名(比如最终的可执行文件,或者中间的 .o 目标文件)。也可以是一个执行动作(如 clean)。
依赖:生成这个目标所需要的原材料(源文件或其他中间文件)。
命令:如何将"依赖"变成"目标"的具体操作(通常是 gcc/g++ 命令)。
⚠️ 致命易错点:命令前面必须是一个纯正的 Tab 键缩进,绝对不能是用空格代替,否则 make 会报错!
三.makefile操作
假设我们有一个简单的项目,包含三个文件:
cpp
main.c (主函数)
math.c (数学功能实现)
math.h (头文件)
传统编译方式: gcc main.c math.c -o myapp
使用 makefile 的方式: 在源码同级目录下创建一个名为 Makefile 或 makefile 的文件,内容如下:
cpp
# 最终目标 myapp 依赖于 main.o 和 math.o
myapp : main.o math.o
gcc main.o math.o -o myapp
# main.o 依赖于 main.c
main.o : main.c
gcc -c main.c -o main.o
# math.o 依赖于 math.c
math.o : math.c
gcc -c math.c -o math.o
工作原理(依赖推导树): 当你输入 make 回车时:
-
make 会在当前目录找
makefile,并默认把找到的第一个目标 (也就是myapp)作为最终目标。 -
它发现要生成
myapp依赖main.o和math.o。 -
如果当前目录下没有这两个
.o文件,它会挂起当前任务,继续向下寻找生成main.o和math.o的规则。 -
找到底层的
.c生成.o的规则后,按从下往上 的顺序,先执行gcc -c生成目标文件,最后再执行链接生成可执行程序myapp。这就是所谓的自动推导。
四.进阶操作
上面的写法有太多重复的内容(比如文件名被写了好多次),我们可以使用变量来简化它。
常用自动化变量:
-
$@:表示规则中的目标文件。 -
$^:表示规则中的所有依赖文件(以空格分隔)。 -
$<:表示规则中的第一个依赖文件。
cpp
# 定义基础变量
CC = gcc
TARGET = myapp
OBJS = main.o math.o
# 链接生成最终可执行文件
$(TARGET) : $(OBJS)
$(CC) $^ -o $@ # 等价于 gcc main.o math.o -o myapp
# 编译生成中间目标文件
# % 是通配符,表示所有的 .o 文件都由对应的 .c 文件生成
%.o : %.c
$(CC) -c $< -o $@
五.项目清理:.PHONY伪目标
编译过程中会产生很多中间文件(如 .o),当你想清理工作区,准备重新全量编译或打包源码时,需要删除它们。我们通常会在 makefile 底部加上清理命令:
cpp
.PHONY:clean
clean:
rm-f $(OBJS) $(TARGET)
为什么要有.PHONY关键字
假设你的当前目录刚好有一个名为clean的实体文件 ,当你执行 make clean时,make发现目标文件clean已经存在,并且它没有任何以来,make就会认为它是最新的,从而提示make:'clean' is up to date,拒绝执行下面的rm命令。 .PHONY的作用就是告诉make,clean是一个伪目标,不代表具体的文件,无论当前目录有没有叫clean的文件,每次执行 make clean时无条件执行它下面的命令
六.核心优势:增量编译
这也是 makefile 最大的价值所在:只编译修改过的文件。
如果你的项目有100个 .c文件,你修改其中一个。当你再次输入make时,make工具会对比源文件(.c)和目标文件(.o)的最后修改时间。
如果发现 xxx.c 的修改时间比 xxx.o 晚,它就知道源文件被改动过了,于是只重新编译这一个文件,然后重新链接。大大节省了大型项目的编译时间!