Linux之RPM打包指南

使用的Linux系统

  • Redhat
  • Centos
  • Fedora
  • Mandriva
  • SuSE

环境安装初始化

1. 安装 rpmdevtools 软件包

1
$ yum install rpmdevtools

2. 运行 rpmdev-setuptree 程序:

1
2
3
4
5
6
7
8
9
$ rpmdev-setuptree

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

3. 创建的目录说明

目录 目的
BUILD 构建软件包时,会创建各种 %buildroot 目录。如果日志输出没有足够的信息,这可用于调查失败的构建。
RPMS 此处创建了二进制 RPM,在用于不同架构的子目录中创建,例如在子目录 x86_64 和 noarch 中。
SOURCES 此处,打包商放置了压缩源代码存档和补丁。rpmbuild 命令将在此处查找它们。
SPECS 软件包程序在此放置 SPEC 文件。
SRPMS 当 rpmbuild 用于构建 SRPM 而不是二进制 RPM 时,会创建生成的 SRPM。

打包SPEC配置

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

SPEC 指令 定义
Name 软件包的基本名称,应该与 SPEC 文件名匹配。
Version 软件的上游版本。
Release 发布此软件版本的次数。通常,将初始值设为 1%{?dist},并在每个新版软件包中递增。当软件的一个新版本构建时,将重置为 1。
Summary 软件包的一个简短总结。
License 所打包的软件许可证。
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 Conflicts 与 Requires 相反。如果存在与 Conflicts 匹配的软件包,则软件包是否可以安装取决于,带有 Conflict 标签的软件包是否位于已安装的软件包中,还是准备要被安装到的软件包中。
Obsoletes 这个指令会改变更新的工作方式,具体取决于 rpm 命令是否直接在命令行中使用,或者更新是由更新还是依赖项解析程序执行。当在命令行中使用时,RPM 会删除与正在安装的软件包的过时匹配的所有软件包。当使用更新或依赖项解析器时,包含匹配 Obsoletes: 的软件包会作为更新添加并替换匹配的软件包。
Provides 如果向软件包添加了 Provides,则软件包可以通过名称以外的依赖项引用。

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

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

SPEC 指令 定义
%description RPM 中打包的软件的完整描述。此描述可跨越多行,并且可以分为几个段落。
%prep 用于准备要构建的软件的命令或一系列命令,例如,在 Source0 中解压缩存档。此指令可以包含 shell 脚本。
%build 将软件构建到机器代码(用于编译的语言)或字节代码(用于某些解释语言)的命令或一系列命令。
%install 命令或一系列命令,用于将所需的构建工件从 %builddir (构建发生位置)复制到 %buildroot 目录(其中包含要打包文件的目录结构)。这通常意味着将文件从 ~/rpmbuild/BUILD 复制到 ~/rpmbuild/BUILDROOT,并在 ~/rpmbuild/BUILDROOT 中创建必要的目录。这仅在创建软件包时运行,而不是当最终用户安装软件包时。
%check 用于测试软件的命令或一系列命令。这通常包括单元测试等内容。
%files 将在最终用户系统中安装的文件列表。
%changelog 在不同 Version 或 Release 之间软件包所发生的更改记录。

3. RPM 宏

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    $ rpm --eval %{_MACRO}

    #评估 %{_bindir} 和 %{_libexecdir} 宏
    $ rpm --eval %{_bindir}
    /usr/bin

    $ rpm --eval %{_libexecdir}
    /usr/libexec
  • 如在 %{version} 宏中定义 Version 一次,并在 SPEC 文件中使用此宏。每次出现时都会自动替换为您之前定义的 Version。

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

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

打包流程说明

1. 使用 rpmdev-newspec 创建新的 SPEC 文件

进入 ~/rpmbuild/SPECS 目录并使用 rpmdev-newspec 实用程序:

1
2
3
4
5
6
7
8
9
10
$ cd ~/rpmbuild/SPECS

$ rpmdev-newspec bello
bello.spec created; type minimal, rpm version >= 4.11.

$ rpmdev-newspec cello
cello.spec created; type minimal, rpm version >= 4.11.

$ rpmdev-newspec pello
pello.spec created; type minimal, rpm version >= 4.11.

2. 修改 rpmdev-newspec 提供的输出 SPEC 文件以创建 RPM。

先决条件

  1. 特定程序的源代码已放入 ~/rpmbuild/SOURCES/ 目录中。
  2. 未填充的 SPEC 文件 ~/rpmbuild/SPECS/.spec 已被 rpmdev-newspec 创建。

步骤

  1. 打开 rpmdev-newspec 程序提供的 ~/rpmbuild/SPECS/.spec 文件的输出模板:

  2. 填充 SPEC 文件的第一个部分:

    • 2.1 第一部分包括 rpmdev-newspec 分组在一起的这些指令:
      • Name: Name 已指定为 rpmdev-newspec 的参数。
      • Version: 将 Version 设置为与源代码的上游版本匹配。
      • Release: Release 自动设置为 1%{?dist},它最初是 1。每当更新软件包而上游发行版本的 Version 没有更改时(例如当包含补丁时),增加初始的值。当出现新的上游版本时,Release 被重置为 1。
      • Summary: Summary 是该软件的简短说明。
    • 2.2 完成后SPEC文件长这样
      1
      2
      3
      4
      Name:           bello
      Version: 0.1
      Release: 1%{?dist}
      Summary: Hello World example implemented in bash script
  3. 填充 License、URL 和 Source0 指令:

    • License 字段是与上游发行版本中源代码关联的软件许可证。如何在 SPEC 文件中标记 License 的具体格式将有所不同,具体取决于您遵循的基于哪个基于 RPM 的 Linux 发行版准则。例如,您可以使用 GPLv3+。
    • URL 字段提供上游软件网站的 URL。为实现一致性,请使用 RPM 宏变量 %{name} ,并使用 https://example.com/%{name}。
    • Source0 字段提供上游软件源代码的 URL。它应直接链接到被打包的特定版本。请注意,本文档中给出的示例 URL 包括可在以后更改的硬编码值。同样,发行版本也可以更改。要简化这些潜在的更改,请使用 %{name} 和 %{version} 宏。通过使用以上,您仅需要在 SPEC 文件中更新一个字段。
    • 完成后SPEC文件长这样
      1
      2
      3
      License:        GPLv3+
      URL: https://example.com/%{name}
      Source0: https://example.com/%{name}/release/%{name}-%{version}.tar.gz
  4. 填充 BuildRequires、Requires 和 BuildArch 指令:

    • BuildRequires: 指定软件包的构建时依赖项。
    • Requires: 指定软件包的运行时依赖项。
    • BuildArch: 这是使用没有原生编译扩展的解释编程语言编写的软件。因此,使用 noarch 值添加 BuildArch 指令。这告知 RPM 不需要将这个软件包绑定到构建它的处理器架构。
    • 完成后SPEC文件长这样
      1
      2
      Requires:       bash
      BuildArch: noarch
  5. 填充 %description、%prep、%build、%install、%files 和 %license 指令:这些指令可被视为部分标题,因为它们是可以定义多行、多结构或脚本化任务的指令。

    • %description 是一个比 Summary 更长的软件的信息,其中包含一个或多个段落。
    • %prep 部分指定如何准备构建环境。这通常涉及对源代码的压缩存档、补丁应用程序以及可能解析源代码中提供的信息的扩展,以便在 SPEC 文件以后的部分中使用。在本节中,您可以使用内置的 %setup -q 宏。
    • %build 部分指定如何构建软件。
    • %install 部分包含在 BUILDROOT 目录中构建软件后如何安装软件的 rpmbuild 指令。该目录是一个空的 chroot 基础目录,类似于最终用户的根目录。您可以在此处创建包含安装文件的目录。要创建这样的目录,您可以使用 RPM 宏,而无需硬编码路径。
    • %files 部分指定此 RPM 提供的文件列表及其终端用户系统的完整路径位置。
    • 在本节中,您可以使用内置宏来指示各种文件的角色。这对于使用 command[]rpm 命令查询软件包文件清单元数据很有用。例如,要表示 LICENSE 文件是软件许可证文件,请使用 %license 宏。
  6. 最后一个部分( %changelog )是软件包的每个 Version-Release 的带有日期戳的条目列表。它们记录打包更改,而非软件更改。打包更改示例:添加补丁,更改 %build 部分中的构建流程。

    • 在第一行使用此格式:以一个 * 字符开头,后跟 Day-of-Week Month Day Year Name Surname - Version-Release
    • 使用以下格式进行实际更改条目:
      • 每个更改条目都可以包含多个项目,每个代表一个改变。
      • 每个项目在新行中开始。
      • 每个项目以 - 字符开头。

至此,您已为所需的程序编写了整个 SPEC 文件。

3. 完整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
Name:           bello
Version: 0.1
Release: 1%{?dist}
Summary: Hello World example implemented in bash script

License: GPLv3+
URL: https://www.example.com/%{name}
Source0: https://www.example.com/%{name}/releases/%{name}-%{version}.tar.gz

Requires: bash

BuildArch: noarch

%description
The long-tail description for our Hello World Example implemented in
bash script.

%prep
%setup -q

%build

%install

mkdir -p %{buildroot}/%{_bindir}

install -m 0755 %{name} %{buildroot}%{_bindir}/%{name}

%files
%license LICENSE
%{_bindir}/%{name}

%changelog
* Tue May 31 2016 Adam Miller <maxamillion@fedoraproject.org> - 0.1-1
- First bello package
- Example second item in the changelog for version-release 0.1-1

4. 构建RPM包

  1. 使用指定的 SPEC 文件运行 rpmbuild 命令:

    1
    2
    # 使用 SPECfile 替换 SPECFILE。-bs 选项代表构建源。
    $ rpmbuild -bs SPECFILE
  2. 从源 RPM(SRPM)重建二进制 RPM。

    1
    2
    $ rpmbuild --rebuild ~/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
    [output truncated]
  3. 从SPEC 文件构建二进制 RPM

    1
    2
    # 使用 bb 选项运行 rpmbuild 命令:
    $ rpmbuild -bb ~/rpmbuild/SPECS/bello.spec
  4. 从源 RPM 构建 RPM

    1
    2
    # 使用以下选项之一运行 rpmbuild 命令,并使用指定的源软件包:
    $ rpmbuild {-ra|-rb|-rp|-rc|-ri|-rl|-rs} [rpmbuild-options] SOURCEPACKAGE
  5. 常用打包命令

    1
    2
    3
    4
    # 常用打包命令
    $ rpmdev-setuptree
    $ rpmbuild -ba hello-world.spec
    # 命令 rpmdev-setuptree 会创建几个工作目录。由于这些目录永久存储在 $HOME 中,因此不需要再次使用此命令

5. 检查 RPM 健全性

rpmlint 工具可以检查二进制 RPM、源 RPM (SRPMs)和 SPEC 文件,因此它对打包的所有阶段都很有用,如下例所示。

  1. 在适用于 bello 的 SPEC 文件中运行 rpmlint 命令的输出

    1
    2
    3
    4
    $ rpmlint bello.spec
    bello.spec: W: invalid-url Source0: https://www.example.com/bello/releases/bello-0.1.tar.gz HTTP Error 404: Not Found
    0 packages and 1 specfiles checked; 0 errors, 1 warnings.
    # 对于 bello.spec,只有一个警告,表示 Source0 指令中列出的 URL 不可访问。这是正常的,因为指定的 example.com URL 不存在。假设我们预期此 URL 在未来工作,我们可以忽略这个警告。
  2. 在 SRPM forllo 上运行 rpmlint 命令的输出

    1
    2
    3
    4
    5
    $ rpmlint ~/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
    bello.src: W: invalid-url URL: https://www.example.com/bello HTTP Error 404: Not Found
    bello.src: W: invalid-url Source0: https://www.example.com/bello/releases/bello-0.1.tar.gz HTTP Error 404: Not Found
    1 packages and 0 specfiles checked; 0 errors, 2 warnings.
    # 对于 bello SRPM,有一个新的警告,表示 URL 指令中指定的 URL 不可访问。假设链接将在以后工作,我们可以忽略此警告。
  3. 在 bello 的二进制 RPM 上运行 rpmlint 命令的输出

    1
    2
    3
    4
    5
    6
    $ rpmlint ~/rpmbuild/RPMS/noarch/bello-0.1-1.el8.noarch.rpm
    bello.noarch: W: invalid-url URL: https://www.example.com/bello HTTP Error 404: Not Found
    bello.noarch: W: no-documentation
    bello.noarch: W: no-manual-page-for-binary bello
    1 packages and 0 specfiles checked; 0 errors, 3 warnings.
    # no-documentation 和 no-manual-page-for-binary 警告表示 RPM 没有文档或手册页,因为我们没有提供任何文档或手册页。除以上警告外,RPM 会传递 rpmlint 检查。

参考