在 Makefile 中,* 和 % 都是用于匹配文件名的通配符,但它们的作用场景和匹配规则有显著区别,理解两者的差异是编写高效 Makefile 的关键。
1. *:文件名通配符(用于匹配现有文件)
* 是shell 风格的通配符,用于匹配当前目录中已存在的文件名,主要在以下场景使用:
(1)匹配文件列表
*匹配任意长度的字符(除了路径分隔符/)。- 常用于获取符合条件的文件列表(如所有
.c源文件、所有.o目标文件)。
示例:
# 匹配当前目录所有 .c 源文件
SRCS = *.c
# 匹配当前目录所有 .o 目标文件
OBJS = *.o
# 编译所有 .c 文件为 .o 文件
all: $(OBJS)
gcc $(OBJS) -o main
# 生成单个 .o 文件的规则
%.o: %.c
gcc -c $< -o $@
- 这里
*.c会被展开为当前目录中所有.c结尾的文件(如a.c、b.c)。 - 注意:
*仅匹配已经存在的文件,如果文件不存在,会被当作普通字符串处理。
(2)在 wildcard 函数中使用
当需要在变量中动态获取文件列表时,通常结合 wildcard 函数使用(避免 * 被当作字符串字面量):
# 正确获取所有 .c 文件(即使变量定义时文件不存在,后续创建后也能匹配)
SRCS = $(wildcard *.c)
# 匹配子目录中的文件(如 src 目录下的 .c 文件)
SRCS += $(wildcard src/*.c)
wildcard *.c会返回当前目录中所有.c文件的列表,比直接写*.c更可靠。
2. %:模式匹配符(用于规则中的模式规则)
% 是 Makefile 特有的模式匹配符,主要用于模式规则(Pattern Rules) 中,定义 “一类文件” 的通用构建规则,不依赖文件是否存在。
(1)基本用法:匹配文件名的对应部分
在模式规则中,% 代表文件名中 “任意长度的字符串”,且在目标和依赖中必须匹配相同的部分。
经典示例:编译所有 .c 文件为 .o 文件的通用规则
# 模式规则:所有 .o 文件都由同名的 .c 文件编译生成
%.o: %.c
gcc -c $< -o $@
- 这里
%是 “通配符占位符”:- 若目标是
a.o,则依赖会被自动识别为a.c。 - 若目标是
b.o,则依赖会被自动识别为b.c。
- 若目标是
- 该规则适用于所有符合 “
.o对应.c” 的文件,无需为每个文件单独写规则。
(2)在变量和函数中使用 %
% 还可在 patsubst(模式替换)等函数中用于字符串替换:
# 获取所有 .c 文件列表
SRCS = $(wildcard *.c) # 假设结果为 a.c b.c
# 将 .c 文件名替换为 .o(如 a.c → a.o,b.c → b.o)
OBJS = $(patsubst %.c, %.o, $(SRCS)) # 结果为 a.o b.o
patsubst %.c, %.o, $(SRCS)表示:将SRCS中所有以.c结尾的字符串,替换为.o结尾。
(3)匹配路径中的文件
% 可以匹配包含路径的文件名,而 * 通常不跨路径匹配:
makefile
# 模式规则:编译 src 目录下的 .c 文件为 obj 目录下的 .o 文件
obj/%.o: src/%.c
mkdir -p obj # 确保 obj 目录存在
gcc -c $< -o $@
- 若目标是
obj/a.o,则依赖会被识别为src/a.c,%匹配了a这部分。
3. * 和 % 的核心区别
| 特性 | *(通配符) | %(模式匹配符) |
|---|---|---|
| 作用场景 | 匹配现有文件的名称(如获取文件列表) | 定义模式规则,匹配 “一类文件” 的通用规则 |
| 依赖文件存在性 | 仅匹配已存在的文件 | 不依赖文件是否存在,用于定义规则模板 |
| 匹配范围 | 通常不跨路径(除非结合 **,部分版本支持) | 可匹配路径中的文件名(如 src/%.c) |
| 典型用法 | *.c、$(wildcard *.o) | %.o: %.c、$(patsubst %.c, %.o, ...) |
4. 常见错误与注意事项
-
混淆
*和%的使用场景:- 错误:在模式规则中用
*代替%,如*.o: *.c(这会被解析为 “所有.o文件依赖所有.c文件”,不符合预期)。 - 正确:用
%.o: %.c定义每个.o对应单个.c的规则。
- 错误:在模式规则中用
-
*在变量中的延迟展开:- 直接写
SRCS = *.c时,*会在变量定义时展开(仅匹配当时存在的文件)。 - 若后续新增
.c文件,需要重新运行make才会识别,而$(wildcard *.c)会动态获取最新文件列表。
- 直接写
-
%必须在目标和依赖中同时出现:- 模式规则中,
%必须在目标和依赖中都存在(如%.o: %.c),否则会被视为无效规则。
- 模式规则中,
总结
*是文件通配符,用于匹配当前目录中已存在的文件,适合获取文件列表。%是模式匹配符,用于定义通用规则(如所有.o依赖.c),不依赖文件是否存在,是 Makefile 实现 “批量处理” 的核心机制。
灵活运用两者可以大幅简化 Makefile 的编写,尤其是 % 模式规则,能显著减少重复代码,提高可维护性。
1427

被折叠的 条评论
为什么被折叠?



