Makefile核心教程(六) --- 一文吃透 Makefile 通配符

文章目录

在编写 Makefile 时,我们经常需要处理多个文件:比如编译所有 .c 文件,或者清理所有 .o 文件。如果逐个列举文件名,不仅繁琐而且难以维护。通配符正是为了解决这类问题而设计的。本文将彻底讲清楚这个概念,从用法到避坑指南,配合实例,让你一次性吃透。

一、通配符介绍

1. 什么是通配符?

通配符是一种用于匹配文件名的特殊字符,是 Makefile 提供的文件名模式匹配语法,用于批量匹配文件路径、文件名、后缀名,避免手动罗列大量文件。

Makefile 核心的四个通配符 *?[]%。这是你必须记住的全部,没有更多了。本文总结前三个通配符,% 在下一篇文章总结模式规则内容会详细讲解。

2. 为什么需要通配符

简化书写:批量代替大量文件名,代码极简洁。

自动适配:文件增删无需修改 Makefile 规则。

通用规则:一套规则适配所有同类文件(.c→.o)。

降低错误:避免手动写文件名的拼写错误。

二、通配符的用法

1. 通配符 * :匹配任意长度的任意字符

核心作用:匹配当前目录下非隐藏文件(不以.开头)的任意名称,支持指定后缀 / 前缀的匹配。

注意:不匹配隐藏文件(如.gitignore.test.c),若需匹配隐藏文件需显式指定.(如.*.c)。

例如:

  • *.c:匹配当前目录下所有后缀为.c的 C 语言源文件(如main.cutils.c)。
  • test*:匹配当前目录下所有以test开头的文件 / 目录(如test.ctest1.otest_dir)。
  • *_lib.*:匹配当前目录下所有以_lib结尾、且带有后缀的文件(如math_lib.clog_lib.o)。

2. 通配符 ?:匹配任意单个字符

核心作用:匹配文件名中某一个位置的任意单个字符,长度严格为 1。

例如:

  • test?.c:匹配test1.ctesta.ctest_.c,但不匹配test.c(无额外字符),也不匹配test12.c(两个字符)。
  • a?b.c:匹配a1b.caXb.c,但不匹配ab.ca12b.c

3. 通配符 []:匹配方括号内的任意单个字符

核心作用:匹配方括号内列举的任意单个字符。

扩展:GNU Make 支持[!...][^...](反向匹配),表示匹配除了方括号里列出的字符之外的任意单个字符,或者更直白一点:只要不是方括号中写的那些字符,都能匹配上。

例如:

  • test[123].c:枚举匹配,仅匹配test1.ctest2.ctest3.c
  • test[a-z].c:范围匹配,匹配testa.c~testz.c的所有小写字母结尾的文件。
  • test[0-9A-Z].c:范围组合,匹配数字(0-9)或大写字母(A-Z)结尾的文件。
  • test[!0-9].c:反向匹配,不匹配数字结尾的test0.c~test9.c文件(如匹配testa.c,不匹配test5.c)。

三、重要注意事项(避坑指南)

  1. 变量定义中使用*,必须配合wildcard函数

直接在变量中写*,Make 不会自动展开为文件列表,而是将其视为普通字符串;需使用$(wildcard 通配符)函数来触发文件匹配。

例如:

bash 复制代码
 # 错误用法:SRC的值是字符串"*.c",不是实际的.c文件列表
SRC_ERROR = *.c

# 正确用法:通过wildcard函数展开,SRC获取当前目录下所有.c文件
SRC = $(wildcard *.c)
  1. 通配符不匹配子目录

*.c 只匹配当前目录,不匹配子文件夹。要匹配子目录,可以用:*/*.c (匹配下一层子目录)或者指定目录dir/*.c

bash 复制代码
# 只匹配当前目录的.c文件
SRC = $(wildcard *.c) $(wildcard src/*.c)

# 匹配子目录下的.c文件(如src/目录)
SRC_SUB = $(wildcard src/*.c)
SRC_SUB = $(wildcard */*.c)

四、完整示例

完整源码请前往知识星球【源码】专栏下载,下载后详看目录中的readme.txt文件内容,有疑问欢迎星球内免费提问。

五、写在最后

欢迎加入嵌入式技术部落知识星球,该星球是高质量、干净、专业的嵌入式技术交流互助圈,编程教学,实战项目与源码解析,职场答疑,嵌入式咨询与学习指南,简历辅导等全方位支持。

加入方式,知识星球app搜索"嵌入式技术部落"。

相关推荐
倔强的石头1062 小时前
【Linux指南】基础IO系列(八):实战衔接 —— 给微型 Shell 添加完整重定向功能
linux·运维·服务器
try2find2 小时前
打印ascii码报错问题
java·linux·前端
Ujimatsu3 小时前
虚拟机安装Ubuntu 26.04.x及其常用软件(2026.4)
linux·运维·ubuntu
一直会游泳的小猫6 小时前
homebrew
linux·mac·工具·包管理
寒秋花开曾相惜6 小时前
(学习笔记)4.2 逻辑设计和硬件控制语言HCL(4.2.1 逻辑门&4.2.2 组合电路和HCL布尔表达式)
linux·网络·数据结构·笔记·学习·fpga开发
狂奔的sherry6 小时前
一次由 mount 引发的 Linux 文件系统“错觉”
linux·运维·服务器
小黑要努力6 小时前
智能音箱遇到的问题(一)
linux·运维·git
ch3nyuyu6 小时前
静态库和动态库的制作
linux·运维·开发语言
一口Linux7 小时前
Linux C编程 | 从0实现telnet获取程序终端控制权
linux·运维·c语言
willhuo7 小时前
Certbot工具在CentOS 7.9上申请和配置SSL证书完整教程
linux·centos·ssl