【Makefile 专家之路 | 基础篇】03. 规矩方圆:书写规则详解(通配符、文件搜索与伪目标)

文章目录

  • [一、 通配符:批量处理的艺术](#一、 通配符:批量处理的艺术)
  • [二、 文件搜索:VPATH 与 vpath](#二、 文件搜索:VPATH 与 vpath)
  • [三、 伪目标(.PHONY):绝对的"安卓必修课"](#三、 伪目标(.PHONY):绝对的“安卓必修课”)
  • [四、 多目标与多规则](#四、 多目标与多规则)
  • [五、 💡 安卓工程师的记忆卡片](#五、 💡 安卓工程师的记忆卡片)

一、 通配符:批量处理的艺术

在 Makefile 中,如果你想表示"所有的 .c 文件",你会用到通配符。

  1. *(星号) :与 Shell 里的用法一致。
    • 例子:rm -f *.o 表示删除所有以 .o 结尾的文件。
    • 陷阱: 如果你在变量定义中使用 objects = *.o,而此时目录下还没有生成任何 .o,那么 objects 的值就是字符串 *.o,而不是文件列表。
  2. % (百分号)这是 Makefile 的精髓 。它用于"匹配"。
    • 它不像 * 那样简单展开,而是在规则中定义"模式"。例如 %.o : %.c 表示"任何一个 .o 目标都依赖于同名的 .c 文件"。

二、 文件搜索:VPATH 与 vpath

在 Android 源码中,头文件和源文件通常分开放(比如 src/ 和 include/)。如果 Makefile 找不到文件,就会报错。

  1. VPATH 变量:这是一个全局搜索路径。
bash 复制代码
VPATH = src:../headers

make 如果在当前目录找不到依赖文件,就会去 src 和 .../headers 目录下挨个找。

  1. vpath 关键字(小写): 更精准的分类搜索。
bash 复制代码
vpath %.h ../headers
vpath %.c src

这告诉 make:所有的 .h 去 .../headers 找,所有的 .c 去 src 找。

三、 伪目标(.PHONY):绝对的"安卓必修课"

这是本章最重要的概念。
场景: 假设你的 Makefile 里有一个 clean 目标,但不巧,你的文件夹里真的有一个文件叫 clean

  • 结果: 当你输入 make clean 时,make 发现 clean 文件已经存在,且没有依赖,它会认为"目标已最新",从而拒绝执行删除命令!

解决方案 : 使用 .PHONY 显式声明。

bash 复制代码
.PHONY: clean
clean:
	rm -rf $(OBJS)
  • 意义: 告诉 make,clean 不是一个真正的"文件",而是一个"动作"。无论目录下有没有同名文件,请务必执行它。

四、 多目标与多规则

  1. 多目标: 一个命令生成多个文件。
  2. 静态模式: 让你能更灵活地指定哪些目标应用哪些规则(我们将在之后的自动化篇深入剖析)。

五、 💡 安卓工程师的记忆卡片

  1. Android 源码中的 .PHONY
    在 AOSP 源码中,你会看到大量的伪目标,比如 make bootimage、make systemimage。这些显然不是为了生成一个叫 bootimage 的单个文件,而是触发一整套复杂的打包脚本。
  2. 目录搜索的工程实践
    虽然 VPATH 很好用,但在极大型项目中(如 Android),过度依赖全局 VPATH 可能会导致链接到错误版本的库。现代 Android 开发更倾向于在 Android.mk 中直接使用 $(LOCAL_PATH) 绝对路径或明确的相对路径。
  3. 续行符 \
    当 vpath 路径太长或者 OBJS 列表太长时,记得在行末使用 \。
    1)\ 后面不能有任何字符(空格和制表符也不能有)
    2)解析时,\ 和换行符被删除,但下一行的前导空白字符(空格和制表符)被保留,一同拼接到第一行的末尾
    3)echo (OBJS) 或 (info $(OBJS)) 输出时,make 本身会将多个空白压缩为一个空格显示(但实际值中仍有多个空白)。

【本篇思考题】

  1. 在 Android 源码中,如果你在当前目录下执行 make clean,结果发现没有任何文件被删除,但目录下确实有 .o 文件。请问最可能的原因是什么?
  2. %.o : %.c 和 *.o : *.c 这两种写法,哪一个是正确的模式匹配规则?
相关推荐
Lueeee.2 小时前
Linux下的ULN2003驱动板与28BYJ-48步进电机驱动移植
linux·驱动开发
洛菡夕2 小时前
nginx核心功能
linux·nginx
原来是猿2 小时前
Linux - 基础IO【下】
linux·运维·服务器
xyd陈宇阳3 小时前
面向网络协议初学者的入门指南
linux·运维·网络协议
_DCG_3 小时前
用户态和内核态的区别
linux
肖恭伟3 小时前
QtCreator Linux ubuntu24.04问题集合
linux·windows·qt
兮动人3 小时前
Linux 云服务器部署 OpenClaw 全攻略:从环境搭建到 QQ 机器人集成
linux·服务器·机器人·openclaw
linux修理工3 小时前
使用 nextcloud.occ 重置用户密码
linux·运维·服务器
toradexsh3 小时前
基于 NXP iMX8MP ARM平台安装测试 Openclaw
linux·docker·arm·nxp·openclaw