make基础

自动化构建 - make / Makefile

背景

  • 工程中的源文件不计其数,按类型、功能、模块分别放在若干个目录中。Makefile 定义了一系列规则来指定:

    • 哪些文件需要先编译
    • 哪些文件需要后编译
    • 哪些文件需要重新编译
    • 甚至进行更复杂的功能操作
  • Makefile 带来的好处就是------"自动化编译" 。一旦写好,只需要一个 make 命令,整个工程完全自动编译,极大地提高了软件开发的效率。

  • make 是一个命令工具,是一个解释 Makefile 中指令的命令工具。一般来说,大多数的 IDE 都有这个命令,例如:

    • Delphi 的 make
    • Visual C++ 的 nmake
    • Linux 下 GNU 的 make
  • 核心关系

    • make 是一条命令
    • Makefile 是一个文件
    • 两者搭配使用,完成项目自动化构建

Makefile 示例与详解

完整 Makefile 代码

makefile 复制代码
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
BIN = process.exe
CC = gcc

$(BIN): $(OBJ)
	@gcc -o $@ $^ -g
	@echo "link $^ and $@ "

%.o: %.c
	@gcc -c $< -g
	@echo "compline $< to $@ "

.PHONY: clean test
clean:
	rm -f $(OBJ) $(BIN)
test:
	@echo "OBJ:$(OBJ)"
	@echo "BIN:$(BIN)"

变量定义说明

变量 说明
SRC = $(wildcard *.c) 使用 wildcard 函数获取当前目录下所有 .c 文件
OBJ = $(SRC:.c=.o) SRC 中所有 .c 后缀替换为 .o,得到目标文件列表
BIN = process.exe 定义最终生成的可执行文件名
CC = gcc 指定编译器为 gcc

规则详解

主规则:生成可执行文件
makefile 复制代码
$(BIN): $(OBJ)
	@gcc -o $@ $^ -g
	@echo "link $^ and $@ "
符号 含义
$@ 目标文件(即 $(BIN),也就是 process.exe
$^ 所有依赖文件(即 $(OBJ),所有 .o 文件)
-g 生成调试信息,供 gdb 使用
@(行首) 静默符号,执行时不显示该命令本身
模式规则:编译 .c.o
makefile 复制代码
%.o: %.c
	@gcc -c $< -g
	@echo "compline $< to $@ "
符号 含义
% 通配符,匹配任意相同的前缀
$< 第一个依赖文件(即对应的 .c 文件)
-c 只编译不链接,生成目标文件

说明 :所有同名 .o 文件依赖于同名的 .c 文件,逐个编译成对应的 .o 文件。

伪目标

makefile 复制代码
.PHONY: clean test

声明 cleantest 为伪目标,防止与同名文件冲突。如果使用make clean/test时,只会在makefile中寻找代码,而不是在当前目录下寻找同名文件

clean - 清理编译产物
makefile 复制代码
clean:
	rm -f $(OBJ) $(BIN)
  • 删除所有 .o 文件和可执行文件
test - 调试变量
makefile 复制代码
test:
	@echo "OBJ:$(OBJ)"
	@echo "BIN:$(BIN)"
  • 打印 OBJBIN 变量的值,用于调试 Makefile

自动化变量速查表

变量 含义
$@ 当前规则的目标文件
$^ 当前规则的所有依赖文件
$< 当前规则的第一个依赖文件
$? 所有比目标新的依赖文件
$* 目标文件名中 % 匹配的部分

执行 make 命令后的工作流程

假设当前目录下有 main.cutils.c 两个源文件。

第 1 步:查找 Makefile 文件

make 在当前目录下查找名字为 Makefilemakefile 的文件,找到了当前这个文件。

第 2 步:确定最终目标

make 找到文件中的第一个目标文件 ,即 $(BIN) 展开后的 process.exe,将其作为最终目标。

makefile 复制代码
$(BIN): $(OBJ)   # 第一个目标,即 process.exe
第 3 步:检查是否需要重新生成

make 检查 process.exe 是否存在,以及它的依赖文件($(OBJ)main.outils.o)是否比它更新(通过文件的时间属性来判断)。

情况 make 的行为
process.exe 不存在 需要生成
某个 .o 文件比 process.exe 需要重新链接
process.exe 存在且比所有 .o 文件都新 什么都不做

假设 process.exe 不存在,make 将执行链接命令:

bash 复制代码
gcc -o process.exe main.o utils.o -g
echo "link main.o utils.o and process.exe "
第 4 步:递归处理依赖(关键步骤)

在执行链接之前,make 检查依赖文件 main.outils.o 是否存在:

  • 如果 .o 文件不存在 ,或者 .o 文件比对应的 .c 文件旧,make 会查找生成该 .o 文件的规则

make 找到了模式规则:

makefile 复制代码
%.o: %.c   # 例如 main.o 依赖 main.c,utils.o 依赖 utils.c

这类似于一个堆栈过程:

复制代码
process.exe 依赖 main.o 和 utils.o
    ↓
main.o 不存在,查找生成 main.o 的规则
    ↓
找到 %.o: %.c,执行 gcc -c main.c -g
    ↓
utils.o 不存在,查找生成 utils.o 的规则
    ↓
找到 %.o: %.c,执行 gcc -c utils.c -g
    ↓
所有 .o 文件生成完毕,返回上一层
    ↓
执行链接,生成 process.exe
第 5 步:编译源文件

make 执行编译命令,生成 .o 文件:

bash 复制代码
gcc -c main.c -g
echo "compline main.c to main.o "
gcc -c utils.c -g
echo "compline utils.c to utils.o "
第 6 步:完成最终目标

所有依赖准备就绪,make 执行链接命令生成 process.exe

第 7 步:依赖链结束

make 完成了第一个目标 process.exe 的生成,整个过程结束。

错误处理示例

错误场景 make 的行为
某个 .c 文件不存在(如 main.c 被删除) 找不到 main.c,直接退出并报错
编译命令写错了(如 gcc -c main.c -wrong make 不管命令执行是否成功,只管执行命令
依赖关系缺失(如没有 %.o: %.c 规则) 找不到生成 .o 的方法,直接退出并报错

核心总结

make 只管文件的依赖性

  • 它会一层一层地检查依赖关系
  • 如果依赖关系链完整,就执行对应命令
  • 如果某个依赖文件找不到且没有生成它的规则,make 就报错退出
  • make 不关心命令执行是否成功,只负责执行命令
  • Makefile 设计的核心规则:最终目标是第一个目标,所以要把最终要生成的文件写在最前面。

其他命令示例

bash 复制代码
make clean   # 执行伪目标 clean,删除 .o 和 .exe 文件
make test    # 执行伪目标 test,显示变量值

执行 make test 的输出示例:

复制代码
OBJ:main.o utils.o
BIN:process.exe
相关推荐
睡一觉就好了。1 小时前
gcc/g++
linux
Championship.23.241 小时前
Linux 3.0 串口机制深度解析:传统8250驱动与基础RS-232/485支持
linux·运维·服务器
顾喵1 小时前
VME总线详解:原理、架构、时序、协议、迭代、调试与实战应用
linux·网络协议
AI行业学习2 小时前
CC‑Switch v3.16.1 免费下载(Windows+macOS+Linux)、使用方法【2026.6.11】
linux·开发语言·windows·python·macos·前端框架·html
睡一觉就好了。2 小时前
vim基础操作
linux·编辑器·vim
__Witheart__2 小时前
Ubuntu 根文件系统开发流程及注意事项
linux·ubuntu·rockchip
vortex52 小时前
解决 Alpine Linux 虚拟机从 VirtualBox 迁移到 VMware 的内核崩溃问题
linux·运维
qq_白羊座2 小时前
Linux 压缩 / 解压(tar)命令 + 参数详解
linux·运维·github
hj2862512 小时前
Rsync 数据同步 + Inotify 实时监控 完整版实操笔记3
linux·运维·网络