RPM 打包 spec 文件全解析

简介: 本文系统讲解RPM打包核心——.spec文件的编写,涵盖软件标识、依赖管理、构建流程、文件配置及条件判断等关键内容,结合Bear、gRPC等实战场景,深入解析多架构与多发行版适配技巧,助力掌握自动化打包技能。

这几天想在Rocky Linux 9上配置一个PostgreSQL的开发环境,需要Bear(一款专为clang工具链生成编译数据库的工具。在clang项目中,JSON编译数据库用于记录单个编译单元的处理信息。借助该数据库,开发者能够轻松使用替代程序重新执行编译流程)这个工具,然而Rocky并没有提供Bear的rpm包,这也难不倒我,自己下载源码编译呗!一动手发现Bear依赖google的gprc,grpc又依赖protobuff,可恨的是Rocky下居然也没包含二者的开发包!考虑到后续很多地方都会用到这三个,所以干脆给它们打个rpm包算了,顺便我也学学rpm打包这项技能。经过一番折腾,在AI的帮助下总算搞定了,于是总结了下面这些内容,后续还会写几个具体的案例。
RPM 打包的核心是 .spec 文件,它是包含打包规则、软件信息、构建流程、安装配置的文本配置文件,所有生成 RPM 包的逻辑均定义于此。除了基础的配置选项,spec 文件还支持条件判断语法,可实现多架构适配、多发行版兼容等灵活配置。本文将系统拆解 spec 文件的核心选项,并详细说明条件判断(if/else)的用法,为 RPM 打包提供完整指南。

一、 基础信息类选项(必选,定义软件核心标识)

这类选项用于描述软件的基本信息,是 RPM 包的“身份标识”,大部分为必选项,确保 RPM 包的可识别性和规范性。

1.1 核心必选选项

选项 详细说明 示例
Name RPM 包的名称(最终 RPM 包名格式:Name-Version-Release.arch.rpm),只能包含字母、数字、下划线、连字符,不能有特殊字符 Name: nginx
Version 软件的原始版本号(对应上游软件版本,如 1.24.0),不能包含连字符(-),可使用点(.)和数字 Version: 1.24.0
Release 发行版号(用于标识同一软件版本的不同 RPM 打包版本,如补丁更新、配置调整),格式通常为 数字%{?dist}%{?dist} 自动适配系统发行版,如 el7、el8) Release: 1%{?dist}
Summary 软件简短描述(一句话概括软件功能),支持多语言(通过 %{_default_lang} 或指定语言标识) Summary: High performance web server and reverse proxy server
License 软件许可证类型(需明确合法许可证,如 GPLv2、MIT、BSD、Commercial 等),对应上游软件授权协议 License: BSD-2-Clause
Group 软件分类(可选,部分旧系统仍需指定,用于软件仓库分类管理),常见分类:System Environment/DaemonsApplications/Internet Group: System Environment/Daemons
Source0 上游软件源码包路径(本地路径或 URL),多个源码/补丁可依次定义为 Source1Source2...,通常使用宏简化路径 Source0: https://nginx.org/download/nginx-%{version}.tar.gz
BuildRoot 构建根目录(可选,现代 RPM 打包可省略,用于指定编译构建时的临时根目录,避免污染系统环境),通常使用宏定义 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

1.2 补充描述选项

选项 详细说明 示例
URL 软件官方网站或源码仓库地址,便于用户获取上游信息 URL: https://nginx.org/
Vendor 打包者/厂商名称(可选,标识 RPM 包的提供方) Vendor: Example Tech Co., Ltd.
Packager 打包者信息(姓名+邮箱,可选) Packager: Zhang San zhangsan@example.com
Description 软件详细描述(多行文本,第一行可省略,后续行需以空格或制表符开头,支持换行和格式说明) Description: Nginx is a high-performance HTTP and reverse proxy server, \n as well as a mail proxy server. It is known for its stability, \n rich feature set, simple configuration and low resource consumption.

二、 构建依赖与运行依赖类选项

这类选项用于声明 RPM 包编译构建时所需的依赖安装后运行时所需的依赖,确保打包过程顺利且软件安装后可正常运行。

2.1 构建依赖选项

选项 详细说明 示例
BuildRequires 编译构建时必需的软件包(如编译器、开发库、配置工具等),多个依赖用空格分隔,支持版本约束(>=<== 等),对应 devel BuildRequires: gcc make pcre-devel zlib-devel openssl-devel
BuildConflicts 编译构建时冲突的软件包(存在该包则无法构建),可选,支持版本约束 BuildConflicts: nginx-legacy-devel < 1.20.0

2.2 运行依赖选项

选项 详细说明 示例
Requires 软件运行时必需的软件包(安装当前 RPM 包时会自动检查并安装依赖包),多个依赖用空格分隔,支持版本约束 Requires: pcre >= 8.32 zlib >= 1.2.8 openssl >= 1.1.1
Requires(pre) 预安装脚本(%pre)执行前必需的依赖包(优先级高于 Requires Requires(pre): shadow-utils >= 4.1.5
Requires(post) 安装后脚本(%post)执行时必需的依赖包 Requires(post): systemd >= 219
Requires(preun) 预卸载脚本(%preun)执行前必需的依赖包 Requires(preun): systemd >= 219
Requires(postun) 卸载后脚本(%postun)执行时必需的依赖包 Requires(postun): systemd >= 219
Conflicts 软件运行时冲突的软件包(无法与当前包同时安装),支持版本约束 Conflicts: apache httpd >= 2.4.0
Obsoletes 声明当前包替代的旧版本软件包(安装当前包时会自动卸载被替代的包),用于软件版本迭代替换 Obsoletes: nginx-old < %{version}-%{release}
Provides 声明当前包提供的“虚拟包”或功能标识(其他包可通过该标识依赖当前包),可选 Provides: web-server = 1.0 nginx = %{version}-%{release}

三、 构建与安装路径类选项(宏定义)

这类选项多为 RPM 内置宏(也可自定义宏),用于指定编译、安装、文件存放的标准路径,遵循 FHS(文件系统层次结构标准),提高打包的规范性和可移植性。

选项/宏 详细说明 默认值(CentOS/RHEL) 示例
%{_prefix} 软件安装根目录 /usr --prefix=%{_prefix}(编译配置参数)
%{_bindir} 可执行程序存放目录(普通用户程序) %{_prefix}/bin %{_bindir}/nginx
%{_sbindir} 系统管理员可执行程序存放目录 %{_prefix}/sbin %{_sbindir}/nginx
%{_datadir} 共享数据文件存放目录 %{_prefix}/share %{_datadir}/nginx/html
%{_sysconfdir} 配置文件存放目录 /etc %{_sysconfdir}/nginx/nginx.conf
%{_localstatedir} 本地状态数据存放目录(日志、缓存等) /var %{_localstatedir}/log/nginx、%{_localstatedir}/run/nginx
%{_libdir} 共享库文件存放目录 %{_prefix}/lib64(64位系统)、%{_prefix}/lib(32位系统) %{_libdir}/nginx/modules
%{_mandir} 手册页(man page)存放目录 %{_datadir}/man %{_mandir}/man8/nginx.8.gz
%{_builddir} 编译构建临时目录 %{_topdir}/BUILD 自动使用,无需手动配置
%{_rpmdir} 生成 RPM 包存放目录 %{_topdir}/RPMS 自动使用,无需手动配置

四、 构建流程脚本段(定义编译、安装逻辑)

这类脚本段以% 开头,按固定顺序执行,用于定义软件的编译、安装、清理等构建步骤,是 spec 文件的核心执行逻辑。

脚本段 执行时机 详细说明 示例
%prep 构建前准备阶段 用于解压源码包、应用补丁、创建目录等预处理操作,常用内置宏:1. %setup -q:自动解压 Source0 源码包并进入解压目录(-q 静默模式)2. %patch0 -p1:应用 Patch0 补丁(-p1 忽略补丁中的顶级目录)3. 支持自定义 shell 命令 %prep%setup -q%patch0 -p1 # 应用补丁mkdir -p %{buildroot}%{_sysconfdir}nginx
%build 编译构建阶段 用于执行软件编译命令(如 ./configuremake 等),通常结合 RPM 宏指定编译参数,确保编译结果符合安装路径要求 %build%configure --prefix=%{_prefix} --conf-path=%{_sysconfdir}/nginx/nginx.conf --with-http_ssl_modulemake %{?_smp_mflags} # 多线程编译,自动适配CPU核心数
%install 安装阶段 用于将编译后的文件安装到 %{buildroot}(临时根目录)中,对应最终系统的安装路径,常用 make install 或手动复制文件,必须确保文件路径与 %files 段一致 %installrm -rf %{buildroot} # 清理旧的临时目录make install DESTDIR=%{buildroot} # 安装到临时根目录# 复制自定义配置文件install -m 644 confnginx.conf %{buildroot}%{_sysconfdir}/nginx/install -m 755 scriptsnginx.service %{buildroot}%{_unitdir}/
%clean 构建后清理阶段 用于清理构建过程中生成的临时文件、目录(现代 RPM 打包可省略,系统会自动清理),通常删除%{buildroot} 和编译目录 %cleanrm -rf %{buildroot}rm -rf %{_builddir}%{name}-%{version}

五、 文件管理段(定义 RPM 包包含的文件)

%files 段用于指定最终生成的 RPM 包中包含的所有文件/目录,以及文件的权限、所有者等属性,%install%{buildroot} 必须与 阶段安装到 的文件路径完全一致,否则打包会失败。

5.1 核心语法


%files [选项]
# 文件/目录路径(基于 %{buildroot},省略 %{buildroot} 前缀)
# 可使用 RPM 宏、通配符(*、? 等)

5.2 关键选项与说明

选项/语法 详细说明 示例
普通文件/目录 直接指定文件或目录路径,RPM 会自动继承 %install 阶段的权限和所有者 %{_sbindir}/nginx(单个文件)%{_sysconfdir}nginx/(整个目录)%{_datadir}nginx/html/*(通配符匹配)
%defattr(mode, user, group, dir_mode) 定义文件默认属性(可选,现代系统可省略,默认继承系统属性):1. mode:文件默认权限(如 0644)2. user:文件默认所有者(如 root)3. group:文件默认所属组(如 root)4. dir_mode:目录默认权限(如 0755) %defattr(0644, root, root, 0755)
%config(noreplace) 标记配置文件,安装时若系统中已存在该配置文件,不会覆盖原有文件(仅生成 .rpmnew 后缀的新文件),避免用户配置丢失;省略noreplace 则会直接覆盖 %config(noreplace) %{_sysconfdir}/nginx/nginx.conf
%doc 标记文档文件(安装后存放于 %{_docdir}/%{name}-%{version} 目录),如 README、CHANGELOG 等,打包时会自动复制并归类 %doc README.md CHANGELOG LICENSE
%man 标记手册页文件(自动识别并安装到 %{_mandir} 对应目录,无需指定完整路径) %man nginx.8
%license 标记许可证文件(单独归类存放,便于用户查看,优先级高于 %doc %license LICENSE
%attr(mode, user, group) 为单个文件/目录指定自定义属性(覆盖 %defattr 默认值) %attr(0700, nginx, nginx) %{_localstatedir}/run/nginx(权限700,所有者nginx)
%dir 明确标记目录(若目录下无文件,需用 %dir 声明才会被包含到 RPM 包中) %dir %{_localstatedir}/log/nginx

六、 安装/卸载脚本段(定义运行时执行逻辑)

这类脚本段在 RPM 包安装、升级、卸载的不同阶段执行,用于完成系统配置、服务启停、用户创建等附加操作,支持标准 shell 命令。

脚本段 执行时机 详细说明 示例
%pre 预安装阶段(文件解压前) 用于准备工作(如创建系统用户/组、创建必要目录、备份旧文件等),运行身份为 root %pre# 创建nginx用户和组,若不存在getent group nginx >dev/null groupadd -r nginxgetent passwd nginx >dev/null useradd -r -g nginx -s /sbin/nologin -d %{_localstatedir}/lib/nginx nginx
%post 后安装阶段(文件解压后) 用于完成配置生效、服务启动、缓存更新等操作 %post# 重新加载systemd配置并启动nginx服务systemctl daemon-reload >dev/null 2>&1 :systemctl enable --now nginx >dev/null 2>&1 :
%preun 预卸载阶段(文件删除前) 用于停止服务、备份配置文件等操作,$1=0 表示完全卸载,$1=1 表示升级/降级 %preunif [ $1 -eq 0 ]; then # 完全卸载时停止nginx服务 systemctl stop nginx >dev/null 2>&1 :fi
%postun 后卸载阶段(文件删除后) 用于清理残留文件、重新加载配置、删除用户/组等操作 %postunif [ $1 -ge 1 ]; then # 升级时重启nginx服务 systemctl restart nginx >/dev/null 2>&1 :else # 完全卸载时清理残留并重载systemd systemctl daemon-reload >dev/null 2>&1 :fi
%verify 验证阶段(执行 rpm -V 时) 用于自定义软件验证规则(可选,极少使用),检查文件完整性、配置有效性等 %verifyif [ ! -f %{_sysconfdir}/nginx/nginx.conf ]; then echo "nginx config file missing" >&2 exit 1fi

关键说明:脚本中建议添加>/dev/null 2>&1 || :,避免非关键错误导致安装/卸载失败。

七、 条件判断(if/else)用法(灵活适配多场景)

RPM spec 文件的 if/else 是 RPM 内置的宏条件判断语法,非普通 shell 脚本判断,核心用于实现多架构适配、多发行版兼容、功能按需编译等灵活配置,核心关键字为 %if%else(可选)、%elif(可选)、%endif(必选,闭合条件块)。

7.1 核心语法格式


# 单分支判断
%if <条件表达式>
  # 满足条件时执行的配置/脚本/文件定义
%endif

# 双分支判断
%if <条件表达式>
  # 满足条件时的逻辑
%else
  # 不满足条件时的逻辑
%endif

# 多分支判断
%if <条件表达式1>
  # 满足条件1的逻辑
%elif <条件表达式2>
  # 满足条件2的逻辑
%else
  # 不满足所有前置条件的默认逻辑
%endif

关键说明:条件表达式前后无需加括号;条件块内可包含 spec 任意内容;%endif 必选;支持嵌套条件判断。

7.2 核心条件判断类型(常用场景)

7.2.1 基于系统架构判断(%{_arch} 宏)

通过内置宏 %{_arch} 获取当前构建系统的硬件架构(如 x86_64、aarch64、i386 等),实现不同架构的差异化配置。

常用表达式:

  1. 精确匹配:%if "%{_arch}" == "x86_64"
  2. 多值匹配:%if "%{_arch}" == "x86_64" || "%{_arch}" == "aarch64"
  3. 反向匹配:%if "%{_arch}" != "i386"

# 不同架构指定不同的构建依赖或文件路径
%if "%{_arch}" == "x86_64"
  BuildRequires: some-lib-x86_64-devel
  %{_libdir}/x86_64-linux-gnu/xxx.so
%elif "%{_arch}" == "aarch64"
  BuildRequires: some-lib-aarch64-devel
  %{_libdir}/aarch64-linux-gnu/xxx.so
%else
  BuildRequires: some-lib-devel
  %{_libdir}/xxx.so
%endif

7.2.2 基于宏是否定义判断(%{?宏名} / %{!宏名}

用于判断某个宏是否已定义,实现“可选功能”的开关配置,灵活度最高。

常用表达式:

  1. %if %{?宏名}:宏已定义则条件为真
  2. %if %{!宏名}:宏未定义则条件为真
  3. 结合值判断:%if "%{?宏名}" == "开启值"

# 自定义宏 --with-ssl,控制是否编译 SSL 功能
%define with_ssl 1

%if %{?with_ssl}
  BuildRequires: openssl-devel >= 1.1.1
  %build
  ./configure --with-ssl %{nil}
%else
  %build
  ./configure %{nil}
%endif

# 判断系统是否为 systemd 系统
%if %{?systemd}
  %{_unitdir}/nginx.service
  Requires(post): systemd
%endif

7.2.3 基于发行版版本判断(%{rhel} / %{fedora} 宏)

通过内置宏判断系统发行版及版本,实现 CentOS/RHEL 不同版本(如 el7、el8、el9)或 Fedora 不同版本的兼容适配。

常用内置宏:

  1. %{rhel}:CentOS/RHEL 主版本号(如 7、8、9)
  2. %{fedora}:Fedora 版本号(如 38、39)
  3. %{dist}:发行版标识(如 el7、fc39)

常用表达式:

  1. 版本比较:%if %{rhel} >= 8
  2. 精确版本:%if %{rhel} == 7

# 不同 CentOS/RHEL 版本的 Python 依赖差异
%if %{rhel} >= 8
  BuildRequires: python3-devel >= 3.6
  Requires: python3 >= 3.6
%else
  BuildRequires: python2-devel
  Requires: python2 >= 2.7
%endif

# 不同版本的系统服务配置差异
%if %{rhel} >= 7
  %post
  systemctl daemon-reload >/dev/null 2>&1 || :
  systemctl enable --now nginx >/dev/null 2>&1 || :
%else
  %post
  chkconfig --add nginx
  service nginx start >/dev/null 2>&1 || :
%endif

7.3 注意事项

  • 语法严格性:%if/%else/%elif/%endif 关键字必须单独成行,否则解析失败;

  • 宏的引号:字符串类型的宏(如%{_arch})判断时建议加双引号,避免宏值为空导致语法错误;

  • 嵌套限制:支持嵌套但层级不宜过深(建议≤3层),避免可读性差;

  • 调试方法:通过 rpmbuild -bp --nodeps xxx.spec 预处理 spec 文件,查看实际生效的配置。

八、 其他辅助选项与总结

8.1 其他辅助选项

选项 详细说明 示例
Patch0 补丁文件路径(多个补丁依次定义为 Patch1Patch2...),配合 %patch0 使用 Patch0: nginx-1.24.0-fix-config-path.patch
ExclusiveArch 指定仅支持的硬件架构,多个架构用空格分隔 ExclusiveArch: x86_64 aarch64
AutoReqProv 自动检测依赖和提供的功能(默认开启 yes,可关闭 no 手动指定) AutoReqProv: no
%define / %global 自定义宏(%global 作用域更广,推荐优先使用) %global nginx_user nginx

8.2 总结

RPM spec 文件的核心逻辑可归纳为“基础定义-依赖管理-构建执行-文件配置-灵活适配”五大模块,关键要点如下:

  1. 基础信息:Name/Version/Release/Summary/License 是必选,定义 RPM 包身份;

  2. 依赖管理:BuildRequires(构建依赖)、Requires(运行依赖)确保打包和运行完整性;

  3. 构建流程:%prep(解压补丁)、%build(编译)、%install(安装到临时目录)按顺序执行;

  4. 文件管理:%files 需与 %install 路径完全一致,通过 %config%attr 等指定文件属性;

  5. 灵活适配:条件判断(%if/%else)基于架构、发行版、宏定义实现多场景兼容,是复杂打包需求的核心工具。

    (注:文档部分内容由 AI 生成)

相关文章
|
8月前
|
Linux BI
rpm打包实战之Rocky Linux 9下打包protobuff
本教程介绍在Rocky Linux下使用RPM打包Protobuf的完整流程,涵盖rpmdevtools环境搭建、SPEC文件编写、rpmbuild构建及rpmlint规范检查,实现软件包的标准化制作与质量管控。
|
关系型数据库 MySQL Nacos
nacos数据库使用PostgreSQL及集群配置
从Nacos2.2版本开始,Nacos提供了数据源扩展插件,以便让需要进行其他数据库适配的用户自己编写插件来保存数据。
|
人工智能 安全 Apache
QwenPaw:你的私人 AI 助理 —— 数据归你、记忆进化、多端触达的开源个人智能体
QwenPaw 是一款开源、本地优先的AI个人智能体(Apache 2.0),数据归属用户、记忆自主进化、支持钉钉/飞书/微信等多端触达。3行命令即可部署,内置Coding IDE、Persona人格、定时任务、MCP工具生态与多Agent协作,真正属于你的私有AI助理。
QwenPaw:你的私人 AI 助理 —— 数据归你、记忆进化、多端触达的开源个人智能体
|
Ubuntu Linux 时序数据库
sudo apt-get update提示E: 仓库 “http://mirrors.aliyun.com/ubuntu eoan Release” 没有 Release 文件。亲试解决办法
将自己亲身解决这个办法进行分享,希望朋友们可以少走弯路。
12712 1
|
7月前
|
存储 NoSQL 安全
如何保存并分析Linux内核转储(coredump)文件
在Linux中,生成coredump需配置系统参数并满足程序条件。通过ulimit或limits.conf设置核心文件大小,修改core_pattern定义存储路径与命名格式,确保程序无信号屏蔽、权限限制,并留足磁盘空间,最后用gdb分析崩溃堆栈,便于调试定位问题。
|
监控 负载均衡 网络协议
TCP重传与超时机制:解锁网络性能之秘
TCP重传与超时机制:解锁网络性能之秘
4718 0

热门文章

最新文章