第 10 章:测试端口

10.1. 运行 make describe

许多 FreeBSD 端口维护工具,例如 portupgrade(1),依赖于一个名为 /usr/ports/INDEX 的数据库,该数据库跟踪端口依赖关系等信息。 INDEX 由顶层 ports/Makefile 通过 make index 命令创建,该命令会进入每个端口子目录并执行 make describe。 因此,如果在任何端口中 make describe 失败,则没有人能够生成 INDEX,并且许多人会很快变得不高兴。

无论 make.conf 中存在哪些选项,都必须能够生成此文件,因此请避免在(例如)依赖关系未满足时使用 .error 语句。(参见 避免使用 .error 结构。)

如果 make describe 生成一个字符串而不是错误消息,则一切都可能安全。有关生成字符串的含义,请参见 bsd.port.mk

另请注意,运行最新版本的 portlint(如下一节所述)将导致自动运行 make describe

10.2. 运行 make test

即使端口构建正常,也建议确保软件能够正确地完成其预期功能。如果原始上游项目随软件一起提供测试,则建议运行这些测试并检查一切按预期工作。

端口可以通过使用 TEST_TARGET 变量自动启用测试。设置后,此变量包含端口测试目标的名称。这通常只是 test,但其他名称包括 testscheck 或针对特定情况的名称,例如 run_tests.py

除了 TEST_TARGET 变量之外,框架还提供以下变量来控制测试执行

  • TEST_WRKSRC 是执行测试的目录。

  • TEST_ENV 包含传递到测试阶段的额外变量。

  • TEST_ARGS 包含传递到测试阶段的任何额外参数。

cad/xycewww/libjwt 等中可以找到这些变量的使用示例。

请确保测试在更新端口时不会中断。

10.3. Portclippy / Portfmt

这些工具来自 ports-mgmt/portfmt

Portclippy 是一个 linter,它检查 Makefile 中的变量是否按 端口 Makefile 中变量的顺序 排列。

Portfmt 是一个用于自动格式化 Makefile 的工具。

10.4. Portlint

在提交或提交端口之前,请使用 portlint 检查该端口。portlint 会警告许多常见的错误,包括功能性和样式性错误。对于新端口,portlint -A 是最彻底的;对于现有端口,portlint -C 就足够了。

由于 portlint 使用启发式方法来尝试找出错误,因此它可能会产生误报。此外,有时被标记为问题的某些内容实际上由于端口框架的限制,无法以其他方式完成。如有疑问,最好的做法是在 FreeBSD 端口邮件列表 上咨询。

10.5. 端口工具

ports-mgmt/porttools 程序是 Ports Collection 的一部分。

port 是前端脚本,它可以帮助简化测试工作。每当需要测试新端口或对现有端口进行更新时,请使用 port test 测试该端口,包括 portlint 检查。此命令还会检测并列出 pkg-plist 中未列出的任何文件。例如

# port test /usr/ports/net/csup

10.6. PREFIXDESTDIR

PREFIX 决定端口将安装的位置。它默认设置为 /usr/local,但用户可以将其设置为自定义路径,例如 /opt。端口必须尊重此变量的值。

如果用户设置了 DESTDIR,则它会确定完整的替代环境,通常是 jail 或安装在 / 以外位置的系统。端口实际上会安装到 DESTDIR/PREFIX 中,并在 DESTDIR/var/db/pkg 中向软件包数据库进行注册。端口基础架构会使用 chroot(8) 自动处理 DESTDIR。无需修改或任何额外注意来编写与 DESTDIR 兼容的端口。

PREFIX 的值将设置为 LOCALBASE(默认为 /usr/local)。如果设置了 USE_LINUX_PREFIX,则 PREFIX 将为 LINUXBASE(默认为 /compat/linux)。

在源代码中避免硬编码 /usr/local 路径,可以使端口更加灵活,并能够满足其他站点的需求。通常,这可以通过在端口的各种 Makefile 中用 ${PREFIX} 替换 /usr/local 的出现来实现。此变量会自动传递到构建和安装过程的每个阶段。

确保应用程序没有将东西安装到 /usr/local 而不是 PREFIX 中。对于此类硬编码路径的快速测试是

% make clean; make package PREFIX=/var/tmp/`make -V PORTNAME`

如果任何东西安装在 PREFIX 以外的位置,则软件包创建过程将抱怨它找不到文件。

此外,值得使用暂存目录支持检查相同的內容(参见 暂存

% make stage && make check-plist && make stage-qa && make package
  • check-plist 检查 plist 中缺少的文件以及 plist 中未由端口安装的文件。

  • stage-qa 检查常见的错误,例如错误的 shebang、指向暂存目录外部的符号链接、setuid 文件和未剥离的库……

这些测试不会查找端口文件内部的硬编码路径,也不会验证 LOCALBASE 是否被用来正确引用来自其他端口的文件。必须测试 /var/tmp/make -V PORTNAME 中临时安装的端口的正常运行情况,以确保路径没有问题。

PREFIX 必须不能在端口的 Makefile 中显式设置。安装端口的用户可能已将 PREFIX 设置为自定义位置,而端口必须尊重该设置。

使用上面提到的变量,而不是显式路径名,来引用来自其他端口的程序和文件。例如,如果端口需要一个宏 PAGER 来获取 less 的完整路径名,请不要使用 /usr/local/bin/less 的文字路径。而是使用 ${LOCALBASE}

-DPAGER=\"${LOCALBASE}/bin/less\"

使用 LOCALBASE 的路径更有可能在系统管理员将整个 /usr/local 树移动到其他位置时仍然有效。

运行 poudriere testportpoudriere bulk -t 时,所有这些测试都会自动执行。强烈建议每个端口贡献者安装和测试他们的端口。有关更多信息,请参见 poudriere

10.7. poudriere

对于端口贡献者来说,poudriere 是最重要的和最有帮助的测试和构建工具之一。它的主要功能包括

  • 批量构建整个端口树、端口树的特定子集或单个端口及其依赖关系

  • 自动打包构建结果

  • 生成每个端口的构建日志文件

  • 提供签名 pkg(8) 仓库

  • 在向 FreeBSD 错误跟踪器提交补丁或提交到端口树之前测试端口构建

  • 测试使用不同选项成功构建端口

由于 poudriere 在干净的 jail(8) 环境中执行其构建,并使用 zfs(8) 功能,因此它比在主机系统上进行的传统测试具有多个优势

  • 不会污染主机环境:没有残留文件、没有意外删除、没有更改现有配置文件。

  • 验证 pkg-plist 中缺少或多余的条目

  • 端口提交者有时会要求在提交补丁时附带 poudriere 日志,以评估补丁是否已准备好集成到端口树中。

它也相当容易设置和使用,没有依赖关系,并且可以在任何支持的 FreeBSD 版本上运行。本节展示了如何在端口贡献者的正常工作流程中安装、配置和运行 poudriere。

本节中的示例显示了默认的文件布局,这是 FreeBSD 的标准。请根据任何本地更改进行相应的替换。端口树(由 ${PORTSDIR} 表示)位于 /usr/ports 中。默认情况下,${LOCALBASE}${PREFIX} 都是 /usr/local

10.7.1. 安装 poudriere

poudriere 在端口树的 ports-mgmt/poudriere 中可用。可以使用 pkg(8) 或从端口中安装它

# pkg install poudriere

# make -C /usr/ports/ports-mgmt/poudriere install clean

还存在一个正在开发的 poudriere 版本,它最终将成为下一个版本。它在 ports-mgmt/poudriere-devel 中可用。此开发版本用于官方 FreeBSD 软件包构建,因此经过了充分的测试。它经常具有更新的有趣功能。端口提交者将希望使用开发版本,因为它是在生产中使用的,并且具有所有新功能,以确保一切都是完全正确的。贡献者不一定需要这些功能,因为最重要的修复程序会被移植到已发布的版本中。使用开发版本构建官方软件包的主要原因是它更快,在使用高端 32 CPU 服务器和 128GB RAM 时,可以将完整的构建时间从 18 小时缩短到 17 小时。在台式机上构建端口时,这些优化不会很重要。

10.7.2. 设置 poudriere

该端口安装了一个默认的配置文件 /usr/local/etc/poudriere.conf。每个参数都在配置文件中进行了说明。

以下是一个最小的配置文件示例

ZPOOL=zroot
BASEFS=/usr/local/poudriere
DISTFILES_CACHE=/usr/ports/distfiles
RESOLV_CONF=/etc/resolv.conf
ZPOOL

poudriere 将使用的 ZFS 存储池的名称。必须在 zpool status 的输出中列出。

BASEFS

poudriere 文件系统的根挂载点。此条目将导致 poudriere 将 tank/poudriere 挂载到 /poudriere

DISTFILES_CACHE

定义 distfiles 的存储位置。在此示例中,poudriere 和主机共享 distfiles 存储目录。这避免了下载系统上已存在的 tarballs。如果此目录尚不存在,请创建它,以便 poudriere 可以找到它。

RESOLV_CONF

在 jail 内使用主机 /etc/resolv.conf 进行 DNS 解析。这需要 jail 在下载 distfiles 时能够解析它们的 URL。使用代理时不需要它。有关代理配置,请参阅默认配置文件。

10.7.3. 创建 poudriere Jails

创建 poudriere 将用于构建的基本 jail

# poudriere jail -c -j 131Ramd64 -v 13.1-RELEASE -a amd64

poudriere.conf 中的 FREEBSD_HOST 给定的 FTP 服务器获取 13.1-RELEASE(适用于 amd64),创建 zfs 文件系统 tank/poudriere/jails/131Ramd64,将其挂载到 /poudriere/jails/131Ramd64 上,并将 13.1-RELEASE tarballs 提取到此文件系统中。

# poudriere jail -c -j 12i386 -v stable/12 -a i386 -m git+https

创建 tank/poudriere/jails/12i386,将其挂载到 /poudriere/jails/12i386 上,然后从 poudriere.conf 中的 GIT_HOST(或默认的 git.freebsd.org)检出 FreeBSD-12-STABLE 的 Git 分支的顶端,检出到 /poudriere/jails/12i386/usr/src 中,然后完成 buildworld 并将其安装到 /poudriere/jails/12i386 中。

虽然可以在旧版本 FreeBSD 上构建新版本,但大多数情况下它无法运行。例如,如果需要一个 stable/13 类型的 jail,则主机也必须运行 stable/13。仅仅运行 13.1-RELEASE 是不够的。

要为 14.0-CURRENT 创建一个 poudriere jail

# poudriere jail -c -j 14amd64 -v main -a amd64 -m git+https

为了运行一个 14.0-CURRENT 的 poudriere jail,主机必须运行 14.0-CURRENT。通常,较新的内核可以构建和运行较旧的 jail。例如,一个 14.0-CURRENT 内核可以构建和运行一个 12.4-STABLE 的 jail,前提是编译了 COMPAT_FREEBSD12 内核选项(默认情况下,在 14.0-CURRENTGENERIC 内核配置中启用)。

可以使用 poudriere jail -l 查看 poudriere 当前已知的 jail 列表。

# poudriere jail -l
JAILNAME             VERSION              ARCH    METHOD
131Ramd64            13.1-RELEASE         amd64   ftp
12i386               12.4-STABLE          i386    git+https

10.7.4. 保持 poudriere Jails 更新

管理更新非常简单。命令

# poudriere jail -u -j JAILNAME

将指定的 jail 更新到可用的最新版本。对于 FreeBSD 发布版,使用 freebsd-update(8) 更新到最新的补丁级别。对于从源代码构建的 FreeBSD 版本,更新到分支中的最新 git 版本。

对于使用 git+* 方法的 jail,添加 -J NumberOfParallelBuildJobs 可以通过增加并行编译作业数量来加快构建速度。例如,如果构建机器有 6 个 CPU,则使用

# poudriere jail -u -J 6 -j JAILNAME

10.7.5. 为 poudriere 设置 Ports 树

在 poudriere 中有多种使用 ports 树的方法。最简单的方法是让 poudriere 使用 Git 为自己创建一个默认的 ports 树

# poudriere ports -c -m git+https -B main

这些命令创建了 tank/poudriere/ports/default,将其挂载到 /poudriere/ports/default 上,并使用 Git 填充它。之后,它将被包含在已知 ports 树的列表中。

# poudriere ports -l
PORTSTREE METHOD    TIMESTAMP           PATH
default   git+https 2020-07-20 04:23:56 /poudriere/ports/default

请注意,“default” ports 树是特殊的。每个后面介绍的构建命令都将隐式地使用此 ports 树,除非明确指定了其他选项。要使用另一个树,请在命令中添加 -p treename

对于 ports 贡献者来说,处理本地修改的最佳方法是使用 Git。与创建 jail 一样,也可以使用其他方法创建 ports 树。要添加另一个 ports 树来测试本地修改和 ports 开发,建议通过 git(如上所述)检出树。

10.7.6. 在 poudriere 中使用手动管理的 Ports 树

根据工作流程,使用手动维护的 ports 树可能非常有用。例如,如果在 /work/ports 中有一个 ports 树的本地副本,则将 poudriere 指向该位置

# poudriere ports -c -m null -M /work/ports -p development

这将在已知树的表格中列出。

# poudriere ports -l
PORTSTREE   METHOD    TIMESTAMP           PATH
development null      2020-07-20 05:06:33 /work/ports

METHOD 列中的破折号或 null 表示 poudriere 将永远不会更新或更改此 ports 树。完全由用户来维护此树,包括可能用于测试新 ports 和提交补丁的所有本地修改。

10.7.7. 保持 poudriere Ports 树更新

与前面介绍的 jail 一样简单

# poudriere ports -u -p PORTSTREE

将给定的 PORTSTREE(由 poudriere -l 输出的单个树)更新到官方服务器上的最新版本。

没有方法的 ports 树(参见 在 poudriere 中使用手动管理的 Ports 树)无法通过这种方式更新,必须由 porter 手动更新。

10.7.8. 测试 Ports

设置好 jail 和 ports 树后,就可以测试贡献者对 ports 树所做的修改结果。

例如,可以测试之前在 /work/ports/www/firefox 中创建的 13.1-RELEASE jail 中对 www/firefox port 的本地修改

# poudriere testport -j 131Ramd64 -p development -o www/firefox

这将构建 Firefox 的所有依赖项。如果之前构建过某个依赖项并且它仍然是最新的,则将安装预构建的软件包。如果某个依赖项没有最新的软件包,则将在一个 jail 中使用默认选项构建一个新的软件包。然后构建 Firefox 本身。

每个 port 的完整构建日志记录在 /poudriere/data/logs/bulk/131Ri386-development/build-time/logs 中。

目录名称 131Ri386-development 来自 -j-p 的参数。为了方便起见,还维护了一个符号链接 /poudriere/data/logs/bulk/131Ri386-development/latest。该链接指向最新的 build-time 目录。该目录中还有一个 index.html,用于在 Web 浏览器中观察构建过程。

默认情况下,poudriere 会清理 jail 并将日志文件保留在上面提到的目录中。为了便于调查,可以通过在 testport 中添加 -i 来保持 jail 在构建完成后继续运行。

# poudriere testport -j 131Ramd64 -p development -i -o www/firefox

构建完成后,无论成功与否,都将在 jail 中提供一个 shell。该 shell 用于进一步调查。可以使用 -I 告诉 poudriere 在构建完成后保持 jail 运行。poudriere 将显示在不再需要 jail 时运行的命令。然后就可以 jexec(8) 到其中。

# poudriere testport -j 131Ramd64 -p development -I -o www/firefox
[...]
====>> Installing local Pkg repository to /usr/local/etc/pkg/repos
====>> Leaving jail 131Ramd64-development-n running, mounted at /poudriere/data/.m/131Ramd64-development/ref for interactive run testing
====>> To enter jail: jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root
====>> To stop jail: poudriere jail -k -j 131Ramd64 -p development
# jexec 131Ramd64-development-n env -i TERM=$TERM /usr/bin/login -fp root
# [do some stuff in the jail]
# exit
# poudriere jail -k -j 131Ramd64 -p development
====>> Umounting file systems

FreeBSD ports 构建基础设施的一个重要组成部分是能够使用选项调整 ports 以满足个人喜好。这些也可以在 poudriere 中进行测试。添加 -c

# poudriere testport -c -o www/firefox

在构建 port 之前显示 port 配置对话框。在 -o 后面的 port(格式为 category/portname)将使用指定的选项,所有依赖项都将使用默认选项。可以使用集合测试具有非默认选项的依赖项,参见 使用集合

在测试 pkg-plist 在构建过程中根据所选选项而改变的 ports 时,建议进行一次选择所有选项的测试运行,以及一次取消选择所有选项的测试运行。

10.7.9. 使用集合

对于所有涉及构建的操作,可以使用 -z setname 指定一个所谓的 集合。集合指的是一个完全独立的构建。例如,这允许使用 testport 为依赖项使用非标准选项。

要使用集合,poudriere 期望有一个类似于 PORT_DBDIR 的现有目录结构(在配置目录中默认为 /var/db/ports)。然后,此目录将被 nullfs(5) 挂载到构建 ports 及其依赖项的 jail 中。通常,可以通过递归地将现有的 PORT_DBDIR 复制到 /usr/local/etc/poudriere.d/jailname-portname-setname-options 来获得一个合适的起点。这在 poudriere(8) 中有详细介绍。例如,要测试名为 devset 的特定集合中的 www/firefox,请在 testport 命令中添加 -z devset 参数

# poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox

这将按以下顺序查找这些目录的存在

  • /usr/local/etc/poudriere.d/131Ramd64-development-devset-options

  • /usr/local/etc/poudriere.d/131Ramd64-devset-options

  • /usr/local/etc/poudriere.d/131Ramd64-development-options

  • /usr/local/etc/poudriere.d/devset-options

  • /usr/local/etc/poudriere.d/development-options

  • /usr/local/etc/poudriere.d/131Ramd64-options

  • /usr/local/etc/poudriere.d/options

从这个列表中,poudriere 将 nullfs(5) 挂载 第一个存在的 目录树到构建 jail 的 /var/db/ports 目录中。因此,在这次 testport 运行期间,所有自定义选项都将用于所有 ports。

提供集合的目录结构后,可以更改特定 port 的选项。例如

# poudriere options -c www/firefox -z devset

将显示 www/firefox 的配置对话框,可以编辑选项。所选选项将保存到 devset 集合中。

poudriere 在选项配置方面非常灵活。poudriere 可以为特定 jail、ports 树以及多个 ports 设置,所有操作都可以通过一个命令完成。有关详细信息,请参阅 poudriere(8)

10.7.10. 提供自定义的 make.conf 文件

与使用集合类似,如果提供了自定义的 make.conf 文件,poudriere 也会使用它。不需要任何特殊的命令行参数。相反,poudriere 会查找与从命令行派生的名称方案匹配的现有文件。例如

# poudriere testport -j 131Ramd64 -p development -z devset -o www/firefox

将导致 poudriere 按以下顺序检查这些文件是否存在

  • /usr/local/etc/poudriere.d/make.conf

  • /usr/local/etc/poudriere.d/devset-make.conf

  • /usr/local/etc/poudriere.d/development-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-development-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-devset-make.conf

  • /usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf

与集合不同的是,所有找到的文件都将按 该顺序 追加到构建 jail 中的一个 make.conf 中。因此,可以在 /usr/local/etc/poudriere.d/make.conf 中设置一般的 make 变量,以影响所有构建。旨在仅影响某些 jail 或集合的特殊变量可以设置在专门的 make.conf 文件中,例如 /usr/local/etc/poudriere.d/131Ramd64-development-devset-make.conf

示例 1. 使用 make.conf 更改默认 Perl

要使用名为 perl5-20 的集合构建使用非默认 Perl 版本(例如 5.20)的集合,请创建一个包含以下行的 perl5-20-make.conf 文件

DEFAULT_VERSIONS+= perl=5.20

请注意使用 +=,以便如果该变量已经在默认的 make.conf 文件中设置,则不会覆盖其内容。

10.7.11. 修剪不再需要的 Distfiles

poudriere 自带一个内置机制,可以删除给定树中任何 port 都不再使用的过时 distfiles。命令

# poudriere distclean -p portstree

将扫描 distfiles 文件夹,DISTFILES_CACHE(位于 poudriere.conf 中),与 -p portstree 参数给出的端口树进行比较,并提示删除那些不使用的 distfiles。 要跳过提示并无条件地删除所有未使用的文件,可以添加 -y 参数。

# poudriere distclean -p portstree -y

10.8. 调试端口

有时事情会出错,端口在运行时失败。 该框架提供了一些工具来帮助调试端口。 这些助手功能有限,因为调试端口的方式很大程度上取决于所使用的技术。 以下变量有助于调试端口

  • WITH_DEBUG。 如果设置,则端口将使用调试符号进行构建。

  • WITH_DEBUG_PORTS。 指定要使用 WITH_DEBUG 设置进行构建的端口列表。

  • DEBUG_FLAGS。 用于指定 CFLAGS 的附加标志。 默认值为 -g

当设置 WITH_DEBUG(全局或针对端口列表)时,生成的二进制文件不会被剥离。

这些变量可以在 make.conf 中或在命令行中指定。

# cd category/port && make -DWITH_DEBUG DEBUG_FLAGSS="-g -O0"

如果端口使用 ports-mgmt/poudriere 构建,则调试变量必须在 poudriere 的 make.conf 中指定,而不是在 /etc/make.conf 中。 有关详细信息,请参阅 ports-mgmt/poudriere 文档。

有关可用调试工具的更多详细信息,请参阅 开发者手册 中的调试信息。


最后修改时间:2024 年 9 月 20 日,由 Fernando Apesteguía 修改