打包教程 1:banner

本教程通过打包 banner 程序来演示RPM打包。这是一个简单的带有 GNU Autotools 构建脚本的程序。

有关如何创建 RPM 文件的全面信息,请参阅 RPM Reference Manual。 如果您计划为 Fedora 存储库创建 RPM 软件包,请遵循以下流程:加入包维护者,包括遵循各种 Fedora 指南。

本教程旨在在 Fedora 40 系统上运行。 不过,它应该也适用于其他 Fedora 版本。只需将 f40 等字符串替换为您的版本号即可。 由于本教程使用了 Fedora 特定功能,而这些功能在其他环境中可能不可用,因此 CentOS Stream 或 Red Hat Enterprise Linux 等 Fedora 下游发行版可能会工作,也可能不会工作。

本教程以逐步的方式进行,其中大多数步骤都是编辑包的规范文件。 最终生成的规范文件列在最后,因此,如果不清楚如何应用特定更改,您可以查看那里。

安装打包工具

创建包目录

在 Fedora 中,包构建指令被组织在所谓的 dist-git 存储库中。 每个包都有一个单独的存储库。 我们通过为本教程创建一个新目录来模仿这个系统。 在 dist-git 中,存储库名称与包名称匹配。 Fedora 的包命名规则写在 Naming Guidelines。 对于 banner 项目,包应该简单命名为 banner。这也是 Fedora official banner package 的名称。

$ mkdir banner && cd banner

Spec 文件内部

RPM packages are configured by .spec files. Tools such as rpmdev-newspec can be used to generate empty specfiles for different purposes. For this tutorial, just create a file called banner.spec and paste the following minimal specfile. It does not work yet, but we will try to build it and fix errors as we encounter them.

Name:     banner
Version:  1.3.6
Release:  %autorelease
Summary:  Prints a short string to the console in very large letters
License:  GPL-2.0-only
URL:      https://github.com/pronovic/banner
Source:   https://github.com/pronovic/banner/releases/download/BANNER_V%{version}/banner-%{version}.tar.gz

%description
This is a classic-style banner program similar to the one found in Solaris or
AIX in the late 1990s. It prints a short string to the console in very large
letters.

%prep
%autosetup

%build
%configure
%make_build

%install
%make_install

%files

%changelog
%autochangelog

规范文件以一组 tags 开头,例如 Name:Version: ,接下来是 sections 例如 %description%prep。 每个标签占一行,而每个部分都会持续到下一个部分开始。

请注意,令人困惑的是,除了标记章节名称之外,百分号 % 还标记 RPM 。因此 %autosetup%configure%make_build%make_install%autochangelog 不是章节。

标签

Version 包含打包软件的版本号。

Release Fedora 中的 spec 文件更新、软件包重建和其他工作。这里使用的值 %autorelease 是https://docs.pagure.org/fedora-infra.rpmautospec/index.html[rpmautospec] 的一部分, 推荐用于Fedora 软件包 。它将 Release 与包的 Git 历史记录联系起来。 由于我们没有 Git 存储库,%autorelease 将计算为默认值 1。

通常,可以从上游 READNE 文件中复制 Summary。 第一个字母应该是大写以避免 rpmlint 报错"。

License 使用 SPDX 许可证标识符描述生成的二进制包的许可证。它必须遵循 Fedora licensing guidelines。在实际中,确定正确的值通常意味着检查各个源文件中的许可证通知。上游开发者可能还需要被要求澄清或更正。在本教程中,我们仅采用上游的说法,即许可证是GNU Public License,版本 2。

URL 指向上游项目的网站,在本例中是 GitHub 存储库的页面。

Source 定义构建包时使用的上游源。通常,如本例所示,它是指向上游发布的 tarball 的 url,但它也可以是本地文件。如果需要,可以有多个 Source 标签。

章节

%description 通常可以从上游 README 文件中复制。

%prep 包含一个用于准备构建源的 shell 脚本。通常只是单个宏 %autosetup,在这种情况下,它只是提取源代码。

%build 包含所需构建步骤的 shell 脚本,例如将源代码编译为二进制文件。由于 banner 程序的构建系统是https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html[Autotools],因此构建它需要运行 configuremake。宏 %configure%make_build 使用 Fedora 的编译标志和其他配置调用这些命令。

%install 包含一个用于将 %build 的结果复制到最初为空的 build root 目录中的 shell 脚本。由于 banner 使用 Autotools,因此使用宏`%make_install`。

%files 列出生成的包的内容。大多数情况下,这些文件来自 %install 创建的构建根目录,但文档和许可证文件也可以直接从源添加。此部分暂时留空,稍后填写。

%changelog 记录每个新软件包版本和发行版中的更改。更改日志数据可以通过 rpm --query --changelog PACKAGE_NAME 显示,这很有用,例如,可以查明是否包含特定的错误和安全补丁。它的值 %autochangelog 同样来自 rpmautospec。它从 Git 提交消息填充变更日志。 由于我们没有 Git 存储库,因此变更日志将为空。

不需要的行可以用 # 注释掉。

您可以在 RPM 参考手册的 Spec file format 章节找到更多信息。

下载源文件

我们需要由 Source 标签定义的源码,通常被称为 upstream 源。使用 spectool 命令最容易实现这一点:

$ spectool -g banner.spec

现在,您的工作目录中应该有了在 Source 中列出的文件:

$ ls *.tar.gz
banner-1.3.6.tar.gz

构建包

我们已准备好首次运行以构建源代码、二进制文件和调试包。此任务以及许多其他任务都是使用 fedpkg 工具完成的。Fedora 的生产版本是在 Koji 构建系统中构建的,它又使用 Mock 来管理隔离的构建环境。为了在本地尽可能接近生产构建,我们使用 fedpkg mockbuild 命令,该命令也调用 Mock:

$ fedpkg --release f40 mockbuild

Mock 创建的构建环境非常基础。 默认情况下它不包含 C 编译器,因此构建将失败。 输出中解释了原因:

checking whether the C compiler works... no
configure: error: in `/builddir/build/BUILD/banner-6':
configure: error: C compiler cannot create executables
See `config.log' for more details

RPM build errors:
error: Bad exit status from /var/tmp/rpm-tmp.R4Tf16 (%build)
    Bad exit status from /var/tmp/rpm-tmp.R4Tf16 (%build)

通过将 BuildRequires: 行添加到规范文件来定义其他构建工具。 在Fedora中,GCC是标准编译器,因此我们需要为 gcc 添加一行 。 Autotools 也使用 make,因此也应该为其添加一行。 在 Source 之后添加这些行:

BuildRequires:   gcc
BuildRequires:   make

再次运行 mockbuild 。

安装文件

rpm 将报错的下一件事是未打包的文件,即将要安装在系统中但未声明为属于该包的文件。我们需要在 %files 部分声明它们。修复这些错误是一个迭代过程。在spec文件中声明缺少文件后,再次运行 fedpkg , 然后声明下一个丢失的文件等等。

我们将一一浏览文件列表。

可执行文件

Installed (but unpackaged) file(s) found:
/usr/bin/banner

这是可执行的二进制程序。 /usr/bin 与许多其他系统目录一样,有一个 默认 rpm 宏。应始终在可用时使用宏,因此可执行文件在 %files 中列出,如下所示:

%files
%{_bindir}/banner

手册页

Installed (but unpackaged) file(s) found:
/usr/share/man/man1/banner.1.gz

打包指南有一个关于 Manpages 的专门章节。按照其说明,手册页列表如下:

%{_mandir}/man1/banner.1.*

至此,mockbuild 已成功完成,但仍有更多文件需要添加到包中。

许可文件

每个软件包都必须安装其许可证,用 %license 指令标记。在 banner 项目,以及许多其他项目,许可证文件位于源 tarball 的顶层,并且可能在安装过程中根本没有复制到构建根目录。无论如何,可以使用相对路径将其安装到标准许可证目录:

%files
%license COPYING

附加文档

通常,包源包含对最终用户也有用的文档。可以使用 %doc 指令安装这些文件并标记为文档。与 %license 类似,相对路径可用于直接包含来自源 tarball 的文件,而不是来自 buildroot 的文件:

%doc AUTHORS ChangeLog NEWS README.md

使用 rpmlint 检查结果

接下来,您应该通过在specfile、源rpm 和二进制rpm 上运行 rpmlint 来检查是否符合RPM 设计规则。 命令 fedpkg lint 执行以下操作:

$ fedpkg --release f40 lint

如果一切正常,应该不会有警告或错误。 为了教程的缘故,我们故意在前面的步骤中留下了一个错误:

 banner.x86_64: E: zero-length /usr/share/doc/banner/NEWS

各种错误码的描述可以通过 rpmlint -e <error_code> 查询。 在本例中,必须删除不必要的零长度文件。 将文档行更改为

%doc AUTHORS ChangeLog README.md

再次运行 fedpkg mockbuildfedpkg lint 观察警告是否已修复。

完整 spe 文件

这是 banner.spec 的最终版本:

Name:           banner
Version:        1.3.6
Release:        %autorelease
Summary:        Prints a short string to the console in very large letters
License:        GPL-2.0-only
URL:            https://github.com/pronovic/banner
Source:         https://github.com/pronovic/banner/releases/download/BANNER_V%{version}/banner-%{version}.tar.gz
BuildRequires:  gcc
BuildRequires:  make

%description
This is a classic-style banner program similar to the one found in Solaris or
AIX in the late 1990s. It prints a short string to the console in very large
letters.

%prep
%autosetup

%build
%configure
%make_build

%install
%make_install

%files
%{_bindir}/banner
%{_mandir}/man1/banner.1.*
%license COPYING
%doc AUTHORS ChangeLog README

%changelog
%autochangelog

通过这个 spec 文件,您应该能够成功完成构建过程,并创建源代码和二进制 RPM 包。

检查结果

有了一个可用的 spec 文件和从中构建的 rpm,就可以检查结果。 在通过安装包检查结果之前,让我们做一些简单的检查。 RPM 包管理器 rpm 可用于此目的。

文件

列出包中包含的文件:

$ rpm --query --package --list results_banner/6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
/usr/bin/banner
/usr/lib/.build-id
/usr/lib/.build-id/01
/usr/lib/.build-id/01/360ae02508eaa0a77d216953b8b658a1e90b10
/usr/share/doc/banner
/usr/share/doc/banner/AUTHORS
/usr/share/doc/banner/ChangeLog
/usr/share/doc/banner/README
/usr/share/licenses/banner
/usr/share/licenses/banner/COPYING
/usr/share/man/man1/banner.1.gz

您可以看到包含了spec 文件 %files 部分中列出的所有文件。 另外,在`/usr/lib/.build-id下,有一个自动生成的文件。 它实际上是一个符号链接,将构建 ID 映射到 `banner 二进制文件以用于调试目的。

依赖

使用以下命令列出包的运行时依赖项:

$ rpm --query --package --requires results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
libc.so.6()(64bit)
libc.so.6(GLIBC_2.2.5)(64bit)
libc.so.6(GLIBC_2.3)(64bit)
libc.so.6(GLIBC_2.3.4)(64bit)
libc.so.6(GLIBC_2.34)(64bit)
libc.so.6(GLIBC_2.4)(64bit)
rpmlib(CompressedFileNames) <= 3.0.4-1
rpmlib(FileDigests) <= 4.6.0-1
rpmlib(PayloadFilesHavePrefix) <= 4.0-1
rpmlib(PayloadIsZstd) <= 5.4.18-1
rtld(GNU_HASH)

要检查 Fedora 存储库中的哪些包提供这些依赖项,您可以使用 dnf repoquery

$ dnf -C repoquery --whatprovides 'libc.so.6()(64bit)'
glibc-0:2.38-16.fc40.x86_64
glibc-0:2.38-7.fc40.x86_64

您将看到 banner 的唯一依赖项是 glibc,它提供了 libc.so.6 以及 rtld(GNU_HASH) 中的符号。

rpmlib 要求很特殊。 这些指定了 rpm 软件包本身使用的各种 rpm 功能,限制了可用于安装软件包的 rpm 版本。

Provides

相反,要检查包提供的功能,您可以执行以下操作:

$ rpm --query --package --provides results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
banner = 1.3.6-1.fc40
banner(x86-64) = 1.3.6-1.fc40

这个包的提供非常简单。 它只是以简单且特定于架构的形式提供自己的名称。

安装

作为最终检查,可以安装并运行该包:

$ sudo dnf -C -y install ./results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.x86_64.rpm
$ banner success

 #####   #     #   #####    #####   #######   #####    #####
#     #  #     #  #     #  #     #  #        #     #  #     #
#        #     #  #        #        #        #        #
 #####   #     #  #        #        #####     #####    #####
      #  #     #  #        #        #              #        #
#     #  #     #  #     #  #     #  #        #     #  #     #
 #####    #####    #####    #####   #######   #####    ##### ..

要清理系统,请撤消安装:

$ sudo dnf -C -y history undo last

在 Fedora 基础设施中构建

即使该包还不是 Fedora 发行版的一部分,也可以执行 scratch build 以确保该包在 Fedora 的 Koji 构建系统中成功构建,并且可以在 Fedora 支持的所有体系结构中成功构建。这种构建是通过将源 rpm 包传递给 fedpkg scratch-build 来启动的。

请注意,Koji 使用 Kerberos 进行身份验证。 有关详细信息,请参阅 Acquiring Kerberos Ticket

$ fedpkg --release f40 scratch-build --srpm results_banner/1.3.6/1.fc40/banner-1.3.6-1.fc40.src.rpm
Building banner-1.3.6-1.fc40.src.rpm for f40-candidate
Created task: 92465688
Task info: https://koji.fedoraproject.org/koji/taskinfo?taskID=92465688
Watching tasks (this may be safely interrupted)...

您可以在浏览器中打开任务信息链接来查看构建进度、日志和结果。 命令行程序还会报告发生的进度。 成功执行看起来像这样:

92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm): free
92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm): free -> open (buildvm-ppc64le-25.iad2.fedoraproject.org)
  92465698 rebuildSRPM (noarch): open (buildvm-s390x-24.s390.fedoraproject.org)
  92465745 buildArch (banner-1.3.6-1.fc40.src.rpm, x86_64): free
  92465748 buildArch (banner-1.3.6-1.fc40.src.rpm, s390x): open (buildvm-s390x-19.s390.fedoraproject.org)
  92465746 buildArch (banner-1.3.6-1.fc40.src.rpm, aarch64): open (buildvm-a64-26.iad2.fedoraproject.org)
  92465747 buildArch (banner-1.3.6-1.fc40.src.rpm, ppc64le): open (buildvm-ppc64le-11.iad2.fedoraproject.org)
  92465744 buildArch (banner-1.3.6-1.fc40.src.rpm, i686): open (buildhw-x86-12.iad2.fedoraproject.org)
  92465698 rebuildSRPM (noarch): open (buildvm-s390x-24.s390.fedoraproject.org) -> closed
  1 free  5 open  1 done  0 failed
  92465745 buildArch (banner-1.3.6-1.fc40.src.rpm, x86_64): free -> open (buildhw-x86-06.iad2.fedoraproject.org)
  92465745 buildArch (banner-1.3.6-1.fc40.src.rpm, x86_64): open (buildhw-x86-06.iad2.fedoraproject.org) -> closed
  0 free  5 open  2 done  0 failed
  92465748 buildArch (banner-1.3.6-1.fc40.src.rpm, s390x): open (buildvm-s390x-19.s390.fedoraproject.org) -> closed
  0 free  4 open  3 done  0 failed
  92465746 buildArch (banner-1.3.6-1.fc40.src.rpm, aarch64): open (buildvm-a64-26.iad2.fedoraproject.org) -> closed
  0 free  3 open  4 done  0 failed
  92465744 buildArch (banner-1.3.6-1.fc40.src.rpm, i686): open (buildhw-x86-12.iad2.fedoraproject.org) -> closed
  0 free  2 open  5 done  0 failed
92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm): open (buildvm-ppc64le-25.iad2.fedoraproject.org) -> closed
  0 free  1 open  6 done  0 failed
  92465747 buildArch (banner-1.3.6-1.fc40.src.rpm, ppc64le): open (buildvm-ppc64le-11.iad2.fedoraproject.org) -> closed
  0 free  0 open  7 done  0 failed

92465688 build (f40-candidate, banner-1.3.6-1.fc40.src.rpm) completed successfully