二进制构建RPM 包

什么是 RPM 包?

RPM(Red Hat Package Manager)是一种用于 Linux 发行版的软件包管理系统和文件格式。RPM 包通常以 .rpm 为扩展名,包含了预编译的软件、安装脚本、元数据信息以及依赖关系等。

RPM 包的主要特点

  • 标准化安装:提供统一的安装、升级、卸载流程
  • 依赖管理:自动处理软件包之间的依赖关系
  • 版本控制:支持软件包的版本管理和回滚
  • 完整性校验:通过数字签名确保软件包的完整性和安全性
  • 跨平台支持:可以在不同的 Linux 发行版(如 RHEL、CentOS、Fedora、openSUSE 等)上使用

为什么需要构建 RPM 包?

  • 企业部署:在企业环境中,通过 RPM 包可以快速、标准化地部署软件
  • 版本管理:便于跟踪和管理不同版本的软件
  • 自动化运维:可以与自动化工具(如 Ansible、Puppet)集成,实现批量部署
  • 软件分发:通过搭建私有软件源,可以方便地在内网中分发软件

接下来,我们将介绍如何从二进制文件构建 RPM 包,这里我们用 JuiceFS 举例。

第 1 步:安装构建工具

1
yum install rpm-build rpmdevtools -y

rpmdevtools 包提供了一个非常有用的工具 rpmdev-setuptree,可以一键创建标准的构建目录结构。

当然,不安装这个工具也是可以的,工作目录完全可以手动创建,只是这样生成会比较快。

第 2 步:创建 RPM 构建环境

执行以下命名,创建标准的构建目录结构

1
rpmdev-setuptree

执行后,会在 ~ 目录下生成一个 rpmbuild 文件夹,其结构如下:

1
2
3
4
5
6
7
8
9
~/rpmbuild/
├── BUILD # 编译软件的临时目录
├── RPMS # 存放最终生成的二进制 RPM 包
├── SOURCES # 存放源代码压缩包、补丁等
│ └── juicefs-1.2.3.tar.gz
├── SPECS # 存放 .spec 文件
│ └── juicefs.spec
└── SRPMS # 存放生成的源码 RPM 包

第 3 步:准备二进制文件

在 juicefs 文件执行 make 命令,编译二进制文件

将二进制文件打包成 .tar.gz 包 

1
2
3
4
5
6
# 创建目录
mkdir juicefs-1.2.3
# 放入二进制文件
mv juicefs juicefs-1.2.3
# 打包并压缩
tar -czvf juicefs-1.2.3.tar.gz juicefs-2.3.3

将 tar 包拷贝到 rpmbuild 目录中的 SOURCES 文件目录下。

第 4 步:编写 .spec 文件

~/rpmbuild/SPECS/ 目录下创建一个 .spec 文件。

.spec 文件关键部分解析:

  • Preamble (元数据区):

    • Name, Version, Release: 软件包的基本信息。Release 后的 %{?dist} 是一个宏,会自动适配不同的发行版(如 .el8, .el9, .fc38)。

    • Summary: 软件包的一句话简介。

    • License: 软件包的许可证。

    • URL: 项目主页。

    • Source0: 源代码包的名称,%{name}%{version} 是自动引用的变量。

    • BuildRequires: 构建这个RPM包所需要的依赖(例如编译器)。

  • Sections (指令区):

    • %description: 详细描述。

    • %prep: 构建 RPM 包的准备阶段,用于解压源码、应用补丁、准备目录等。%setup -q 是一个宏,会自动解压 Source0 定义的源码包到 BUILD 目录。

    • %build: 构建阶段。在这里执行编译命令,如 makegcc

    • %install: 构建 RPM 包阶段,是构建阶段的脚本,不会在用户安装 RPM 时执行。将编译好的文件从 BUILD 目录安装到 %{buildroot} 目录中。%{buildroot} 是一个临时的、空的目录结构,rpmbuild 会在这里模拟安装过程。%{_bindir} 是一个标准宏,通常指向 /usr/bin

    • %postun: 卸载阶段,是在软件包卸载之后执行的脚本。

    • %posttrans: 事务完成脚本,在安装或升级完成后执行(类似“安装收尾动作”)。

    • %files: 文件列表。非常重要,这里必须明确列出所有要打包进RPM的文件。这些文件路径是相对于 %{buildroot} 的。

    • %changelog: 变更日志。

以下是一个写好的 .spec 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Name:           juicefs
Version: 1.2.3
Release: 1%{?dist}
Summary: JuiceFS is an open-source, high-performance distributed file system designed for the cloud.
License: Apache License 2.0
URL: http://download2.com/
Source0: http://download2.com/cdos/%{name}/releases/%{name}-%{version}.tar.gz

%description
JuiceFS is an open-source, high-performance distributed file system designed for the cloud, released under the Apache License 2.0. By providing full POSIX compatibility, it allows almost all kinds of object storage to be used as massive local disks and to be mounted and accessed on different hosts across platforms and regions.

%prep
%setup -q

%global debug_package %{nil}
%build

%pre
mkdir -p /root/.test_juicefs/
rm -rf /tmp/.test_juicefs/
cp /root/.test_juicefs/ /tmp/.test_juicefs/ -r


%install
mkdir -p %{buildroot}/%{_bindir}
install -m 0755 juicefs %{buildroot}%{_bindir}/juicefs


%postun
rm /root/.test_juicefs/ -rf

%posttrans
mkdir -p /tmp/.test_juicefs/
cp /tmp/.test_juicefs/ /root/.test_juicefs/ -r

%files
%{_bindir}/juicefs

%changelog
* Wed Nov 19 2025 Fruitee <kejp@test.com> - 1.3.0-1
- Release juicefs version 1.3.0+test2025-11-17

%setup -q 的意思是:自动解压 Source0,并进入解压目录(默认目录名是 juicefs-1.2.3/)。

在这个构建脚本中,我们将 %build 设置为空的,因为我们已经提前构建好了二进制包,不需要在这里进行构建。

%global debug_package %{nil} 是为了 禁用 debug 包的生成(juicefs-debuginfo),因为 JuiceFS 是一个单二进制,没有必要生成 debuginfo。

%pre 阶段,执行安装前脚本,rpm 包会在 root 目录下面创建 /root/.test_juicefs,并且备份到 /tmp/.test_juicefs/ 中。

%install 阶段并不是用来在系统上安装 rpm 包的,而是用来进行包的构建。%{buildroot} 这里指的是 rpmbuild 的构建目录,而 %{_bindir} 是 rpm 包的安装目录。这样的目的其实是为了构建一个完整的 rpm 包安装路径,这个文件内部就像一个压缩包,里面记录着:“我包含一个文件,名叫 juicefs,它将来应该被放在 /usr/bin/ 下。”

%postun 表示 rpm 软件包卸载之后的脚本,这里其实就是清理了 /root/.test_juicefs 目录。

%posttrans 是事务完成后执行的脚本,这是所有安装/卸载动作彻底结束后最后执行的一步。它把 %pre 阶段备份到 /tmp 的数据,重新复制回 /root。

%files 是文件列表,声明哪些文件属于这个软件包。这里只有一个 /usr/bin/juicefs。

第 5 步:执行构建命令

1
2
3
4
5
6
7
8
9
# 切换到 rpmbuild 目录
cd ~/rpmbuild/

# 执行构建命令
# -bb 表示 build binary (只构建二进制RPM包)
rpmbuild -bb --define "_topdir $(pwd)" ./SPECS/juicefs.spec

# 在 x86 平台构建 arm64 的 rpm 包
rpmbuild -bb --define "_topdir $(pwd)" --target aarch64-linux ./SPECS/juicefs.spec
  • --define "_topdir $(pwd)" 的意思就是:

“告诉 rpmbuild,不要使用默认的 ~/rpmbuild 作为构建的顶级目录。请使用我当前所在的这个目录作为本次构建的顶级目录 (_topdir)。”

  • -bb: 只构建二进制包 (Binary RPM)。

  • -ba: 构建二进制包和源码包 (Source RPM, SRPM)。

第 6 步:验证和安装 RPM 包

查询RPM包信息:
在安装前,可以先查看包的信息。

1
2
3
4
5
# 查询包的基本信息
rpm -qip ~/rpmbuild/RPMS/x86_64/juicefs-*.rpm

# 查询包内包含的文件
rpm -qlp ~/rpmbuild/RPMS/x86_64/juicefs-*.rpm

安装并测试:

1
2
3
4
# 使用 sudo 安装
sudo rpm -ivh ~/rpmbuild/RPMS/x86_64/juicefs-*.rpm
# 或者使用 yum 安装,可以自动处理依赖
sudo yum install ~/rpmbuild/RPMS/x86_64/juicefs-*.rpm