构建 RPM 包
1. RPM 简介
RPM (Resd HatPackage Manager ),顾名思义是 Red Hat 的软件包管理。RPM 可以让用户直接以 binary 方式安装软件包,并且可以在安装、更新和删除的时候自动解决软件包的依赖。
2. 构建 RPM 包
2.1. 安装工具
首先需要安装一些必要的打包工具。
yum install rpmdevtools
2.2. 创建工作空间
工作空间是 RPM 存放源码、编译、打包的一个场所。可以通过以下命令来创建一套标准化的工作空间。
rpmdev-setuptree
之后,就会得到这样这样一个目录
~/rpmbuild/
├── BUILD
├── BUILDROOT
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS
其中各个目录的作用及宏定义如下,宏定义将会在之后具体构建 RPM 包的时候,用来指代具体的路径。
| 路径 | 宏定义 | 说明 |
|---|---|---|
| ~/rpmbuild/SPECS | %_specdir | 保存 RPM 包配置(.spec)文件 |
| ~/rpmbuild/SOURCES | %_sourcedir | 保存源码包(如 .tar 包)和所有 patch 补丁 |
| ~/rpmbuild/BUILD | %_builddir | 源码包被解压至此,并在该目录的子目录完成编译 |
| ~/rpmbuild/BUILDROOT | %_buildrootdir | 保存 %install 阶段安装的文件 |
| ~/rpmbuild/RPMS | %_rpmdir | 生成/保存二进制 RPM 包 |
| ~/rpmbuild/SRPMS | %_srcrpmdir | 生成/保存源码 RPM 包(SRPM) |
2.3. 创建 Spec 文件
有了工作空间,将源码包和补丁文件等原材料放入 %_sourcedir 目录,便可以通过 spec 文件的指导,生成需要的 RPM 包。因此最为关键的就是如何根据需求编写一个 spec 文件。
3. Spec 文件组成
可以通过命令 rpmdev-newspec 来产生一个典型的 spec 模板。如下:
Name: lq-app
Version:
Release:
...
BuildRequires:
Requires:
%prep
%autosetup
%build
%configure
%make_build
%install
rm -rf $RPM_BUILD_ROOT
%make_install
%files
...
其中包含了构成 spec 文件的大部分条目,可以将其分为以下几种类型:
- 注释 -- 被 RPM 忽略的可读性说明
- 标签 -- 定义数据
- 脚本标识 -- 其后包含可执行的 shell 命令
- 宏定义 -- 包含多行 shell 命令的宏
- 文件清单 -- 指导哪些文件最终要包含在包中
- 指示符 -- 修饰文件清单中的文件
- 条件判断 -- 面向操作系统或者特定硬件体系的预处理
3.1. 注释
以 # 开头的行为注释。但是需要注意宏定义会在任何地方展开,因此需要在多行宏之前加 % 转义字符。比如 # %%configure 。
3.2. 标签
标签定义的格式为 <tag>:<value>。所支持标签都有特殊含义。标签是大小写不敏感的。以下列出一些常见的标签,详看Tags: Data Definitions。
| 标签 | 说明 |
|---|---|
| Name | 软件名称,详看注解 1 |
| Version | 软件版本 |
| Release | 发布次数 |
| Summary | 简介 |
| BuildArch | 构建体系,默认为编译机体系,可指定 noarch 编译体系架构无关包。 |
| License | 证书 |
| URL | 网址 |
| Packager | 打包人的姓名和邮箱 |
| Group | 软件包所属类别 |
| Source<num> | 源码包,可通过改变 num 指定多个。 |
| Patch<num> | 补丁包,可通过改变 num 指定多个。 |
| Provides | 提供的能力 |
| BuildRequires | 编译依赖 |
| Requires | 安转生成的 rpm 包时的依赖,详看注解 2 |
| Conflicts | 与当前软件包正常运行有冲突的包 |
| Obsoletes | 此软件的安转会导致过时的包,详看注解 3 |
| Description | 详细描述 |
注解:
name
最终生成的软件包名称为
<name>-<version>-<release>。BuildRequires
手动添加包需求的能力,详看下一章 包的依赖信息。
Obsoletes
表示安装当前包会导致过时的包。当更新(rpm -U)当前软件包时,会删除所有
Obsoletes的软件包。当安装(rpm -i)当前软件时,会将Obsolietes:当做Conflicts:,因此不会更新。详看 rpm.org - Obsoletes。
3.3. 脚本标识
此类 spec 条目,跟随其后的文本会被 RPM 传递给 shell 解释器直接执行,详看RPM:Scripts。主要分为两类:
-
Build-time : 表示构建包时执行的脚本。构建包时会依次执行以下条目内的脚本:
%prep、%build、%install、%check、%clean。 -
Install/Erase-time :表示安装、更新、删除包时执行的脚本。有
%pre、%post、%preun、%postun、%pretrans、%posttrans。具体如下:动作 说明 安装 依次执行 %pretrans、%pre、%post、%posttrans下的脚本。删除 依次执行 %preun、%postun下的脚本。更新 依次执行 %pretrans、%pre、%post、%preun(旧包)、%postun(旧包)、%posttrans下的脚本。
3.3.1. %prep
RPM 在看到此字段后,首先会自动进行初步检查,比如标签 source 指定的文件是否存在,然后进入 RPM 构建目录 %{_builddir},然后将 %prep 后文本传递给 shell 解释器直接执行。这些命令通常会选择做一些编译前的准备工作,比如解压源码包,应用补丁等。因此 RPM 提供了一些 shell 命令的宏定义来简化操作。比如 %setup 、%autosetup、%patch 。
3.3.2. %build
RPM 在看到此字段后,会自动进入到软件构建顶层目录 RPM_BUILD_DIR,默认是 %{_builddir}/%{name}-%{version},然后将 %build 后文本传递给 shell 解释器直接执行。这些命令通常为配置、编译源码包。此阶段常用宏有 %configure、%make_build 等。
3.3.3. %install
RPM 在看到此字段后,和 %build 相似,会自动进入到软件构建顶层目录,然后将 %install 后文本传递给 shell 解释器直接执行。这些命令通常为直接执行 make install,或执行一些复制文件和创建目录的操作。此阶段常用宏有 %make_install 等。
3.3.4. %check
RPM 在看到此字段后,和 %build 相似,会自动进入到软件构建顶层目录 ,然后将 %check 后文本传递给 shell 解释器直接执行。这些命令通常会选择执行一些测试程序,确认二进制程序可以正确工作,往往直接执行 make test 或者 make check。在 RPM 版本 4.2 之后开始支持 %check。
3.3.5. %clean
RPM 在看到此字段后,和 %build 相似,会自动进入到软件构建顶层目录 ,然后将 %clean 后文本传递给 shell 解释器直接执行。这些命令往往用于清除构建软件的一些文件,通常是直接执行 rm -rf $RPM_BUILD_ROOT。
3.3.6. %pre
安装软件包前,执行的脚本命令。
3.3.7. %post
安装软件包后,执行的脚本命令。比如,新安装一个共享库之后,执行 ldconfig 更新相关信息。
3.3.8. %preun
卸载软件前,执行的脚本命令。
3.3.9. %postun
卸载软件包后,执行的脚本命令。比如,卸载一个共享库之后,执行 ldconfig 删除相关信息。
3.3.8. %pretrans
在安转或更新所有事务前,执行的脚本命令。
3.3.9. %posttrans
在安转或更新所有事务后,执行的脚本命令。
3.4. 宏定义
可以通过 %define 来定义宏,比如:
%define myecho() echo %1 %2
%myecho first second
RPM 有一些预定义的用于简化 spec 文件编写的宏,存在于文件 /usr/lib/rpm/macros 下。常用的宏如下:
| 宏名 | 值 | 说明 |
|---|---|---|
| %_builddir | %{_topdir}/BUILD | 构建顶层目录 |
| %_buildshell | /bin/sh | 默认脚本解释器 |
| %_defaultdocdir | %{_datadir}/doc | 文档安装目录 |
| %_defaultlicensedir | %{_datadir}/licenses | 许可安装目录 |
| %_rpmdir | %{_topdir}/RPMS | 生成二进制包存在位置 |
| %_sourcedir | %{_topdir}/SOURCES | 源码即补丁存在位置 |
| %_specdir | %{_topdir}/SPECS | spec 文件存在位置 |
| %_srcrpmdir | %{_topdir}/SRPMS | 生成源码包存在位置 |
| %_buildrootdir | %{_topdir}/BUILDROOT | 所有包的虚拟安装根目录 |
| %buildroot | %{_buildrootdir}/%{NAME}-%{VERSION}-%{RELEASE}.% | 虚拟安装根目录,详看注解 1 |
| %_topdir | %{getenv:HOME}/rpmbuild | rpm 根目录,详看注解 2 |
| %_prefix | /usr | 安转文件的路径前缀,用于重定位安装文件 |
| %_datadir | %{_prefix}/share | 数据文件安装位置 |
| %configure | ... | 配置宏 |
| %make_install | %{__make} install DESTDIR=%{?buildroot} INSTALL="%{__install} -p" | 安装宏 |
| %setup | ... | 解压宏,详看注解 3 |
| %patch | ... | 打补丁宏,详看注解 4 |
| %autopatch | ... | 自动打补丁宏 |
| %autosetup | ... | 自动解压宏 |
注解:
%buildroot
在生成 rpm 包的
%install阶段,需要以此标签的值作为虚拟安装根目录。后面可直接引用,或使用$RPM_BUILD_ROOT的方式引用。%_topdir
rpm 根目录,一般通过命令行传参方式覆盖此默认值。如
rpmbuild --define="_topdir <topdir>"。%setup
主要作用是解压标签
%{source}指定的源码包,并进入目录%{_builddir}/%{name}-%{version}下。其扩展后的详细代码,和具体说明详看Macros: %setup,常用选项如下:
选项 说明 -n <dir> 指定自动进入目录名称。用于当源码解压后目录名不规范。 -c 解压之前先创建默认目录,用于压缩文件未包含在一个顶层目录下。 -q 抑制输出,可以减少日志的输出。 -D 解压前不删除目录。 -T 不执行默认解压动作。 -b <num> 切换目录前,解压 %{source<num>}指定的包。-a <num> 切换目录后,解压 %{source<num>}指定的包。注解:
-P <num>
表示应用标签
%{patch<num>}指定的补丁。也可以直接在宏定义后面指定,如%patch -P 1等价于%patch1。%patch
应用标签
%{patch}指定的补丁到已解压的源码上。其扩展后的详细代码,和具体说明详看Macros:patch,常用选项如下:
选项 说明 -p<num> 表示忽略路径层数,将直接传递给命令 patch。 -P <num> (大写 P)表示应用的补丁序号,详看注解 1-b<suffix> 指定备份文件的后缀。 -s 不显示详细信息。 注解:
-P <num>
表示应用标签
%{patch<num>}指定的补丁。也可以直接在宏定义后面指定,如%patch -P 1等价于%patch1。
3.5. 文件清单
文件清单为条目 %files 后的文本,每一行都被解释为一个文件的路径。表示为所有要被打包的文件清单。
一般情况下,此路径为全路径,即表示在构建系统中的定位,也表示安装包时的位置。
当路径是一个目录时,RPM 自动递归的包含此目录下所有文件。路径可以使用 shell-style 的通配符。
3.6. 指示符
指示条目用于修饰文件清单。详看Directives For the %files list。常用指示如下:
| 指示符 | 说明 |
|---|---|
| %doc | 标记文件是文档。详看注解 1 |
| %config | 标记文件是配置文件。详看注解 2 |
| %attr | 标记文件的属性,包括许可、用户和用户组。 |
| %defattr | 标记文件的默认属性。 |
| %ghost | 指示文件包含在包中,但不进行安装。 |
| %verify | 指示验证文件的各种属性以保证完整性。 |
注解:
%doc
RPM 会在文档目录(默认为
/usr/share/doc)下创建一个与包同名的目录,并将此指示符修饰的文件复制到此目录中。%config
标识文件是配置文件。如果文件在安装后发生修改,则在更新软件时应保留此文件。
3.7. 条件判断
面向操作系统或者特定硬件体系的预处理,详看Conditionals。常用条目如下:
%ifarch%ifnarch%ifos%ifnos%else%endif
4. 包的依赖信息
包的依赖关系通过包提供的能力(capabilities)和包需求的能力来解决。
- 需求的能力
- 依赖的共享库,由 RPM 调用命令
ldd自动生成。 - 由标签
requires手动添加。通常是其他软件包名称,可包含版本信息。
- 依赖的共享库,由 RPM 调用命令
- 提供的能力
- 提供的共享库
soname,由 RPM 自动生成。 - 由标签
provides手动添加。用于可替代其他软件包时。 - 包的名称和版本号,由 RPM 自动添加。
- 提供的共享库

浙公网安备 33010602011771号