【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 的方式: 在源码同级目录下创建一个名为 Makefilemakefile 的文件,内容如下:

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.omath.o

  • 如果当前目录下没有这两个 .o 文件,它会挂起当前任务,继续向下寻找生成 main.omath.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 晚,它就知道源文件被改动过了,于是只重新编译这一个文件,然后重新链接。大大节省了大型项目的编译时间!

相关推荐
AOwhisky4 小时前
下一代容器来了?Docker 宣布原生支持 WebAssembly
java·运维·docker·容器·rust·wasm
玖玥拾6 小时前
C++ 数据结构 八大基础排序算法专题
数据结构·c++·算法·排序算法
haidy ahmed6 小时前
企微复杂审批流反序列化:动态表单解析引擎与EAV存储模型
数据库·人工智能·自动化·企业微信
Tim_107 小时前
【C++】017、new/delete与malloc/free的区别
java·数据结构·算法
摇滚侠7 小时前
Linux 零基础教程 09、11、77
linux·运维·服务器
Lottie20268 小时前
电商自动化提质增效:API接口落地的核心价值与实战用法
运维·自动化
Hardworking6669 小时前
第6章 数据工程
运维·服务器·数据库·数据工程
岑梓铭9 小时前
《考研408数据结构》第六章(6.3 图的遍历)复习笔记
数据结构·笔记·考研··拓扑排序·408
jieyucx10 小时前
Docker 入门第六阶段:综合实战项目
运维·docker·容器
美丽的欣情10 小时前
RK3588 Debian 交叉编译环境搭建(Windows + VMware Debian + CMake)
运维·windows·debian