构建一个 RPM 包,基本思路:
明确你要构建什么。一个 rpm 包可能只是一个应用程序,也可能是不需要编译的包含一堆网页文件的 rpm 包,也可能是一个包含库的单独的 rpm 包,也可能只是文档性质的 rpm 包,也可能是补丁性质的 rpm 包,也可能只是包含配置文件的 rpm 包。
- 准备好「原材料」,也就是项目源代码的压缩归档文件,常以 .tar.gz 或 .tar.xz 或 .tar.bz2 等后缀结尾
- 收集补丁,给 rpm 打补丁
- 升级,包含兼容性、功能改进和冲突解决等
- 依赖关系。每个 rpm 都有一个能力,这个能力大多数情况下都与其名字有关。众所周知,rpm 安装后生成一堆文件,释放出的对应文件也是一种能力体现,它们有可能被其他 rpm 包依赖。换言之,这里的能力包括包的名称、包安装后的文件。在制作 rpm 的时候,有两类依赖关系:一个叫编译依赖(BuildRequires);一个叫安装依赖(Requires)
- 编写一个 spec 文件。spec 是配置规范文件,可理解为打包成 rpm 格式的配方。
- 开始构建 rpm 包,生成 rpm 包
- 对 rpm 包进行测试
构建要求
- 目录结构要求 – rpm 包的构建需要对目录结构有一定的要求,可理解为构建时所必须的「工作目录」
- 构建时使用的用户 – 推荐使用 root (uid=0),当然普通用户(uid>=1000)也可以进行构建
- 将「原材料」放入到对应的目录中
- 编写 spec 文件,编译打包成 rpm 包
spec 文件
什么是 spec 文件?
一个包含元数据、构建指令和安装规则的脚本,它驱动整个 RPM 包的生成流程,定义了软件从源码编译到最终打包的所有步骤。spec 的文件内容包含三部分:
- 序言项(Preamble items)
- 主体项(Body items)
- 高级项(Advanced items)
除了序言项,其他部分都需要定义一些指令为构建系统提供必要的信息。
序言项标签
- Name – 软件包的基本名称,应与 spec 文件名匹配
- Version – 软件包的上游版本号,注意!这里的版本号不要带 – ,- 在 spec 中有特殊的意义
- Release – 此软件包的发布次数。通常将初始值设置为 1%{?dist}
- Summary – 简短的、单行的说明软件包的摘要信息
- License – 被打包的软件包的开源许可证
- URL – 大多数情况下,这是所打软件包的上游项目网站。
- Source0 – 上游源代码压缩包存档的路径或URL
- Patch – 补丁,可以有两种方式应用该指令,在 Patch 后面加或不加数字。也可以使用 %Patch0 这种方式。
- BuildArch – 构建的体系架构,如果软件包不依赖特定的架构,可写为 BuildArch: noarch。如果不写,则自动继承当前机器的体系架构
- BuildRequires – 编译时的依赖包,多个依赖包可用空格或逗号分隔。可以有多个 BuildRequires 条目
- Requires – 软件安装后运行所需的依赖包,多个依赖包可用空格或逗号分隔。可以有多个 Requires 条目
- ExcludeArch – 如果某个软件不能在特定的处理器架构上运行,你可以在此处排除该架构
- Conflicts – 冲突的包,与 Requires 相反,如果匹配到对应的包,则无法安装该包。
- Obsoletes – 废弃的包,也就是其他包提供的功能已经不推荐使用了 rpm 软件包的命名规范:
rpm 软件包的命名规范:
[Package_Name]-[Version]-[Release].[OS].[Arch].rpm [Package_Name]-[Version]-[Release].[OS].[Arch].src.rpmNote:通常一个 rpm 软件包的完整名称由 Name、Version、Release 组成,我们称其为 NVR,即 Name-Version-Release.rpm。在上面的命名规范中,有些资料也将 [Release].[OS].[Arch] 这三部分单独划分到 Release 中。
主体项指令
一个软件包能否打包成功,全看主体项的各种步骤。
- %description – rpm 软件包的完整描述,可跨越多行,可分为多列。
- %prep – 预处理(编译前的准备操作),为下一步编译安装做准备。
- %build – 编译位于 BUILD 目录里的文件,类似源代码安装 ./configure && make 的操作。
- %install – 将 BUILD 目录的文件安装至 BUILDROOT 目录下,需要注意的是!这个 BUILDROOT 目录是最终用户安装 rpm 后得到的文件 。类似源代码安装中的 make install
- %check – 用于测试软件的一系列命令。类似源代码安装中的 make test
- %files – 制作 rpm 包时应该包含哪些文件。注意!这里的文件一定是和 BUILDROOT 目录下是一一对应的关系(除了 debug 目录)。BUILDROOT 是一个模拟操作系统根的临时目录。
- %changelog – 每个 release 所做的变更日志,例如漏洞修复、补丁、额外的功能增强等。
高级项
高级项包含 Scriptlet(程序段)与 Triggers(触发器)。
- Scriptlet 是在安装或删除软件包之前或之后执行的一系列 RPM 指令;Triggers 提供了一种在安装和卸载软件包期间进行交互的方法。Triggers 难以调试,因此要尽量减少使用它。
- %pre – 在安装包之前执行的程序段
- %pretrans – 在安装或删除任何包之前执行的程序段
- %post – 在安装包之后执行的程序段
- %preun – 在卸载包之前执行的程序段,通常在升级的时候会执行
- %postun – 在卸载包之后执行的程序段
- %posttrans – 在事务结束时执行的程序段
关于这部分内容的更多内容,请参阅 这里。
rpm 软件包构建实验
实验要求:将 Nginx 最新版本构建成 rpm 包
环境: 操作系统:Rocky Linux 8.10
rpm 版本:4.14.3
用户:root (uid=0)
准备好需要的命令行工具:
Shell > dnf -y install rpmdevtools rpm-build其中 rpmdevtools 软件包包含这些基本的命令行工具:
- rpmdev-setuptree 在当前用户家目录中生成 rpm 的构建树(build tree)
- rpmdev-diff 比对两个归档的不同内容
- rpmdev-newspec 从模板中创建新的 .spec 文件
- rpmdev-checksig 使用备用的rpm密钥环检查软件包的签名
- rpminfo 打印有关可执行文件和库的信息
- rpmdev-md5 显示 RPM 中所有文件的 md5 校验
步骤一:准备「工作目录」
Shell > cd ; rpmdev-setuptree
Shell > tree rpmbuild/
rpmbuild/
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS目录 说明
- BUILD 构建过程中的工作目录
- RPMS 存放生成的二进制 rpm 包
- SOURCES 存放构建所需的资源,包含源码压缩文件、补丁文件、配置文件等
- SPECS 核心目录,存放 spec 文件
- SRPMS 存放生成的源码 RPM 包(.src.rpm),其包含源代码和 .spec 文件,便于分发和重新构建
步骤二:使用 spec 文件
有两种方式创建 spec 文件:
使用者创建一个全新的 spec 文件,文件内容需要自行填写
使用 rpmdev-newspec 命令工具创建一个 spec 模块文件,使用者只需填写必要的指令与字段即可
Shell > cd /root/rpmbuild/SOURCES ; wget -c https://nginx.org/download/nginx-1.29.0.tar.gz
Shell > cd /root/rpmbuild/SPECS ; rpmdev-newspec nginx
nginx.spec created; type minimal, rpm version >= 4.14.
# 该文件的内容如下:
Shell > cat nginx.spec
Name: nginx
Version:
Release: 1%{?dist}
Summary:
License:
URL:
Source0:
BuildRequires:
Requires:
%description
%prep
%autosetup
%build
%configure
%make_build
%install
rm -rf $RPM_BUILD_ROOT
%make_install
%files
%license add-license-file-here
%doc add-docs-here
%changelog
* Fri Jul 4 2025 root
-修改之后的内容如下:
Name: nginx
Version: 1.29.0
Release: 1%{?dist}
Summary: A high performance web server and reverse proxy server
License: BSD
URL: http://nginx.org/
Source0: %{name}-%{version}.tar.gz
BuildRequires: gcc gcc-c++ openssl openssl-devel make pcre pcre-devel gzip tar bzip2 bzip2-devel
# Requires:
%description
Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and \
IMAP protocols, with a strong focus on high concurrency, performance and low \
memory usage.
%prep
%setup -q
%build
./configure \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--http-log-path=/var/log/nginx/access.log \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_stub_status_module \
--with-http_gzip_static_module
make %{_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=%{buildroot}
%{__install} -p -d -m 0755 %{buildroot}/var/run/nginx
%{__install} -p -d -m 0755 %{buildroot}/var/log/nginx
%clean
rm -rf %{buildroot}
%pre
# $1表示软件包的执行方式,0表示卸载;1表示第一次安装;2表示升级
if [ $1 == 1 ];then
/usr/sbin/groupadd -r nginx 2> /dev/null
/usr/sbin/useradd -r -g nginx nginx 2> /dev/null
fi
%files
%defattr(-,root,root,-)
%doc LICENSE CHANGES README
%{_sbindir}/%{name}
%dir /var/run/nginx
%dir /var/log/nginx
%dir /etc/nginx
%config(noreplace) /etc/nginx/fastcgi.conf
%config(noreplace) /etc/nginx/fastcgi.conf.default
%config(noreplace) /etc/nginx/fastcgi_params
%config(noreplace) /etc/nginx/fastcgi_params.default
%config(noreplace) /etc/nginx/koi-utf
%config(noreplace) /etc/nginx/koi-win
%config(noreplace) /etc/nginx/mime.types
%config(noreplace) /etc/nginx/mime.types.default
%config(noreplace) /etc/nginx/nginx.conf
%config(noreplace) /etc/nginx/nginx.conf.default
%config(noreplace) /etc/nginx/scgi_params
%config(noreplace) /etc/nginx/scgi_params.default
%config(noreplace) /etc/nginx/uwsgi_params
%config(noreplace) /etc/nginx/uwsgi_params.default
%config(noreplace) /etc/nginx/win-utf
/usr/local/nginx/html/50x.html
/usr/local/nginx/html/index.html
%changelog
* Fri Jul 4 2025 root
- first version
- init
稍后我们将说明 spec 文件中的内容。
步骤三:使用 rpmbuild 进行构建 常见选项如下表所示:
- -bp 只执行到 %prep 阶段
- -bi 只执行到 %install 阶段
- -bc 只执行到 %build 阶段
- -bb 制作二进制的 rpm 包
- -bs 制作源码格式的 rpm 包
- -bl 检测,检测哪些文件在 BUILDROOT 目录下安装生成了,但是在 spec 文件中的 %files 没有包含进来
- -ba 既制作二进制的 rpm 包,也制作源码格式的 rpm包
使用 -bp 选项时:
若输出文本的最后一行看到 exit 0 表示无任何问题
Shell > rpmbuild -bp /root/rpmbuild/SPECS/nginx.spec
Shell > ls /root/rpmbuild/BUILD
nginx-1.29.0
Shell > ls -lh /root/rpmbuild/BUILD/nginx-1.29.0/使用 -bc 选项时:
检查环境后会执行编译过程
同样的,若输出文本的最后一行看到 exit 0 表示无任何问题
Shell > rpmbuild -bc /root/rpmbuild/SPECS/nginx.spec使用 -bi 选项时:
未出现 error 或 file not found 之类的错误则表示正常
Shell > rpmbuild -bi /root/rpmbuild/SPECS/nginx.spec使用 -ba 选项时:
Shell > rpmbuild -ba /root/rpmbuild/SPECS/nginx.spec
Shell > tree /root/rpmbuild/RPMS/步骤四:安装 我们的 nginx-1.29.0-1.el8.x86_64.rpm 已经制作完成,安装即可:
Shell > rpm -ivh /root/rpmbuild/RPMS/x86_64/nginx-1.29.0-1.el8.x86_64.rpm
Verifying... ################################# [100%]
Preparing... ################################# [100%]
Updating / installing...
1:nginx-1.29.0-1.el8 ################################# [100%]
# 释放出的文件
Shell > rpm -ql nginx请注意!我这里并没有将 nginx 的启动 unit 存放在 /usr/lib/systemd/system/ 目录中。 到这一步,构建 nginx 的简单 rpm 包就完成了。
最后
spec 文件的内容非常丰富,单靠这一篇文档是可能了解完整的,详情参阅官方的 手册页
对于一般的使用者或运维人员来说,构建考虑全面的 rpm 包是一件非常费时费力的事情,主要原因在于其涉及的多环节精细化管理与技术挑战:
- 依赖管理的复杂性。库依赖、依赖冲突等
- spec 文件编写的技术门槛。需要考虑多阶段构建流程、跨平台适配以及相关的脚本逻辑,比如一些关系型数据库的 RPM 包需在spec 中声明 400+ 文件路径及 20+ 依赖项
- 高昂的测试与验证成本。需要考虑卸载后无残留文件、升级时配置文件保留(.rpmnew 机制),还要考虑在不同的 RHEL 衍生版去验证一致性。
转载自:
https://www.rockylinux.cn/notes/rpm-fundamentals-02-building-software-packages.html