打包和分发软件


Red Hat Enterprise Linux 10

使用 RPM 软件包管理系统打包软件

Red Hat Customer Content Services

摘要

使用 RPM 软件包管理器将软件打包到 RPM 软件包中。准备打包的源代码、打包软件并调查高级打包场景,如将 Python 项目或 RubyGems 软件包打包到 RPM 软件包中。

对红帽文档提供反馈

我们感谢您对我们文档的反馈。让我们了解如何改进它。

通过 Jira 提交反馈(需要帐户)

  1. 登录到 Jira 网站。
  2. 在顶部导航栏中点 Create
  3. Summary 字段中输入描述性标题。
  4. Description 字段中输入您对改进的建议。包括文档相关部分的链接。
  5. 点对话框底部的 Create

第 1 章 RPM 简介

RPM Package Manager (RPM)是一个运行在 Red Hat Enterprise Linux (RHEL)、CentOS 和 Fedora 上的软件包管理系统。您可以使用 RPM 为任何这些操作系统所创建的软件进行分发、管理和更新。

与在传统存档文件中分发软件相比,RPM 软件包管理系统有以下优点:

  • RPM 以可独立安装、更新或删除软件包的形式管理软件,从而更轻松地维护操作系统。
  • RPM 简化了软件的分发,因为 RPM 软件包是独立的二进制文件,类似于压缩的存档。这些软件包是为特定的操作系统和硬件架构而构建的。RPM 包含诸如这样的文件,如在软件包安装时放到文件系统上适当路径下的已编译的可执行文件和库。

使用 RPM,您可以执行以下任务:

  • 安装、升级和删除打包的软件。
  • 查询关于打包的软件的详细信息。
  • 验证打包的软件的完整性。
  • 从软件源构建您自己的软件包,并完成构建说明。
  • 使用 GNU Privacy Guard (GPG)工具对您的软件包进行数字签名。
  • 在 DNF 存储库中发布您的软件包。

在 Red Hat Enterprise Linux 中,RPM 完全集成到更高级别的软件包管理软件中,如 DNF 或 PackageKit。虽然 RPM 提供了自己的命令行界面,但大多数用户只需要通过这个软件与 RPM 进行交互。但是,在构建 RPM 软件包时,您必须使用 RPM 工具,如 rpmbuild (8)

1.1. RPM 软件包

RPM 软件包由用于安装和删除这些文件的文件和元数据的存档组成。具体来说,RPM 软件包包含以下部分:

  • GPG 签名

    GPG 签名用于验证软件包的完整性。

  • 标头(软件包元数据)

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

  • payload

    有效负载是一个 cpio 归档,其中包含要安装到系统的文件。

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

  • 源 RPM(SRPM)

    SRPM 包含源代码和一个 spec 文件,该文件描述了如何将源代码构建为二进制 RPM。另外,SRPM 可以包含源代码的补丁。

  • 二进制 RPM

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

1.2. 列出 RPM 打包工具

除了用于构建软件包的 rpmbuild (8) 程序外,RPM 还提供其他工具,以便更轻松地创建软件包。您可以在 rpmdevtools 软件包中找到这些程序。

先决条件

  • rpmdevtools 软件包已安装:

    # dnf install rpmdevtools
    Copy to Clipboard Toggle word wrap

步骤

  • 使用以下方法之一列出 RPM 打包工具:

    • 要列出 rpmdevtools 软件包提供的某些工具及其简短描述,请输入:

      $ rpm -qi rpmdevtools
      Copy to Clipboard Toggle word wrap
    • 要列出所有工具,请输入:

      $ rpm -ql rpmdevtools | grep ^/usr/bin
      Copy to Clipboard Toggle word wrap

第 2 章 为 RPM 打包创建软件

要为 RPM 打包准备软件,您必须了解什么是源代码以及如何创建软件。

2.1. 什么是源代码

源代码是人类可读的计算机指令,其描述了如何执行计算。源代码是使用编程语言表达的。

以下三种不同编程语言编写的 Hello World 程序版本涵盖了主要的 RPM Package Manager 用例:

  • 使用 Bash 编写的 hello World

    bello 项目使用 Bash 实现 Hello World。实现仅包含 bello shell 脚本。此程序的目的是在命令行上输出 Hello World

    bello 文件包含以下内容:

    #!/bin/bash
    
    printf "Hello World\n"
    Copy to Clipboard Toggle word wrap
  • 使用 Python 编写的 hello World

    pello 项目使用 Python 实现 Hello World。该实现仅包含 pello.py 程序。程序的目的是在命令行中输出 Hello World

    pello.py 文件包含以下内容:

    #!/usr/bin/python3
    
    print("Hello World")
    Copy to Clipboard Toggle word wrap
  • 使用 C 编写的 hello World

    cello 项目在 C 中实现 Hello World。实现仅包含 cello.cMakefile 文件。因此,除了 LICENSE 文件外,生成的 tar.gz 存档还有两个文件。程序的目的是在命令行中输出 Hello World

    cello.c 文件包含以下内容:

    #include <stdio.h>
    
    int main(void) {
        printf("Hello World\n");
        return 0;
    }
    Copy to Clipboard Toggle word wrap
注意

对于 Hello World 程序的每个版本,打包过程会是不同的。

2.2. 创建软件的方法

您可以使用以下方法之一将人类可读的源代码转换为机器码:

  • 原生编译软件。
  • 使用语言解释器或语言虚拟机解释软件。您可以使用原始解释或字节编译软件。

2.2.1. 原生编译的软件

原生编译的软件是使用编程语言编写的软件,使用生成的二进制可执行文件编译到机器代码中。原生编译的软件是独立软件。

注意

原生编译的 RPM 软件包是特定于架构的。

如果您在使用 64 位(x86_64) AMD 或 Intel 处理器的计算机上编译此类软件,则它不能在 32 位(x86) AMD 或 Intel 处理器上运行。生成的软件包在其名称中指定了架构。

2.2.2. 解释的软件

一些编程语言,如 Bash 或 Python 不会编译成机器代码。相反,语言解释器或语言虚拟机会逐步执行程序的源代码步骤,而无需之前进行转换。

注意

完全使用解释编程语言编写的软件不是特定于架构的。因此,生成的 RPM 软件包在其名称中有 noarch 字符串。

您可以使用解释语言编写的原始解释或字节编译软件:

  • 原始解释的软件

    您不需要编译这类软件。原始解释的软件由解释器直接执行。

  • 字节编译的软件

    您必须首先将这类软件编译成字节码,然后由语言虚拟机执行。

    注意

    有些字节编译的语言可以是原始解释的或字节编译的。

请注意,对于这两个软件类型,使用 RPM 构建和打包软件的方式是不同的。

2.3. 从源构建软件

在软件构建过程中,源代码被转换为可以使用 RPM 打包的软件工件。

2.3.1. 从原生编译的代码构建软件

您可以使用以下方法之一将使用编译语言编写的软件构建成可执行文件:

  • 手动构建
  • 自动化构建
2.3.1.1. 手动构建一个 C 程序示例

您可以使用手动构建来构建使用编译语言编写的软件。

使用 C 编写的 Hello World 程序示例(cello.c)包含以下内容:

#include <stdio.h>

int main(void) {
    printf("Hello World\n");
    return 0;
}
Copy to Clipboard Toggle word wrap

流程

  1. 从 GNU Compiler Collection 调用 C 编译器,来将源代码编译成二进制:

    $ gcc -g -o cello cello.c
    Copy to Clipboard Toggle word wrap
  2. 运行生成的二进制文件 cello

    $ ./cello
    Hello World
    Copy to Clipboard Toggle word wrap
2.3.1.2. 为示例 C 程序设置自动构建

大规模软件通常使用自动构建。您可以通过创建 Makefile 文件,然后运行 GNU make 工具来设置自动构建。

流程

  1. 在与 cello.c 相同的目录中,创建包含以下内容的 Makefile 文件:

    cello:
    	gcc -g -o cello cello.c
    clean:
    	rm cello
    Copy to Clipboard Toggle word wrap

    请注意,cello:clean: 下的行必须以制表符(tab)开头。

  2. 构建软件:

    $ make
    make: 'cello' is up to date.
    Copy to Clipboard Toggle word wrap
  3. 因为构建已在当前目录中可用,所以请输入 make clean 命令,然后再次输入 make 命令:

    $ make clean
    rm cello
    
    $ make
    gcc -g -o cello cello.c
    Copy to Clipboard Toggle word wrap

    请注意,此时尝试再次构建程序无效,因为 GNU make 系统检测到现有的二进制文件:

    $ make
    make: 'cello' is up to date.
    Copy to Clipboard Toggle word wrap
  4. 运行程序:

    $ ./cello
    Hello World
    Copy to Clipboard Toggle word wrap

2.3.2. 解释源代码

您可以使用以下方法之一将解释编程语言编写的源代码转换为机器码:

  • 字节编译

    字节软件的流程因以下因素而异:

    • 编程语言
    • 语言虚拟机
    • 与该语言一起使用的工具和流程

      注意

      您可以对例如用 Python 编写的软件进行字节编译。用于分发的 Python 软件通常是字节编译的,但这不是以本文档中介绍的方法。上述流程目的不是为了符合社区标准,而是为了简单。有关实际工作环境中的 Python 指南,请参阅打包和发布

    您还可以原始解释 Python 源代码。但是,字节编译的版本速度更快。因此,RPM 软件包程序更喜欢将字节编译的版本打包,来分发给最终用户。

  • 原始解释

    使用 shell 脚本语言(如 Bash)编写的软件始终由原始解释执行。

2.3.2.1. 字节编译一个 Python 程序示例

通过对 Python 源代码选择字节编译而不是原始解释,您可以创建更快的软件。

使用 Python 编程语言编写的 Hello World 程序示例(pello.py)具有以下内容:

print("Hello World")
Copy to Clipboard Toggle word wrap

流程

  1. 字节编译 pello.py 文件:

    $ python -m compileall pello.py
    Copy to Clipboard Toggle word wrap
  2. 验证是否已创建了文件的字节编译版本:

    $ ls __pycache__
    pello.cpython-311.pyc
    Copy to Clipboard Toggle word wrap

    请注意,输出中的软件包版本可能会因安装的 Python 版本而有所不同。

  3. pello.py 中运行程序:

    $ python pello.py
    Hello World
    Copy to Clipboard Toggle word wrap
2.3.2.2. 原始解析一个 Bash 程序示例

使用 Bash shell 内置语言编写的 Hello World 程序示例(bello)具有如下内容:

#!/bin/bash

printf "Hello World\n"
Copy to Clipboard Toggle word wrap
注意

bello 文件顶部的 shebang (#!)符号不是编程语言源代码的一部分。

使用 shebang 将文本文件转换为可执行文件。系统程序加载程序解析包含 shebang 的行,以获取二进制可执行文件的路径,其然后用作编程语言解释器。

流程

  1. 使源代码文件可执行:

    $ chmod +x bello
    Copy to Clipboard Toggle word wrap
  2. 运行创建的文件:

    $ ./bello
    Hello World
    Copy to Clipboard Toggle word wrap

第 3 章 为 RPM 打包准备软件

要准备一个使用 RPM 进行打包的软件,您可以首先给软件打补丁,为其创建一个 LICENSE 文件,并将它归档为 tar 包。

3.1. 修复软件

在打包软件时,您可能需要对原始源代码进行某些更改,如修复 bug 或更改配置文件。在 RPM 打包中,您可以将原始源代码保持不变,并对其应用补丁。

补丁是更新源代码文件的一段文本。补丁具有 diff 格式,因为它代表文本的两个版本之间的区别。您可以使用 diff 工具创建一个补丁,然后使用 patch 工具将补丁应用到源代码。

注意

软件开发人员通常使用版本控制系统(如 Git)来管理其代码库。这些工具提供了自己的创建区别或给软件打补丁的方法。

3.1.1. 为 C 程序示例创建一个补丁文件

您可以使用 diff 工具从原始源代码创建一个补丁。例如,要修补使用 C 编写的 Hello world 程序(cello.c),请完成以下步骤。

先决条件

  • 您在系统上安装了 diff 工具:

    # dnf install diffutils
    Copy to Clipboard Toggle word wrap

流程

  1. 备份原始源代码:

    $ cp -p cello.c cello.c.orig
    Copy to Clipboard Toggle word wrap

    -p 选项保留模式、所有权和时间戳。

  2. 根据需要修改 cello.c

    #include <stdio.h>
    
    int main(void) {
        printf("Hello World from my very first patch!\n");
        return 0;
    }
    Copy to Clipboard Toggle word wrap
  3. 生成补丁:

    $ diff -Naur cello.c.orig cello.c
    --- cello.c.orig        2016-05-26 17:21:30.478523360 -0500
    + cello.c     2016-05-27 14:53:20.668588245 -0500
    @@ -1,6 +1,6 @@
     #include<stdio.h>
    
     int main(void){
    -    printf("Hello World!\n");
    +    printf("Hello World from my very first patch!\n");
         return 0;
     }
    \ No newline at end of file
    Copy to Clipboard Toggle word wrap

    + 开头的行替换以 - 开头的行。

    注意

    建议使用 diff 命令的 Naur 选项,因为它适合大多数用例:

    • -N (--new-file)

      -N 选项将缺少的文件处理为空文件。

    • -a (--text)

      -a 选项将所有文件视为文本。因此,diff 工具不会忽略它归类为二进制文件的文件。

    • -u (-U NUM--unified[=NUM])

      -u 选项以统一上下文的输出 NUM (默认 3)行的形式返回输出。这是一个在补丁文件中常用的紧凑的,易读的格式。

    • -r (--recursive)

      -r 选项递归比较 diff 工具找到的任何子目录。

    但请注意,在这种特殊情况下,只需要 -u 选项。

  4. 将补丁保存到文件中:

    $ diff -Naur cello.c.orig cello.c > cello.patch
    Copy to Clipboard Toggle word wrap
  5. 恢复原始 cello.c

    $ mv cello.c.orig cello.c
    Copy to Clipboard Toggle word wrap
    重要

    您必须保留原始 cello.c,因为 RPM 软件包管理器在构建 RPM 软件包时使用原始文件,而不是修改后的文件。如需更多信息,请参阅 使用 spec 文件

3.1.2. 给 C 程序示例打补丁

要对软件应用代码补丁,您可以使用 patch 工具。

先决条件

  • 您在系统上安装了 patch 工具:

    # dnf install patch
    Copy to Clipboard Toggle word wrap
  • 您从原始源代码创建了一个补丁。具体说明请参阅 为 C 程序示例创建一个补丁文件

流程

以下步骤对 cello.c 文件应用之前创建的 cello.patch 文件。

  1. 将补丁文件重定向到 patch 命令:

    $ patch < cello.patch
    patching file cello.c
    Copy to Clipboard Toggle word wrap
  2. 检查 cello.c 的内容现在是否反映了所需的更改:

    $ cat cello.c
    #include<stdio.h>
    
    int main(void){
        printf("Hello World from my very first patch!\n");
        return 1;
    }
    Copy to Clipboard Toggle word wrap

验证

  1. 构建打了补丁的 cello.c 程序:

    $ make
    gcc -g -o cello cello.c
    Copy to Clipboard Toggle word wrap
  2. 运行构建的 cello.c 程序:

    $ ./cello
    Hello World from my very first patch!
    Copy to Clipboard Toggle word wrap

3.2. 创建一个 LICENSE 文件

建议您使用软件许可证分发软件。

软件许可证文件告知用户他们可以使用源代码做什么和不能做什么。没有源代码许可证意味着您保留此代码的所有权限,任何人都不能从源代码复制、分发或创建衍生工作。

流程

  • 使用所需许可证声明创建 LICENSE 文件:

    $ vim LICENSE
    Copy to Clipboard Toggle word wrap

    例 3.1. GPLv3 LICENSE 文件文本示例

    $ cat /tmp/LICENSE
    This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
    
    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
    Copy to Clipboard Toggle word wrap

3.3. 为分发创建一个源代码存档

归档文件是一个带有 .tar.gz.tgz 后缀的文件。将源代码放入存档是一种发布软件以便以后打包分发的常见方法。

3.3.1. 为 Bash 程序示例创建一个源代码存档

bello 项目是一个用 Bash 写的 Hello World 文件。

以下示例仅包含 bello shell 脚本。因此,生成的 tar.gz 存档除了 LICENSE 文件外只有一个文件。

注意

patch 文件不在存档中随程序一起分发。构建 RPM 时,RPM 软件包管理器应用补丁。补丁将与 tar.gz 存档一起放在 ~/rpmbuild/SOURCES/ 目录中。

先决条件

  • 假定使用 bello 程序的 0.1 版本。
  • 您创建了一个 LICENSE 文件。具体说明,请参阅 创建一个 LICENSE 文件

流程

  1. 将所有需要的文件移到一个目录中:

    $ mkdir bello-0.1
    
    $ mv ~/bello bello-0.1/
    
    $ mv LICENSE bello-0.1/
    Copy to Clipboard Toggle word wrap
  2. 为分发创建存档:

    $ tar -cvzf bello-0.1.tar.gz bello-0.1
    bello-0.1/
    bello-0.1/LICENSE
    bello-0.1/bello
    Copy to Clipboard Toggle word wrap
  3. 将创建的存档移到 ~/rpmbuild/SOURCES/ 目录中,这是 rpmbuild 命令存储用于构建软件包的文件的默认目录:

    $ mv bello-0.1.tar.gz ~/rpmbuild/SOURCES/
    Copy to Clipboard Toggle word wrap

3.3.2. 为 Python 程序示例创建一个源代码存档

pello 项目是一个用 Python 写的 Hello World 文件。

以下示例仅包含 pello.py 程序。因此,生成的 tar.gz 存档除了 LICENSE 文件外只有一个文件。

注意

patch 文件不在存档中随程序一起分发。构建 RPM 时,RPM 软件包管理器应用补丁。补丁将与 tar.gz 存档一起放在 ~/rpmbuild/SOURCES/ 目录中。

先决条件

  • 假定使用 pello 程序的 0.1.1 版本。
  • 您创建了一个 LICENSE 文件。具体说明,请参阅 创建一个 LICENSE 文件

流程

  1. 将所有需要的文件移到一个目录中:

    $ mkdir pello-0.1.1
    
    $ mv pello.py pello-0.1.1/
    
    $ mv LICENSE pello-0.1.1/
    Copy to Clipboard Toggle word wrap
  2. 为分发创建存档:

    $ tar -cvzf pello-0.1.1.tar.gz pello-0.1.1
    pello-0.1.1/
    pello-0.1.1/LICENSE
    pello-0.1.1/pello.py
    Copy to Clipboard Toggle word wrap
  3. 将创建的存档移到 ~/rpmbuild/SOURCES/ 目录中,这是 rpmbuild 命令存储用于构建软件包的文件的默认目录:

    $ mv pello-0.1.1.tar.gz ~/rpmbuild/SOURCES/
    Copy to Clipboard Toggle word wrap

3.3.3. 为 C 程序示例创建一个源代码存档

cello 项目是 C 中的 Hello World 文件。

以下示例仅包含 cello.cMakefile 文件。因此,生成的 tar.gz 存档除了 LICENSE 文件有两个文件。

注意

patch 文件不在存档中随程序一起分发。构建 RPM 时,RPM 软件包管理器应用补丁。补丁将与 tar.gz 存档一起放在 ~/rpmbuild/SOURCES/ 目录中。

先决条件

  • 假定使用 cello 程序的 1.0 版本。
  • 您创建了一个 LICENSE 文件。具体说明,请参阅 创建一个 LICENSE 文件

流程

  1. 将所有需要的文件移到一个目录中:

    $ mkdir cello-1.0
    
    $ mv cello.c cello-1.0/
    
    $ mv Makefile cello-1.0/
    
    $ mv LICENSE cello-1.0/
    Copy to Clipboard Toggle word wrap
  2. 为分发创建存档:

    $ tar -cvzf cello-1.0.tar.gz cello-1.0
    cello-1.0/
    cello-1.0/Makefile
    cello-1.0/cello.c
    cello-1.0/LICENSE
    Copy to Clipboard Toggle word wrap
  3. 将创建的存档移到 ~/rpmbuild/SOURCES/ 目录中,这是 rpmbuild 命令存储用于构建软件包的文件的默认目录:

    $ mv cello-1.0.tar.gz ~/rpmbuild/SOURCES/
    Copy to Clipboard Toggle word wrap

第 4 章 打包软件

在以下部分中,了解使用 RPM 软件包管理器的打包过程的基础知识。

4.1. 设置 RPM 打包工作区

要构建 RPM 软件包,您必须首先创建一个特殊的工作区,它由用于不同打包目的的目录组成。

4.1.1. 配置 RPM 打包工作区

要配置 RPM 打包工作区,您可以使用 rpmdev-setuptree 工具设置一个目录布局。

先决条件

  • 您已安装了 rpmdevtools 软件包,它提供打包 RPM 的工具:

    # dnf install rpmdevtools
    Copy to Clipboard Toggle word wrap

流程

  • 运行 rpmdev-setuptree 程序:

    $ rpmdev-setuptree
    
    $ tree ~/rpmbuild/
    /home/user/rpmbuild/
    |-- BUILD
    |-- RPMS
    |-- SOURCES
    |-- SPECS
    `-- SRPMS
    
    5 directories, 0 files
    Copy to Clipboard Toggle word wrap

4.1.2. RPM 打包工作区目录

以下是使用 rpmdev-setuptree 工具创建的 RPM 打包工作区目录:

Expand
表 4.1. RPM 打包工作区目录
目录用途

BUILD

包含从 SOURCES 目录中的源文件编译的构建工件。

RPMS

二进制 RPM 在不同架构的子目录中的 RPMS 目录下创建。例如,在 x86_64noarch 子目录中。

SOURCES

包含压缩的源代码存档和补丁。然后,rpmbuild 命令在此目录中搜索这些存档和补丁。

SPECS

包含由打包程序创建的 spec 文件。然后使用这些文件构建软件包。

SRPMS

当您使用 rpmbuild 命令构建 SRPM 而不是二进制 RPM 时,会在此目录下创建生成的 SRPM。

4.2. 关于 spec 文件

spec 文件是一个包含 rpmbuild 工具用来构建 RPM 软件包的指令的文件。此文件通过在一系列部分中定义指令,为构建系统提供必要的信息。这些部分在 spec 文件的 PreambleBody 部分中定义:

  • Preamble 部分包含一系列在 Body 部分中使用的元数据项。
  • Body 部分代表说明的主要部分。

4.2.1. Preamble 项

以下是您一些可以在 RPM spec 文件的 Preamble 部分中使用的指令。

Expand
表 4.2. Preamble 部分指令
指令定义

Name

软件包的基本名称必须与 spec 文件名匹配。

Version

软件的上游版本号。

发布

软件包版本发布的次数。

将初始值设置为 1%{?dist},并随着软件包的每次新发布而增加该值。当构建软件的新 版本 时,重置为 1

Summary

软件包的一行简短摘要。

License

被打包的软件的许可证。

如何在 spec 文件中标记 License 的确切格式随您遵循的基于 RPM 的 Linux 发行版准则(例如 GPLv3+)而异。

URL

有关软件的更多信息的完整 URL,例如,打包软件的上游项目网站。

Source

到压缩的未打补丁的上游源代码的存档的路径或 URL。此链接必须指向存档的可访问且可靠的存储,例如上游页面,不是打包程序的本地存储。

您可以在指令名称的末尾使用或不使用号码应用 Source 指令。如果没有给定号码,则会在内部将号码分配给条目。您也可以明确提供号码,例如 Source0Source1Source2Source3 等。

Patch

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

您可以在指令名称的末尾使用或不使用号码应用 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

如果软件的一部分无法在特定的处理器架构上运行,您可以在 ExcludeArch 指令中排除此架构。

Conflicts

不必安装在系统上,以便您的软件在安装时可以正常工作的用逗号或空格分开的软件包的列表。可以有多个 Conflicts 条目,每个条目在 spec 文件中各占一行。

Obsoletes

Obsoletes 指令根据以下因素更改更新的工作方式:

  • 如果您直接在命令行上使用 rpm 命令,它会删除与正在安装的软件包的过时版本匹配的所有软件包,或者通过更新或依赖项解决程序执行更新。
  • 如果您使用更新或依赖项解决程序(DNF),则包含匹配 Obsoletes: 的软件包会被作为更新添加,并替换匹配的软件包。

Provides

如果您向软件包中添加了 Provides 指令,则这个软件包可以通过依赖项,而不是其名称引用。

NameVersionRelease (NVR)指令以 名称-版本-发行版本 格式组成 RPM 软件包的文件名。

您可以使用 rpm 命令查询 RPM 数据库来显示特定软件包的 NVR 信息,例如:

# rpm -q bash
bash-4.4.19-7.el8.x86_64
Copy to Clipboard Toggle word wrap

在这里,bash 是软件包名称,4.4.19 是版本,7el8 是发行版本。x86_64 标记是软件包架构。与 NVR 不同,架构标记不在 RPM 打包程序的直接控制之下,而是由 rpmbuild 构建环境定义。这种情况的例外是独立于架构的 noarch 软件包。

4.2.2. 正文项

以下是 RPM spec 文件的 Body 部分中使用的项:

Expand
表 4.3. Body 部分项
指令定义

%description

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

%prep

准备进行构建的软件的命令或一系列命令,例如,在 Source 指令中解压缩存档。%prep 指令可以包含 shell 脚本。

%build

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

%install

软件构建后,rpmbuild 工具用来将软件安装到 BUILDROOT 目录的命令或一系列命令。这些命令将所需的构建工件从 %_builddir 目录(构建发生的地方)复制到包含要打包的文件的目录结构的 %buildroot 目录中。这包括将文件从 ~/rpmbuild/BUILD 复制到 ~/rpmbuild/BUILDROOT,并在 ~/rpmbuild/BUILDROOT 中创建必要的目录。

%install 目录是一个空的 chroot 基础目录,类似于最终用户的 目录。您可以在此处创建包含安装文件的目录。要创建这样的目录,您可以使用 RPM 宏,而无需硬编码路径。

请注意,%install 仅在创建软件包时运行,而不是在安装它时运行。如需更多信息,请参阅 使用 spec 文件

%check

用于测试软件(如单元测试)的命令或一系列命令。

%files

RPM 软件包提供的要安装到用户的系统中的文件的列表,以及系统上它们的完整路径位置。

在构建期间,如果 %buildroot 目录中有文件没有在 %files 中列出,您将收到一条有关可能的未打包文件的警告。

%files 部分中,您可以使用内置宏指示各种文件的作用。这可用于使用 rpm 命令查询软件包文件清单元数据。例如,要指示 LICENSE 文件是一个软件许可证文件,请使用 %license 宏。

%changelog

在不同的 VersionRelease 构建之间软件包所发生的更改的记录。这些更改包括软件包的每个 Version-Release 的日期戳条目的列表。这些条目会记录打包更改,而不是软件更改,例如在 %build 部分中添加补丁或更改构建流程。

4.2.3. 高级 items

spec 文件可以包含高级项目,如 Scriptlets 或 Triggers。Scriptlets 和 Triggers 在最终用户系统上的安装过程中的不同点生效,而不是在构建过程中生效。

4.3. BuildRoots

在 RPM 打包的上下文中,buildroot 是一个 chroot 环境。构建工件通过使用与最终用户系统中将来层次结构相同的文件系统层次结构放在此,buildroot 充当根目录。构建工件的放置必须遵循最终用户系统的文件系统层次结构标准。

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

注意

rpmbuild 程序有自己的默认值。覆盖这些默认值可能导致某些问题。因此,请避免定义您自己的 buildroot 宏的值。改为使用默认的 %{buildroot} 宏。

4.4. RPM 宏

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

例如,您只能在 %{version} 宏中定义打包软件的 Version 一次,并在整个 spec 文件中使用此宏。每次出现时都会自动替换为您在宏中定义的 Version

注意

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

$ rpm --eval %{MACRO}
Copy to Clipboard Toggle word wrap

例如,要评估 %{_bindir}%{_libexecdir} 宏,请输入:

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

$ rpm --eval %{_libexecdir}
/usr/libexec
Copy to Clipboard Toggle word wrap

4.5. 使用 spec 文件

要打包新软件,您必须创建一个 spec 文件。您可以使用以下方法之一创建 spec 文件:

  • 从头开始手动编写新的 spec 文件。
  • 使用 rpmdev-newspec 工具。这个工具会创建一个未填充的 spec 文件,您可以在其中填充必要的指令和字段。
注意

某些以程序员为中心的文本编辑器,预先使用自己的 spec 模板填充一个新的 spec 文件。rpmdev-newspec 工具提供了一个与编辑器无关的方法。

您可以使用 rpmdev-newspec 工具为 Hello World! 程序的三个实现创建一个 spec 文件。

先决条件

流程

  1. 进到 ~/rpmbuild/SPECS 目录:

    $ cd ~/rpmbuild/SPECS
    Copy to Clipboard Toggle word wrap
  2. Hello World! 程序的三个实现创建一个 spec 文件:

    $ 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.
    Copy to Clipboard Toggle word wrap

    ~/rpmbuild/SPECS/ 目录现在包含三个 spec 文件,名为 bello.speccello.specpello.spec

  3. 检查创建的文件。

    文件中的指令代表 About spec files 中描述的指令。在以下部分中,您将在 rpmdev-newspec 的输出文件中填充特定的部分。

4.5.2. 修改原始 spec 文件

rpmdev-newspec 工具生成的 spec 文件的原始输出代表一个您必须修改的模板,以便为 rpmbuild 工具提供必要的指令。然后,rpmbuild 使用这些指令来构建 RPM 软件包。

先决条件

流程

  1. 打开 rpmdev-newspec 工具提供的 ~/rpmbuild/SPECS/<name>.spec 文件。
  2. 填充 spec 文件 Preamble 部分的以下指令:

    Name
    Name 已被指定为 rpmdev-newspec 的参数。
    Version
    Version 设置为与源代码的上游版本匹配。
    发布
    Release 被自动设置为 1%{?dist},它最初是 1
    Summary
    输入软件包的一行解释。
    License
    输入与源代码关联的软件许可证。
    URL
    输入上游软件网站的 URL。为实现一致性,请使用 %{name} RPM 宏变量,并使用 https://example.com/%{name} 格式。
    Source

    输入上游软件源代码的 URL。直接到被打包的软件版本的连接。

    注意

    本文档中的 URL 示例包括可能在以后更改的硬编码的值。同样,发行版本也可以更改。要简化这些潜在的更改,请使用 %{name}%{version} 宏。通过使用这些宏,您只需要更新 spec 文件中的一个字段。

    BuildRequires
    指定软件包的构建时依赖项。
    Requires
    指定软件包的运行时依赖项。
    BuildArch
    指定软件架构。
  3. 填充 spec 文件 Body 部分的以下指令:您可以将这些指令视为部分标题,因为这些指令可以定义要发生的多行、多指令或脚本化任务。

    %description
    输入软件的完整描述。
    %prep
    输入准备构建软件的命令或一系列命令。
    %build
    输入构建软件的命令或一系列命令。
    %install
    输入指示 rpmbuild 命令如何将软件安装到 BUILDROOT 目录中的命令或一系列命令。
    %files
    指定 RPM 软件包提供的要安装在您的系统上的文件的列表。
    %changelog

    输入软件包的每个 Version-Release 的日期戳条目的列表。

    启动带有一个星号(*)字符,后跟 Day-of-Week Month Day Year Name Surname <email> - Version-Release%changelog 部分的第一行

    对于实际更改条目,请遵循这些规则:

    • 每个更改条目都可以包含多个项,每个代表一个更改。
    • 每项都从新行开始。
    • 每项都以连字符(-)字符开头。

现在,您已为所需程序编写了一个完整的 spec 文件。

4.5.3. Bash 程序示例的 spec 文件示例

对于使用 bash 编写的 bello 程序,您可以使用以下示例 spec 文件作为参考。

使用 bash 编写的 bello 程序的 spec 文件示例

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
Copy to Clipboard Toggle word wrap

  • BuildRequires 指令指定软件包的 build-time 依赖项已被删除,因为没有可用于 bello 的构建步骤。Bash 是原始解释编程语言,文件仅安装到其系统上的位置。
  • Requires 指令,其指定软件包的运行时依赖项,仅包含 bash,因为 bello 脚本只需要 bash shell 环境即可执行。
  • 指定如何构建软件的 %build 部分为空,因为不需要构建 bash 脚本。
注意

要安装 bello,您必须创建目标目录,并在其中安装可执行的 bash 脚本文件。因此,您可以在 %install 部分中使用 install 命令。您可以使用 RPM 宏来执行此操作,而无需硬编码路径。

4.5.4. Python 程序示例的 spec 文件示例

您可以对使用 Python 编程语言编写的 pello 程序使用以下示例 spec 文件作为参考。

使用 Python 编写的 pello 程序的 spec 文件示例

Name:           pello
Version:        0.1.1
Release:        1%{?dist}
Summary:        Hello World example implemented in Python

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

BuildRequires:  python
Requires:       python
Requires:       bash

BuildArch:      noarch

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

%prep
%setup -q

%build

python -m compileall %{name}.py

%install

mkdir -p %{buildroot}/%{_bindir}
mkdir -p %{buildroot}/usr/lib/%{name}

cat > %{buildroot}/%{_bindir}/%{name} <<EOF
#!/bin/bash
/usr/bin/python /usr/lib/%{name}/%{name}.pyc
EOF

chmod 0755 %{buildroot}/%{_bindir}/%{name}

install -m 0644 %{name}.py* %{buildroot}/usr/lib/%{name}/

%files
%license LICENSE
%dir /usr/lib/%{name}/
%{_bindir}/%{name}
/usr/lib/%{name}/%{name}.py*

%changelog
* Tue May 31 2016 Adam Miller <maxamillion@fedoraproject.org> - 0.1.1-1
  - First pello package
Copy to Clipboard Toggle word wrap

  • Requires 指令指定软件包的运行时依赖项,其中包括两个软件包:

    • python 软件包需要在运行时执行字节编译的代码。
    • bash 软件包需要执行小入口点脚本。
  • BuildRequires 指令指定软件包的 build-time 依赖项,它只包括 python 软件包。pello 程序需要 python 来执行字节编译构建过程。
  • %build 部分指定如何构建软件,创建脚本的字节编译版本。请注意,在实际打包中,它通常会根据所使用的发行版自动完成。
  • %install 部分对应于这样的事实,即您必须将字节文件安装到系统上的库目录中,以便可以访问它。

spec 文件中内联创建包装程序脚本的示例表明 spec 文件本身是可以写成脚本的。此打包程序脚本使用 此文档 执行 Python 字节编译的代码。

4.5.5. C 程序示例的 spec 文件示例

您可以对使用 C 编程语言编写的 cello 程序使用以下示例 spec 文件作为参考。

使用 C 编写的 cello 程序的 spec 文件示例

Name:           cello
Version:        1.0
Release:        1%{?dist}
Summary:        Hello World example implemented in C

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

Patch0:         cello-output-first-patch.patch

BuildRequires:  gcc
BuildRequires:  make

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

%prep
%setup -q

%patch0

%build
make %{?_smp_mflags}

%install
%make_install

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

%changelog
* Tue May 31 2016 Adam Miller <maxamillion@fedoraproject.org> - 1.0-1
- First cello package
Copy to Clipboard Toggle word wrap

  • BuildRequires 指令,其指定软件包的 build-time 依赖项,包括以下执行编译构建过程所需的软件包:

    • gcc
    • make
  • 本例中省略了该软件包的运行时依赖项 Requires 指令。所有运行时要求都由 rpmbuild 进行处理,而 cello 程序不需要核心 C 标准库之外的任何内容。
  • %build 部分反映了这样一个事实,即此示例中,为 cello 程序编写了 Makefile 文件。因此,您可以使用 GNU make 命令。但是,您必须删除对 %configure 的调用,因为您没有提供配置脚本。

您可以使用 %make_install 宏安装 cello 程序。这是可能是因为 cello 程序的 Makefile 文件可用。

4.6. 构建 RPM

您可以使用 rpmbuild 命令构建 RPM 软件包。使用此命令时,期望某个目录和文件结构,它们与 rpmdev-setuptree 工具设置的结构相同。

不同的用例和所需结果需要不同的参数组合到 rpmbuild 命令。以下是主要用例:

  • 构建源 RPM.
  • 构建二进制 RPM:

    • 从源 RPM 重新构建二进制 RPM 。
    • spec 文件构建二进制 RPM。

4.6.1. 构建源 RPM

构建源 RPM (SRPM)有以下优点:

  • 您可以保留部署到环境中的 RPM 文件的某些 Name-Version-Release 的确切的源。这包括确切的 spec 文件、源代码以及所有相关的补丁。这对于跟踪和调试目的很有用。
  • 您可以在不同的硬件平台或构架上构建二进制 RPM。

先决条件

流程

  1. 导航到 ~/rpmbuild/SPECS/ 指令,其包含创建的 spec 文件:

    $ cd ~/rpmbuild/SPECS/
    Copy to Clipboard Toggle word wrap
  2. 输入 rpmbuild 命令和指定的 spec 文件来构建源 RPM:

    $ rpmbuild -bs <specfile>
    Copy to Clipboard Toggle word wrap

    -bs 选项代表 build source

    例如,要为 bellopellocello 程序构建源 RPM,请输入:

    $ rpmbuild -bs bello.spec
    Wrote: /home/admiller/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
    
    $ rpmbuild -bs pello.spec
    Wrote: /home/admiller/rpmbuild/SRPMS/pello-0.1.2-1.el8.src.rpm
    
    $ rpmbuild -bs cello.spec
    Wrote: /home/admiller/rpmbuild/SRPMS/cello-1.0-1.el8.src.rpm
    Copy to Clipboard Toggle word wrap

验证

  • 验证 rpmbuild/SRPMS 目录是否包含生成的源 RPM。该目录是 rpmbuild 所期望的结构的一部分。

4.6.2. 从源 RPM 重新构建一个二进制 RPM

要从源 RPM (SRPM)重建二进制 RPM,请使用 rpmbuild 命令和 --rebuild 选项。

创建二进制 RPM 时产生的输出非常详细,这对调试非常有用。输出因不同的示例而异,并对应于其 spec 文件。

生成的二进制 RPM 位于以下目录中之一:

  • ~/rpmbuild/RPMS/YOURARCH,其中 YOURARCH 是您的架构。
  • 如果软件包不是特定于架构的,则为 ~/rpmbuild/RPMS/noarch/

先决条件

  • 您已在系统上安装了 rpmbuild 工具:

    # dnf install rpm-build
    Copy to Clipboard Toggle word wrap

流程

  1. 导航到 ~/rpmbuild/SRPMS/ 目录,其包含 SRPM:

    $ cd ~/rpmbuild/SRPMS/
    Copy to Clipboard Toggle word wrap
  2. 从 SRPM 重建二进制 RPM:

    $ rpmbuild --rebuild <srpm>
    Copy to Clipboard Toggle word wrap

    例如,要从其 SRPM 中重新构建 bellopellocello,请输入:

    $ rpmbuild --rebuild bello-0.1-1.el8.src.rpm
    [output truncated]
    
    $ rpmbuild --rebuild pello-0.1.2-1.el8.src.rpm
    [output truncated]
    
    $ rpmbuild --rebuild cello-1.0-1.el8.src.rpm
    [output truncated]
    Copy to Clipboard Toggle word wrap
注意

调用 rpmbuild --rebuild 涉及以下过程:

  • 将 SRPM 的内容(spec 文件和源代码)安装到 ~/rpmbuild/ 目录中。
  • 使用安装的内容构建一个 RPM。
  • 删除 spec 文件和源代码。

在使用以下任一方法构建后,您可以保留 spec 文件和源代码:

  • 在构建 RPM 时,请使用 rpmbuild 命令和 --recompile 选项,而不是 --rebuild 选项。
  • bellopellocello 安装 SRPM:

    $ rpm -Uvh ~/rpmbuild/SRPMS/bello-0.1-1.el8.src.rpm
    Updating / installing…​
       1:bello-0.1-1.el8               [100%]
    
    $ rpm -Uvh ~/rpmbuild/SRPMS/pello-0.1.2-1.el8.src.rpm
    Updating / installing…​
    …​1:pello-0.1.2-1.el8              [100%]
    
    $ rpm -Uvh ~/rpmbuild/SRPMS/cello-1.0-1.el8.src.rpm
    Updating / installing…​
    …​1:cello-1.0-1.el8            [100%]
    Copy to Clipboard Toggle word wrap

4.6.3. 从 spec 文件构建二进制 RPM

要从其 spec 文件构建二进制 RPM,请使用 rpmbuild 命令和 -bb 选项。

先决条件

  • 您已在系统上安装了 rpmbuild 工具:

    # dnf install rpm-build
    Copy to Clipboard Toggle word wrap

流程

  1. 导航到 ~/rpmbuild/SPECS/ 指令,其包含 spec 文件:

    $ cd ~/rpmbuild/SPECS/
    Copy to Clipboard Toggle word wrap
  2. 从其 spec 构建二进制 RPM:

    $ rpmbuild -bb <spec_file>
    Copy to Clipboard Toggle word wrap

    例如,要从其 spec 文件构建 bellopellocello 二进制 RPM,请输入:

    $ rpmbuild -bb bello.spec
    
    $ rpmbuild -bb pello.spec
    
    $ rpmbuild -bb cello.spec
    Copy to Clipboard Toggle word wrap

4.7. 将 RPM 活动记录到 syslog

您可以使用系统日志协议(syslog)记录任何 RPM 活动或交易。

先决条件

  • syslog 插件已安装在系统上:

    # dnf install rpm-plugin-syslog
    Copy to Clipboard Toggle word wrap
    注意

    syslog 消息的默认位置是 /var/log/messages 文件。但是,您可以将 syslog 配置为使用另一个位置来存储消息。

流程

  1. 打开您配置为存储 syslog 消息的文件。

    或者,如果您使用默认的 syslog 配置,请打开 /var/log/messages 文件。

  2. 搜索包括 [RPM] 字符串的新行。

4.8. 提取 RPM 内容

在某些情况下,例如,如果 RPM 需要的软件包损坏了,您可能需要提取软件包的内容。在这种情况下,如果 RPM 安装仍正常工作,您可以使用 rpm2archive 实用程序将 .rpm 文件转换为 tar 存档以使用软件包的内容。

注意

如果 RPM 安装严重损坏,您可以使用 rpm2cpio 工具将 RPM 软件包文件转换为 cpio 存档。

流程

  • 将 RPM 文件转换为 tar 归档:

    $ rpm2archive <filename>.rpm
    Copy to Clipboard Toggle word wrap

    生成的文件具有 .tgz 后缀。例如,要从 bash 软件包创建归档,请输入:

    $ rpm2archive bash-4.4.19-6.el8.x86_64.rpm
    $ ls bash-4.4.19-6.el8.x86_64.rpm.tgz
    bash-4.4.19-6.el8.x86_64.rpm.tgz
    Copy to Clipboard Toggle word wrap

4.9. 签名 RPM 软件包

您可以使用以下软件之一签署 RPM 软件包,以确保任何第三方都不能更改其内容:

  • Sequoia PGP 支持 OpenPGP 标准。RPM 也使用 Sequoia PGP 来验证软件签名。
  • GNU Privacy Guard (GnuPG)支持旧的 OpenPGP 标准版本,这使得 GnuPG 与 RHEL 9 及更早的版本更加兼容。
警告

新的算法和签名可能与早期的 RHEL 版本不兼容。

4.9.1. 使用 GnuPG 签名 RPM 软件包

您可以使用 GNU Privacy Guard (GnuPG)软件签名 RPM 软件包。

要使用 GNU Privacy Guard (GnuPG)软件签名 RPM 软件包,您必须首先创建一个 OpenPGP 密钥。

先决条件

  • 您已在您的系统上安装了 rpm-signpinentry 软件包。

流程

  1. 生成一个 OpenPGP 密钥对:

    $ gpg --gen-key
    Copy to Clipboard Toggle word wrap
  2. 检查生成的密钥对:

    $ gpg --list-keys
    Copy to Clipboard Toggle word wrap
  3. 导出公钥:

    $ gpg --export -a '<public_key_name>' > RPM-GPG-KEY-pmanager
    Copy to Clipboard Toggle word wrap
4.9.1.2. 配置 RPM ,以使用 GnuPG 签名软件包

要使用 GNU Privacy Guard (GnuPG)软件签名一个 RPM 软件包,您必须通过指定 %_gpg_name RPM 宏来配置 RPM。

先决条件

流程

  • $HOME/.rpmmacros 目录中定义 %_gpg_name 宏:

    %_gpg_name <key-ID>
    Copy to Clipboard Toggle word wrap

    GnuPG 的有效密钥 ID 值可以是密钥指纹、全名或您在创建密钥时提供的电子邮件地址。

4.9.1.3. 向 RPM 软件包添加签名

软件包通常是在没有签名的情况下构建的。您可以在软件包发布前添加您的签名。

先决条件

流程

  • 在软件包中添加签名:

    $ rpmsign --addsign <package-name>.rpm
    Copy to Clipboard Toggle word wrap

验证

  1. 导出的 OpenPGP 公钥 导入到 RPM keyring 中:

    # rpmkeys --import RPM-GPG-KEY-pmanager
    Copy to Clipboard Toggle word wrap
  2. 使用 GnuPG 显示密钥 ID:

    $ gpg --list-keys
    [...]
    pub   rsa3072 2025-05-13 [SC] [expires: 2028-05-12]
          A8AF1C39AC67A1501450734F6DE8FC866DE0394D
    [...]
    Copy to Clipboard Toggle word wrap

    密钥 ID 是命令输出中的 40 个字符的字符串,例如 A8AF1C39AC67A1501450734F6DE8FC866DE0394D

  3. 验证 RPM 文件是否有相应的签名:

    $ rpm -Kv <package_name>.rpm
    <package_name>.rpm:
        Header V4 RSA/SHA256 Signature, key ID 6de0394d: OK
        Header SHA256 digest: OK
        Header SHA1 digest: OK
        Payload SHA256 digest: OK
        MD5 digest: OK
    Copy to Clipboard Toggle word wrap

    签名密钥 ID 与 OpenPGP 密钥 ID 的最后部分匹配。

4.9.2. 使用 Sequoia PGP 签名 RPM 软件包

您可以使用 Sequoia PGP 签名 RPM 软件包,并确保任何第三方不能更改其内容。

要使用 Sequoia PGP 软件签名软件包,您必须首先创建一个 OpenPGP 密钥。

流程

  1. 安装 Sequoia PGP 工具:

    # dnf install sequoia-sq
    Copy to Clipboard Toggle word wrap
  2. 生成一个 OpenPGP 密钥对:

    $ sq key generate --own-key --userid <key_name>
    Copy to Clipboard Toggle word wrap
  3. 检查生成的密钥对:

    $ sq key list
    Copy to Clipboard Toggle word wrap
  4. 导出公钥:

    $ sq cert export --cert-userid '<key_name>' > RPM-PGP-KEY-pmanager
    Copy to Clipboard Toggle word wrap

要使用 Sequoia PGP 软件签名 RPM 软件包,您必须配置 RPM ,以使用 Sequoia PGP,并指定 %_gpg_name 宏。

先决条件

  • 您已在您的系统上安装了 rpm-sign 软件包。

流程

  1. macros.rpmsign-sequoia 文件复制到 /etc/rpm 目录中:

    # cp /usr/share/doc/rpm/macros.rpmsign-sequoia /etc/rpm/
    Copy to Clipboard Toggle word wrap
  2. 从密钥列表的输出中获取有效的 OpenPGP 密钥指纹值:

    $ sq cert list --cert-userid '<key_name>'
     - 7E4B52101EB3DB08967A1E5EB595D12FDA65BA50
       - created 2025-05-13 10:33:29 UTC
       - will expire 2028-05-13T03:59:50Z
    
       - [    ✓    ] <key_name>
    Copy to Clipboard Toggle word wrap

    密钥指纹是输出的第一行上的 40 个字符的字符串,例如 7E4B52101EB3DB08967A1E5EB595D12FDA65BA50

  3. $HOME/.rpmmacros 文件中定义 %_gpg_name 宏,如下所示:

    %_gpg_name <key_fingerprint>
    Copy to Clipboard Toggle word wrap

    请注意,您也可以使用完整的密钥 ID,而不是指纹。

    注意

    与 GnuPG 不同,Sequoia PGP 仅接受完整的密钥 ID 或指纹。

4.9.2.3. 向 RPM 软件包添加签名

软件包通常是在没有签名的情况下构建的。您可以在软件包发布前添加您的签名。

先决条件

流程

  • 在软件包中添加签名:

    $ rpmsign --addsign <package-name>.rpm
    Copy to Clipboard Toggle word wrap

验证

  1. 导出的 OpenPGP 公钥 导入到 RPM keyring 中:

    # rpmkeys --import RPM-PGP-KEY-pmanager
    Copy to Clipboard Toggle word wrap
  2. 显示签名密钥的密钥指纹:

    $ sq key list --cert-userid <key_name>
     - 7E4B52101EB3DB08967A1E5EB595D12FDA65BA50
       - user ID: <key_name> (authenticated)
       - created 2025-05-13 10:33:29 UTC
       - will expire 2028-05-13T03:59:50Z
       - usable for signing
       - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
    
       - 78E56DD2E12E02CFEEA27F8B9FE57972D6BCEA6F
         - created 2025-05-13 10:33:29 UTC
         - will expire 2028-05-13T03:59:50Z
         - usable for decryption
         - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
       - C06E45F8ABC3E59F44A9E811578DDDB66422E345
         - created 2025-05-13 10:33:29 UTC
         - will expire 2028-05-13T03:59:50Z
         - usable for signing
         - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
       - E0BD231AB350AD6802D44C0A270E79FFC39C3B25
         - created 2025-05-13 10:33:29 UTC
         - will expire 2028-05-13T03:59:50Z
         - usable for signing
         - @softkeys/7E4B52101EB3DB08967A1E5EB595D12FDA65BA50: available, unlocked
    Copy to Clipboard Toggle word wrap

    密钥指纹通常是 sq key list --cert-userid <key_name> 命令输出中的一个签名子密钥,例如 E0BD231AB350AD6802D44C0A270E79FFC39C3B25

  3. 验证 RPM 文件是否有相应的签名,例如:

    $ rpm -Kv <package_name>.rpm
    <package_name>.rpm:
        Header V4 EdDSA/SHA512 Signature, key ID c39c3b25: OK
        Header SHA256 digest: OK
        Header SHA1 digest: OK
        Payload SHA256 digest: OK
        MD5 digest: OK
    Copy to Clipboard Toggle word wrap

    签名密钥 ID 与密钥指纹的最后部分匹配。

第 5 章 打包 Python 3 RPM

您可以使用 DNF 软件包管理器在系统上安装 Python 软件包。DNF 使用 RPM 软件包格式,它提供对软件的下游控制。

与原生 Python 软件包相比,将 Python 项目打包成 RPM 软件包提供了以下优点:

  • 可以对 Python 和非 Python 软件包的依赖项,并严格由 DNF 软件包管理器强制执行。
  • 您可以用加密的方式为软件包签名。使用加密签名,您可以验证、集成和测试 RPM 软件包的内容以及操作系统的其余部分。
  • 您可以在构建过程中执行测试。

原生 Python 软件包的打包格式由 Python Packaging Authority (PyPA) 规范定义。历史上,大多数 Python 项目使用 distutilssetuptools 工具打包,并在 setup.py 文件中定义软件包信息。但是,创建原生 Python 软件包可能性随着时间而演变:

  • 要打包使用 setup.py 文件的 Python 软件,请按照此文档操作。
  • 要使用 pyproject.toml 文件打包更现代的软件包,请参阅 pyproject-rpm-macros 中的 README 文件。请注意,pyproject-rpm-macros 包含在 CodeReady Linux Builder (CRB)存储库中,该存储库包含不受支持的软件包,其可能会随着时间的变化而改变,来支持较新的 Python 打包标准。

5.1. 示例 Python 软件包的 spec 文件描述

与非 Python RPM spec 文件相比,Python 项目的 RPM spec 文件有一些具体信息。

请注意,建议任何 Python 库的 RPM 软件包名称包含 python3- 前缀。

请参阅以下 python3-pello 软件包示例中的有关 Python RPM spec 文件的备注。

使用 Python 编写的 pello 程序的 SPEC 文件示例

%global python3_pkgversion 3                                          
1


Name:           python-pello                                          
2

Version:        1.0.2
Release:        1%{?dist}
Summary:        Example Python library

License:        MIT
URL:            https://github.com/fedora-python/Pello
Source:         %{url}/archive/v%{version}/Pello-%{version}.tar.gz

BuildArch:      noarch
BuildRequires:  python%{python3_pkgversion}-devel                     
3


# Build dependencies need to be specified manually
BuildRequires:  python%{python3_pkgversion}-setuptools

# Test dependencies need to be specified manually
# Runtime dependencies need to be BuildRequired manually to run tests during build
BuildRequires:  python%{python3_pkgversion}-pytest >= 3


%global _description %{expand:
Pello is an example package with an executable that prints Hello World! on the command line.}

%description %_description

%package -n python%{python3_pkgversion}-pello                         
4

Summary:        %{summary}

%description -n python%{python3_pkgversion}-pello %_description


%prep
%autosetup -p1 -n Pello-%{version}


%build
# The macro only supports projects with setup.py
%py3_build                                                            
5



%install
# The macro only supports projects with setup.py
%py3_install


%check                                                                
6

%pytest


# Note that there is no %%files section for python-pello
%files -n python%{python3_pkgversion}-pello
%doc README.md
%license LICENSE.txt
%{_bindir}/pello_greeting

# The library files needed to be listed manually
%{python3_sitelib}/pello/

# The metadata files needed to be listed manually
%{python3_sitelib}/Pello-*.egg-info/
Copy to Clipboard Toggle word wrap

1
通过定义 python3_pkgversion 宏,您可以设置将为哪个 Python 版本构建此软件包。要为默认的 Python 版本 3.12 进行构建,请删除该行。
2
将 Python 项目打包到 RPM 中时,需要将 python- 前缀添加到项目的原始名称中。这里的项目名称是 Pello,因此源 RPM (SRPM)的名称是 python-pello
3
BuildRequires 指定了构建和测试此软件包所需的软件包。在 BuildRequires 中,始终包括构建 Python 软件包所需的工具:python3-devel 以及您的软件包,如 python3-setuptools 或要在 %check 部分中运行测试所需的运行时和测试依赖项的特定软件所需的相关项目。
4
当为二进制 RPM 选择名称(用户必须安装的软件包)时,请添加版本化的 Python 前缀。对默认的 Python 3.12 使用 python3- 前缀。您可以使用 %{python3_pkgversion} 宏,对于默认的 Python 版本 3.12 其评估为 3,除非您将其设置为明确的版本,例如,当有较新版本的 Python 可用时(请参阅脚注 1)。
5
%py3_build%py3_install 宏会分别运行 setup.py buildsetup.py install 命令,使用附加参数来指定安装位置、要使用的解释器以及其他详情。
注意

使用 setuptools 软件包中的 setup.py buildsetup.py install 命令已弃用,并将在以后的主 RHEL 发行版本中删除。您可以改为使用 pyproject-rpm-macros

6
%check 部分运行打包项目的测试。确切的命令取决于项目本身,但您可以使用 %pytest 宏以 RPM 友好的方式运行 pytest 命令。

5.2. Python 3 RPM 的常见宏

在 Python RPM spec 文件中,总是对 Python 3 RPM 使用宏,而不是硬编码其值。

您可以通过在 spec 文件之上定义 python3_pkgversion 宏来重新定义这些宏中使用哪个 Python 3 版本。如需更多信息,请参阅 Python 软件包示例的 spec 文件描述。如果您定义了 python3_pkgversion 宏,则下表中描述的宏的值将反映指定的 Python 3 版本。

Expand
表 5.1. Python 3 RPM 宏
Macro常规定义描述

%{python3_pkgversion}

3

所有其他宏使用的 Python 版本。是否可以重新定义到将要添加的任何 Python 版本中。

%{python3}

/usr/bin/python3

Python 3 解释器。

%{python3_version}

3.12

Python 3 解释器的 major.minor 版本。

%{python3_sitelib}

/usr/lib/python3.12/site-packages

安装了纯 Python 模块的位置。

%{python3_sitearch}

/usr/lib64/python3.12/site-packages

包含特定于架构扩展模块的模块的位置已安装。

%py3_build

 

使用适合 RPM 软件包的参数扩展 setup.py build 命令。

%py3_install

 

使用适合 RPM 软件包的参数扩展 setup.py install 命令。

%{py3_shebang_flags}

sP

Python 解释器指令宏的默认的标记集合 %py3_shebang_fix

%py3_shebang_fix

 

将 Python 解释器指令改为 #! %{python3},保留任何现有的标志(如果找到的话),并添加 %{py3_shebang_flags} 宏中定义的标记。

5.3. 为 Python RPM 使用自动生成的依赖项

您可以使用上游提供的元数据为 Python RPM 自动生成依赖项。

先决条件

流程

  1. 在生成的 RPM 中包含以下目录之一:

    • .dist-info
    • .egg-info

      RPM 构建过程会自动从这些目录中生成虚拟 pythonX.Ydist,例如:

      python3.12dist(pello)
      Copy to Clipboard Toggle word wrap

      然后,Python 依赖项生成器读取上游元数据,并使用生成的 pythonX.Ydist 虚拟提供为每个 RPM 软件包生成运行时需求。生成的要求标签的示例:

      Requires: python3.12dist(requests)
      Copy to Clipboard Toggle word wrap
  2. 检查生成的 Requires
  3. 要删除某些生成的 Requires,请在 spec 文件的 %prep 部分中修改上游提供的元数据。
  4. 要禁用自动需求生成器,请在主软件包的 %description 声明上面包含 %{?python_disable_dependency_generator} 宏。

第 6 章 修改 Python 脚本中的解释器指令

在 Red Hat Enterprise Linux 10 中,可执行的 Python 脚本预计会使用解释器指令(也称为 hashbangs 或 shebangs),其明确指定最小主 Python 版本。例如:

#!/usr/bin/python3
#!/usr/bin/python3.12
Copy to Clipboard Toggle word wrap

构建任何 RPM 软件包时会自动运行 /usr/lib/rpm/redhat/brp-mangle-shebangs buildroot 策略(BRP)脚本,来尝试更正所有可执行文件中的解释器指令。当遇到带有模糊解释器指令(例如 #!/usr/bin/python#!/usr/bin/env python)的 Python 脚本时,BRP 脚本会产生错误。

您可以修改 Python 脚本中的解释器指令,以防止 RPM 构建时的构建错误。

先决条件

  • Python 脚本中的一些解释器指令会导致构建错误。

流程

  • 根据您的场景,执行以下步骤之一来修改解释器指令:

    • spec 文件的 %prep 部分中使用以下宏:

      %py3_shebang_fix <SCRIPTNAME> …​
      Copy to Clipboard Toggle word wrap

      SCRIPTNAME 可以是任何文件、目录或文件和目录列表。

      因此,所有列出的文件和列出的目录中的所有 .py 文件的解释器指令都已修改为指向 %{python3}。将保留原始解释器指令的现有标记,并将添加 %{py3_shebang_flags} 宏中定义的其他标志。您可以在 spec 文件中重新定义 %{py3_shebang_flags} 宏,以更改将要添加的标记。

    • 修改打包的 Python 脚本,以便它们符合预期格式。

第 7 章 打包 Ruby gems

Ruby 是一个动态、解释、反射、面向对象的通用编程语言。

使用 Ruby 编写的程序通常使用 RubyGems 软件打包,后者提供特定的 Ruby 打包格式。

RubyGems 创建的软件包称为 gems,它们可以被重新打包成 RPM 软件包。

注意

本文档指的是与 gem 前缀相关的 RubyGems 概念,如 .gemspec 用于 gem 规范,与 RPM 相关的术语是不合格的。

7.1. RubyGems 与 RPM 的关系

RubyGems 代表 Ruby 自己的打包格式。但是 RubyGems 包含与 RPM 所需的元数据类似的元数据。这个元数据简化了将 gem 打包为 RPM 的过程。从 gems 重新打包的 RPM 适合其余发行版。最终用户也可以通过安装合适的 RPM 软件包 gem 和其他系统库来满足 gem 的依赖项。

RubyGems 使用与 RPM 软件包类似的术语,如 spec 文件、软件包名称、依赖项和其他项目。

要符合其余 RHEL RPM 发行版,RubyGems 创建的软件包必须符合以下规则:

  • 在命名软件包时遵循 rubygem-%{gem_name} 模式。
  • 使用 #!/usr/bin/ruby 字符串作为解释器指令。

7.2. RubyGems spec 文件约定

RubyGems spec 文件必须满足以下约定:

  • 文件包含 %{gem_name} 的定义,后者是 gem 规范中的名称。
  • 软件包的源必须是发布的 gem 归档的完整 URL。
  • 软件包的版本必须是 gem 的版本。
  • 文件包含以下 BuildRequires: 指令:

    BuildRequires: rubygems-devel
    Copy to Clipboard Toggle word wrap

    rubygems-devel 软件包包含构建所需的宏。

  • 文件不包含任何其他 rubygem (foo) RequiresProvides 指令,因为这些指令是从 gem 元数据自动生成的。

7.2.1. RubyGems spec 文件示例

以下是用于构建 gems 的示例 spec 文件的特定于 RubyGems 的部分。spec 文件的其余部分遵循通用准则。

示例 spec 文件的特定于 RubyGems 的部分

%prep
%setup -q -n  %{gem_name}-%{version}

# Modify the gemspec if necessary
# Also apply patches to code if necessary
%patch 0 -p1

%build
# Create the gem as gem install only works on a gem file
gem build ../%{gem_name}-%{version}.gemspec

# %%gem_install compiles any C extensions and installs the gem into ./%%gem_dir
# by default, so that we can move it into the buildroot in %%install
%gem_install

%install
mkdir -p %{buildroot}%{gem_dir}
cp -a ./%{gem_dir}/* %{buildroot}%{gem_dir}/

# If there were programs installed:
mkdir -p %{buildroot}%{_bindir}
cp -a ./%{_bindir}/* %{buildroot}%{_bindir}

# If there are C extensions, copy them to the extdir.
mkdir -p %{buildroot}%{gem_extdir_mri}
cp -a .%{gem_extdir_mri}/{gem.build_complete,*.so} %{buildroot}%{gem_extdir_mri}/
Copy to Clipboard Toggle word wrap

7.2.2. RubyGems spec 文件指令

以下是 spec 文件的特定于 RubyGems 部分中的特定项的具体信息。

Expand
表 7.1. RubyGems 的 spec 指令的具体信息
指令RubyGems 具体信息

%prep

RPM 可以直接解包 gem 归档。%setup -n %{gem_name}-%{version} 宏提供解包 gem 的目录。在同一目录级别,会自动创建 %{gem_name}-%{version}.gemspec 文件。您可以使用此文件执行以下操作:

  • 修改 .gemspec 文件
  • 将补丁应用到代码。

%build

本节包含将软件构建成机器码的命令。%gem_install 宏仅对 gem 归档进行操作。因此,您必须首先使用 gem build ../%{gem_name}-%{version}.gemspec 命令重新创建存档。然后,%gem_install 使用重新创建的 gem 文件进行构建,并将 gem 代码安装到默认的 ./%{gem_dir} 临时目录中。在安装之前,构建的源会被放入自动创建的临时目录中。

%install

安装将在 %{buildroot} 层次结构中执行。您可以创建所需的目录,然后将安装的代码从临时目录复制到 %{buildroot} 层次结构中。如果 gem 创建了共享对象,则它们会被移到特定于架构的 %{gem_extdir_mri} 路径中。

7.3. RubyGems macros

以下是用于 RubyGems 创建的软件包的宏。这些宏由 rubygems-devel 软件包提供。

Expand
表 7.2. RubyGems 的宏
宏名称扩展路径使用方法

%{gem_dir}

/usr/share/gems

gem 结构的顶级目录。

%{gem_instdir}

%{gem_dir}/gems/%{gem_name}-%{version}

包含 gem 的实际内容的目录。

%{gem_libdir}

%{gem_instdir}/lib

gem 的库目录。

%{gem_cache}

%{gem_dir}/cache/%{gem_name}-%{version}.gem

缓存的 gem。

%{gem_spec}

%{gem_dir}/specifications/%{gem_name}-%{version}.gemspec

gem 规范文件。

%{gem_docdir}

%{gem_dir}/doc/%{gem_name}-%{version}

gem 的 RDoc 文档。

%{gem_extdir_mri}

%{_libdir}/gems/ruby/%{gem_name}-%{version}

gem 扩展的目录。

7.4. 使用 gem2rpm 生成 spec 文件

您可以使用 gem2rpm 工具创建 RPM spec 文件。

7.4.1. 为 Ruby gem 创建 RPM spec 文件

您可以使用 gem2rpm 工具为 RubyGems 软件包生成 RPM spec 文件。

先决条件

  • 您已在系统中安装了 gem2rpm 工具:

    $ gem install gem2rpm
    Copy to Clipboard Toggle word wrap

流程

  1. 下载最新版本的 gem,并为这个 gem 生成 RPM spec 文件:

    $ gem2rpm --fetch <gem_name> > <gem_name>.spec
    Copy to Clipboard Toggle word wrap
  2. 编辑生成的 spec 文件来添加缺失的信息,例如许可证和更改日志。

7.4.2. 使用自定义 gem2rpm 模板生成 spec 文件

gem2rpm 模板是可以从中生成 RPM spec 文件的标准的 嵌入式 Ruby (ERB) 文件。您可以编辑生成的 RPM spec 文件的模板,而不是编辑生成的 spec 文件。

先决条件

  • 您已在系统中安装了 gem2rpm 工具:

    $ gem install gem2rpm
    Copy to Clipboard Toggle word wrap

流程

  1. 显示所有 gem2rpm 内置模板:

    $ gem2rpm --templates
    Copy to Clipboard Toggle word wrap
  2. 选择其中一个内置模板,并将其保存为自定义模板:

    $ gem2rpm -t <template> -T > rubygem-<gem_name>.spec.template
    Copy to Clipboard Toggle word wrap

    请注意,对于 RHEL 10 Beta,建议使用 fedora-27-rawhide 模板。

  3. 根据需要编辑模板。如需更多信息,请参阅 gem2rpm 模板变量
  4. 使用编辑的模板生成 spec 文件:

    $ gem2rpm -t rubygem-<gem_name>.spec.template <gem_name>-<latest_version>.gem > <gem_name>-GEM.spec
    Copy to Clipboard Toggle word wrap

7.4.3. gem2rpm 模板变量

以下是 RPM spec 文件生成的 gem2rpm 模板中包含的变量。

Expand
表 7.3. gem2rpm 模板中的变量
变量解释

package

gem 的 Gem::Package 变量。

spec

gem 的 Gem::Specification 变量(与 format.spec相同)。

config

Gem2Rpm::Configuration 变量,可以重新定义 spec 模板助手中使用的默认宏或规则。

runtime_dependencies

Gem2Rpm::RpmDependencyList 变量,其提供软件包运行时依赖项的列表。

development_dependencies

Gem2Rpm::RpmDependencyList 变量,其提供软件包开发依赖项的列表。

测试

Gem2Rpm::TestSuite 变量,其提供允许其执行的测试框架的列表。

files

Gem2Rpm::RpmFileList 变量,其提供软件包中未过滤的文件的列表。

main_files

Gem2Rpm::RpmFileList 变量,其提供适合主软件包的文件的列表。

doc_files

Gem2Rpm::RpmFileList 变量,其提供适合 -doc 子软件包的文件的列表。

法律通告

Copyright © 2025 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2026 Red Hat
返回顶部