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

文章目录

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

一、通配符介绍

1. 什么是通配符?

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

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

2. 为什么需要通配符

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

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

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

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

二、通配符的用法

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

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

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

例如:

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

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

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

例如:

  • test?.c:匹配test1.c、testa.c、test_.c,但不匹配test.c(无额外字符),也不匹配test12.c(两个字符)。
  • a?b.c:匹配a1b.c、aXb.c,但不匹配ab.c、a12b.c。

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

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

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

例如:

  • test[123].c:枚举匹配,仅匹配test1.c、test2.c、test3.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搜索"嵌入式技术部落"。

相关推荐
祖力5525 分钟前
驱动工程搭建与字符设备驱动框架
linux·运维·服务器·内核·arm·imx6ull·驱动
Escalating_xu2 小时前
【Linux 网络编程】网络基础概念(下):IP、端口、Socket 与网络字节序,写代码前先打好基础
linux·网络·tcp/ip
刚入门的大一新生2 小时前
Linux-Ext系列文件系统
linux·运维·服务器
无足鸟ICT2 小时前
【RHCA+】select循环
linux
SKH.3 小时前
Linux驱动-led、beep
linux·运维·单片机
碧海银沙音频科技研究院3 小时前
炬芯ATS308X的扩音器:麦克风到扬声器直通功能实现
java·linux·运维
睡一觉就好了。3 小时前
序列化与非序列化
linux·网络
想做小南娘,发现自己是女生喵4 小时前
第三周学习文档 Linux C 多进程与多线程
linux·c语言·学习
此生决int4 小时前
Linux系列(06)——进程概念(上)
linux·运维·服务器
H.莓飛6 小时前
【C++】内存管理
linux·开发语言·jvm·c++·visual studio