【Linux】自动化编译工具——make/makefile

一.前言

前文讲到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 晚,它就知道源文件被改动过了,于是只重新编译这一个文件,然后重新链接。大大节省了大型项目的编译时间!

相关推荐
0+1113 小时前
Linux --从 poll 到 epoll多路转接
linux·服务器·1024程序员节
青瓦梦滋4 小时前
WebSocket协议
linux·服务器·网络·c++·websocket·网络协议·http
桌面运维家4 小时前
旧电脑跑不动课程软件,VDI云桌面怎样接着用?
运维·服务器·虚拟化·pve·vdi·云桌面
zhang133830890754 小时前
传统机械三杯式风速传感器易磨损冻堵?CG-88金属超声波风速风向传感器给出免运维方案
运维·服务器·网络·人工智能·自动化
知已难寻5 小时前
第 2 篇 · 云的地基:服务器、存储、网络三大基础设施
运维·服务器·网络·云原生·云计算·负载均衡·1024程序员节
2601_949847757 小时前
bcrypt.js 跨端三方库仓颉适配全流程
linux·运维·ubuntu
m0_639906947 小时前
Linux 操作系统入门:目录结构、服务排查常用命令、Shell 脚本基础
linux·运维·后端
meiying88387 小时前
快递单号批量查询Python脚本:从手动到自动化的完整实现
开发语言·python·自动化
今天重构了吗7 小时前
Linux 上 rm -rf 删错了能找回吗
运维·服务器
KaiwuDB8 小时前
KaiwuDB 分布式集群扩缩容,从原理到完整操作踩坑总结
运维·数据库·分布式