Red Hat Training

A Red Hat training course is available for Red Hat Enterprise Linux

第 3 章 打包软件

3.1. RPM 软件包

本节介绍 RPM 打包格式的基础知识。

3.1.1. RPM 是什么

RPM 软件包是包含其它文件和元数据的文件(系统所需文件的信息)。

特别是,RPM 软件包由 cpio 归档组成。

cpio 归档包含:

  • 文件
  • RPM 标头(软件包元数据)

    rpm 软件包管理器使用此元数据来确定依赖项、安装文件的位置和其他信息。

RPM 软件包的类型

RPM 软件包有两种类型。这两种类型都共享文件格式和工具,但内容不同,并实现不同的目的:

  • 源 RPM(SRPM)

    SRPM 包含源代码和 SPEC 文件,这些文件描述了如何将源代码构建为二进制 RPM。另外,也可以选择包括源代码的补丁。

  • 二进制 RPM

    一个二进制 RPM 包含了根据源代码和补丁构建的二进制文件。

3.1.2. 列出 RPM 打包工具的工具

以下流程演示了如何列出 rpmdevtools 软件包提供的工具。

先决条件

为了可以使用 RPM 打包工具,您需要安装 rpmdevtools 软件包,该软件包为打包 RPM 提供了多个实用程序。

# yum install rpmdevtools

流程

  • 列出 RPM 打包工具的工具:

    $ rpm -ql rpmdevtools | grep bin

附加信息

  • 有关以上实用程序的更多信息,请参阅其手册页或帮助对话框。

3.1.3. 设置 RPM 打包工作区

这部分论述了如何使用 rpmdev-setuptree 程序设置属于 RPM 打包工作区的目录布局。

先决条件

在您的系统中必须安装 rpmdevtools 软件包:

# yum install rpmdevtools

流程

  • 运行 rpmdev-setuptree 程序:
$ rpmdev-setuptree

$ tree ~/rpmbuild/
/home/<username>/rpmbuild/
|-- BUILD
|-- RPMS
|-- SOURCES
|-- SPECS
`-- SRPMS

5 directories, 0 files

创建的目录用于这些目的:

目录

目的

BUILD

构建软件包时,会创建各种 %buildroot 目录。如果日志输出没有足够的信息,这可用于调查失败的构建。

RPMS

此处创建了二进制 RPM,在用于不同架构的子目录中创建,例如在子目录 x86_64noarch 中。

此处,打包商放置了压缩源代码存档和补丁。rpmbuild 命令将在此处查找它们。

SPECS

软件包程序在此放置 SPEC 文件。

SRPMS

rpmbuild 用于构建 SRPM 而不是二进制 RPM 时,会创建生成的 SRPM。

3.1.4. SPEC 文件是什么

您可以将 SPEC 文件作为 rpmbuild 实用程序用来构建 RPM 的配方。SPEC 文件通过定义一系列部分中的说明,为构建系统提供必要信息。这些部分在 PreambleBody 部分中定义。Preamble 部分包含一系列在 Body 部分中使用的元数据项。Body 部分代表说明的主要部分。

3.1.4.1. Preamble Items

下表介绍了 RPM SPEC 文件的 Preamble 部分中经常使用的一些指令。

表 3.1. RPM SPEC 文件的 Preamble 部分中使用的项目

SPEC 指令定义

名称

软件包的基本名称,应该与 SPEC 文件名匹配。

版本

软件的上游版本。

Release

发布此软件版本的次数。通常,将初始值设为 1%{?dist},并在每个新版软件包中递增。当软件的一个新版本构建时,将重置为 1。

概述

软件包的一个简短总结.

许可证

所打包的软件许可证。

URL

有关程序的更多信息的完整 URL。大多数情况下,这是所打包软件的上游项目网站。

Source0

上游源代码的压缩存档的路径或 URL(未修补,补丁会在其他位置处理)。这应该指向该存档的可访问且可靠的存储,例如上游页面而不是打包程序的本地存储。如果需要,可以添加更多 SourceX 指令,每次递增数字,例如: Source1、Source2、Source3 等。

Patch

应用于源代码的第一个补丁的名称(如有必要)。

该指令可以通过两种方式应用:带有或不带补丁末尾的数字。

如果没有指定数字,则会在内部分配一个条目。也可以使用 Patch0, Patch1, Patch2, Patch3 明确提供数字。

这些补丁可以通过使用 %patch0、%patch1、%patch2 宏等应用。宏在 RPM SPEC 文件的 Body 部分中的 %prep 指令中应用。或者,您可以使用 %autopatch 宏,以 SPEC 文件中提供的顺序自动应用所有补丁。

BuildArch

如果软件包没有架构依赖,例如,如果完全使用解释编程语言编写,则将其设置为 BuildArch: noarch。如果没有设置,软件包会自动继承构建机器的架构,如 x86_64

BuildRequires

使用编译语言构建程序所需的逗号或空格分开的软件包列表。BuildRequires 可以有多个条目,每个条目都在 SPEC 文件中的独立的行中。

Requires

安装之后,软件需要以逗号或空格分开的软件包列表。Requires 可以有多个条目,每个条目都在 SPEC 文件中的独立的行中。

ExcludeArch

如果某一软件不能在特定处理器架构上运行,您可以在此处排除该架构。

Conflicts

ConflictsRequires 相反。如果存在与 Conflicts 匹配的软件包,则软件包是否可以安装取决于,带有 Conflict 标签的软件包是否位于已安装的软件包中,还是准备要被安装到的软件包中。

Obsoletes

这个指令会改变更新的工作方式,具体取决于 rpm 命令是否直接在命令行中使用,或者更新是由更新还是依赖项解析程序执行。当在命令行中使用时,RPM 会删除与正在安装的软件包的过时匹配的所有软件包。当使用更新或依赖项解析器时,包含匹配 Obsoletes: 的软件包会作为更新添加并替换匹配的软件包。

Provides

如果向软件包添加了 Provides,则软件包可以通过名称以外的依赖项引用。

NameVersionRelease 指令包含 RPM 软件包的文件名。RPM 软件包维护者和系统管理员经常调用这三个指令 N-V-RNVR,因为 RPM 软件包文件名具有 NAME-VERSION-RELEASE 格式。

以下示例演示了如何通过查询 rpm 命令获取特定软件包的 NVR 信息。

例 3.1. 查询 rpm 为 bash 软件包提供 NVR 信息

$ rpm -q bash
bash-4.2.46-34.el7.x86_64

在这里,bash 是软件包名称,4.2.46 是版本,34.el7 是发行版本。最后的标记是 x86_64,它向架构发出信号。与 NVR 不同,架构标记不直接控制 RPM 打包程序,而是由 rpmbuild 构建环境进行定义。这种情况的例外是独立于架构的 noarch 软件包。

3.1.4.2. 正文项目

下表列出 RPM SPEC 文件的 Body 部分中使用的项目。

表 3.2. RPM SPEC 文件的 Body 部分中使用的项目

SPEC 指令定义

%description

RPM 中打包的软件的完整描述。此描述可跨越多行,并且可以分为几个段落。

%prep

用于准备要构建的软件的命令或一系列命令,例如,在 Source0 中解压缩存档。此指令可以包含 shell 脚本。

%build

将软件构建到机器代码(用于编译的语言)或字节代码(用于某些解释语言)的命令或一系列命令。

%install

命令或一系列命令,用于将所需的构建工件从 %builddir (构建发生位置)复制到 %buildroot 目录(其中包含要打包文件的目录结构)。这通常意味着将文件从 ~/rpmbuild/BUILD 复制到 ~/rpmbuild/BUILDROOT,并在 ~/rpmbuild/BUILDROOT 中创建必要的目录。这仅在创建软件包时运行,而不是当最终用户安装软件包时。详情请查看 第 3.2 节 “使用 SPEC 文件”

%check

用于测试软件的命令或一系列命令。这通常包括单元测试等内容。

%files

将在最终用户系统中安装的文件列表。

%changelog

在不同 VersionRelease 之间软件包所发生的更改记录。

3.1.4.3. 高级 items

SPEC 文件还可以包含高级项目,如 ScriptletsTriggers。它们在安装过程中对最终用户系统而不是构建过程的不同点生效。

3.1.5. BuildRoots

在 RPM 打包上下文中,buildroot 是 chroot 环境。这意味着,构建工件被放在使用与最终用户系统中未来层次结构相同的文件系统层次结构,并将 buildroot 用作根目录。构建工件的放置应遵守最终用户系统的文件系统层次结构标准。

buildroot 中的文件稍后放入 cpio 存档,后者成为 RPM 的主要部分。当在最终用户的系统中安装 RPM 时,这些文件将提取到 root 目录中,保留正确的层次结构。

注意

从 6 开始,rpmbuild 程序有自己的默认值。覆盖这些默认设置会导致几个问题,因此 {RH} 不推荐定义这个宏的值。您可以在 rpmbuild 目录中使用 %{buildroot} 宏。

3.1.6. RPM 宏

rpm 宏 是一种直接文本替换,在使用特定内置功能时,可以根据声明的可选评估来有条件地分配。因此,RPM 可以为您执行文本替换。

示例用法是在 SPEC 文件中多次引用打包软件 Version。您仅在 %{version} 宏中定义 Version 一次,并在 SPEC 文件中使用此宏。每次出现时都会自动替换为您之前定义的 Version

注意

如果您看到不熟悉的宏,您可以使用以下命令评估它:

$ rpm --eval %{_MACRO}

评估 %{_bindir} 和 %{_libexecdir} 宏

$ rpm --eval %{_bindir}
/usr/bin

$ rpm --eval %{_libexecdir}
/usr/libexec

常用的宏是 %{?dist} 宏,它向哪个发行版发出用于构建的信号(分配标签)。

# On a RHEL 8.x machine
$ rpm --eval %{?dist}
.el8