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

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

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

自动化变量速查表

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

执行 make 命令后的工作流程

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

第 1 步:查找 Makefile 文件

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

第 2 步:确定最终目标

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

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

make 检查 process.exe 是否存在,以及它的依赖文件($(OBJ) 即 main.o 和 utils.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.o 和 utils.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
相关推荐
GeW21 分钟前
制造强国底座:Linux与数据库驱动的新型工业基础设施
linux
xiaoye-duck35 分钟前
《Linux 网络编程》深入理解 IO 多路复用:select 函数详解与 Echo 服务实战
linux·网络
Tairitsu_H1 小时前
[Linux系统] 命令行参数 | 环境变量 | 程序地址空间
linux·环境变量·命令行参数·程序地址空间
雯宝1 小时前
devices_init / buses_init / classes_init / firmware_init / hypervisor_init 函数
linux
M78佐菲2 小时前
ARM学习笔记(12)
linux·arm开发·笔记·嵌入式硬件·学习
可涵不会debug2 小时前
C++ std::bind 实战教程:线程池、回调场景全覆盖
linux·开发语言·c++
青梅味猪大肠3 小时前
【操作系统-26】进程互斥软件实现-Peterson算法
linux·运维·服务器
wdfk_prog4 小时前
Wi-Fi Direct教程 01:在 Ubuntu 搭建双 mac80211_hwsim + wpa_supplicant 2.12
linux·运维·服务器·ubuntu·ros·wifi-direct
Vcaker4 小时前
Linux学习36-k8s集群升级及kube-vip高可用
linux·运维·学习
skywalk81635 小时前
Deepseek harness的4种模式 配置文件内容
linux·人工智能·ubuntu·deepseek·harness