Mock 编译 RPM 包时基于 Spec 宏定义定制组件产物范围指南

Mock 编译 RPM 包时基于 Spec 宏定义定制组件产物范围指南
在构建大型 RPM 包尤其是内核 Kernel 包时官方 spec 文件通常通过宏定义提供了丰富的组件开关。利用 Mock 结合这些宏定义可以灵活控制最终生成的 RPM 产物集合如是否生成 headers、debuginfo、perf 工具等从而显著缩短编译时间并减小存储占用。一、基本概念介绍1. 什么是 RPM 宏MacrosRPM 宏是 spec 文件中预定义的变量或条件判断语句用于控制构建流程。在 kernel.spec 中常见的组件开关定义如下# 默认开启构建 headers %define with_headers %{?_without_headers:0} %{?!_without_headers:1} # 默认开启构建 debuginfo %define with_debuginfo %{?_without_debuginfo:0} %{?!_without_debuginfo:1}2. 什么是--with/--without开关这是rpmbuild命令原生支持的参数用于在构建时动态修改宏值--without feature将对应宏的with_feature值设为0关闭。--with feature将对应宏的with_feature值设为1开启通常用于默认关闭的特性。3. 什么是 MockMock 是一个在隔离的 chroot 环境中构建 RPM 包的工具。它本身不直接解析--with但提供了--define选项可以将任意宏定义直接传递给内部的rpmbuild进程。二、工作原理核心机制1. Spec 文件中的条件判断逻辑以您提供的宏定义为例%define with_headers %{?_without_headers:0} %{?!_without_headers:1}如果用户没有指定--without headers则宏_without_headers未定义此时%{?!_without_headers:1}生效with_headers1开启。如果用户指定了--without headers则_without_headers被定义为任意非空值此时%{?_without_headers:0}生效with_headers0关闭。后续 spec 中通过%if %{with_headers}条件包裹具体的%package和%build子段从而决定该组件是否被构建。2. Mock 传递参数的本质Mock 执行命令时会将--define MACRO VALUE原样传递给 chroot 内的rpmbuild。关键映射rpmbuild --without headers等效于rpmbuild --define _without_headers 1。因此在 Mock 中禁用组件就是利用--define来模拟rpmbuild的--without行为。三、常用操作指南基于您提供的 kernel.spec 宏定义默认全开以下是常见的构建定制操作。1. 禁用单个组件包场景不需要构建kernel-headers。mock-rchroot配置文件\--define_without_headers 1\源码包.src.rpm2. 禁用多个组件包场景调试阶段仅需核心内核镜像无需 tools、perf 和 debuginfo。mock-rchroot配置文件\--define_without_tools 1\--define_without_perf 1\--define_without_debuginfo 1\源码包.src.rpm3. 开启默认关闭的组件逆向场景如果 spec 中使用的是%bcond_with foo默认关闭则开启方法如下# 对于 %bcond_with foo默认关闭需开启mock-rchroot配置文件\--define_with_foo 1\源码包.src.rpm4. 精简构建仅构建标准内核场景仅保留标准内核with_up剔除 Kata、Debug、Doc 等。mock-rchroot配置文件\--define_without_kata 1\--define_without_debug 1\--define_without_doc 1\--define_without_bpftool 1\源码包.src.rpm5. 使用 Mock 配置文件永久定制如果频繁使用同一套开关可修改~/.mock/配置.cfg在config_opts中添加config_opts[rpmbuild_opts][--define _without_headers 1,--define _without_perf 1]之后直接运行mock -r 配置即可自动应用。四、注意事项与最佳实践1. 明确宏的默认状态Default State在操作前务必检查 spec 文件头部%define with_xxx %{?_without_xxx:0} ...默认开启需要用_without_xxx关闭。%bcond_without xxx默认开启需要用--without关闭对应_without_xxx。%bcond_with xxx默认关闭需要用--with开启对应_with_xxx。错误判断默认状态是导致组件意外缺失或冗余的最常见原因。2. 依赖关系连带影响禁用某些组件可能导致其他组件因依赖缺失而编译失败。例如禁用kernel-tools可能不影响核心镜像但如果perf依赖特定的工具链子包强行禁用可能会触发%check阶段的报错。建议在禁用前查看 spec 中%package和Requires部分的依赖关系。3. 验证构建产物构建完成后查看 Mock 输出日志中Wrote:的行确认生成的 RPM 列表是否符合预期Wrote: /builddir/build/RPMS/x86_64/kernel-5.14.0-1.x86_64.rpm Wrote: /builddir/build/RPMS/x86_64/kernel-core-5.14.0-1.x86_64.rpm若发现依然生成了禁用的包检查宏名称是否拼写错误注意下划线_without_。4. 清理缓存与增量构建Mock 默认会缓存之前的构建根目录。如果修改了宏定义建议加上--no-clean复用缓存加速或先执行mock --scruball彻底清理避免旧的编译对象残留干扰新配置。5. 区分 SRPM 构建与 RPM 构建--define可以放在mock --buildsrpm阶段影响 spec 预处理也可以放在mock --rebuild阶段。若需要生成修改了组件定义的 SRPM请在构建 SRPM 时就将宏定义传入。五、总结速查表目标行为Mock 命令参数格式禁用默认开启的组件如 headers--define _without_headers 1开启默认关闭的组件如 experimental--define _with_experimental 1同时禁用多个组件串联多个--define _without_xxx 1查看最终生效的宏值调试在 spec 中临时添加%echo %{with_headers}或使用rpm --eval测试通过灵活运用 Mock 的--define传递机制您可以像操作原生rpmbuild一样精细化管理内核等大型软件的产物范围实现高效、定制化的持续集成构建。