第 13 章. 注意事项

13.1. 简介

以下是移植过程中常见的一些注意事项。在检查端口时,请参考此列表,同时还可以查看 PR 数据库 中其他人提交的端口。根据 错误报告和一般评论 中的说明提交任何有关端口的评论。检查 PR 数据库中的端口,既可以加快我们提交端口的速度,又能证明你了解自己在做什么。

13.2. WRKDIR

不要向 WRKDIR 外部的文件写入任何内容。WRKDIR 是唯一一个保证在端口构建期间可写的位置(请参阅 从 CDROM 安装端口 以了解从只读树构建端口的示例)。pkg-* 文件可以通过 重新定义变量 来修改,而不是覆盖文件。

13.3. WRKDIRPREFIX

确保端口遵守 WRKDIRPREFIX。大多数端口不需要担心这个问题。特别是,当引用另一个端口的 WRKDIR 时,请注意正确的位置是 ${WRKDIRPREFIX}${PORTSDIR}/subdir/name/work,而不是 ${PORTSDIR}/subdir/name/work${.CURDIR}/../../subdir/name/work 或类似的位置。

13.4. 区分操作系统和操作系统版本

某些代码需要根据其运行的 FreeBSD Unix 版本进行修改或条件编译。区分 FreeBSD 版本的首选方法是 sys/param.h 中定义的 __FreeBSD_version__FreeBSD__ 宏。如果未包含此文件,请在 .c 文件的适当位置添加以下代码:

#include <sys/param.h>

__FreeBSD__ 在所有版本的 FreeBSD 中都定义为其主版本号。例如,在 FreeBSD 9.x 中,__FreeBSD__ 定义为 9

#if __FreeBSD__ >= 9
#  if __FreeBSD_version >= 901000
	 /* 9.1+ release specific code here */
#  endif
#endif

__FreeBSD_version 值的完整列表可在 __FreeBSD_version 值 中找到。

13.5. 在 bsd.port.mk 之后编写内容

不要在.include <bsd.port.mk>行之后编写任何内容。通常可以通过在Makefile的中间某个位置包含bsd.port.pre.mk并在末尾包含bsd.port.post.mk来避免这种情况。

仅包含bsd.port.pre.mk/bsd.port.post.mk对或bsd.port.mk;不要混合这两种用法。

bsd.port.pre.mk仅定义了一些变量,这些变量可以在Makefile中的测试中使用,bsd.port.post.mk定义了其余部分。

以下是bsd.port.pre.mk中定义的一些重要变量(这不是完整列表,请阅读bsd.port.mk以获取完整列表)。

变量描述

ARCH

uname -m返回的体系结构(例如,i386

OPSYS

uname -s返回的操作系统类型(例如,FreeBSD

OSREL

操作系统的发行版本(例如,2.1.52.2.7

OSVERSION

操作系统的数字版本;与__FreeBSD_version相同。

LOCALBASE

"本地"树的基目录(例如,/usr/local

PREFIX

端口安装自身的位置(请参阅有关PREFIX的更多信息)。

当需要MASTERDIR时,请务必在包含bsd.port.pre.mk之前定义它。

以下是一些可以在bsd.port.pre.mk之后添加的内容示例

# no need to compile lang/perl5 if perl5 is already in system
.if ${OSVERSION} > 300003
BROKEN=	perl is in system
.endif

BROKEN=之后始终使用制表符而不是空格。

13.6. 在包装脚本中使用exec语句

如果端口安装了一个其目的是启动另一个程序的shell脚本,并且如果启动该程序是脚本执行的最后一个操作,请确保使用exec语句启动该程序,例如

#!/bin/sh
exec %%LOCALBASE%%/bin/java -jar %%DATADIR%%/foo.jar "$@"

exec语句用指定的程序替换shell进程。如果省略exec,则shell进程会在程序执行期间保留在内存中,并无谓地消耗系统资源。

13.7. 合理地做事

Makefile应该以简单合理的方式执行操作。使其缩短几行或更具可读性总是更好。例如,使用make的.if结构而不是shell的if结构,如果重新定义EXTRACT*足够,则不要重新定义do-extract,以及使用GNU_CONFIGURE而不是CONFIGURE_ARGS += --prefix=${PREFIX}

如果需要大量新代码来执行某些操作,则可能已经在bsd.port.mk中实现了它。虽然难以阅读,但对于许多看似困难的问题,bsd.port.mk已经提供了简写解决方案。

13.8. 尊重CCCXX

端口必须同时尊重CCCXX。我们的意思是,端口不得绝对设置这些变量的值,覆盖现有值;相反,它可以将它需要的任何值附加到现有值。这样,影响所有端口的构建选项可以在全局范围内设置。

如果端口不尊重这些变量,请将NO_PACKAGE=ignores either cc or cxx添加到Makefile中。

这是一个尊重CCCXXMakefile示例。请注意?=

CC?= gcc
CXX?= g++

这是一个既不尊重CC也不尊重CXX的示例

CC= gcc
CXX= g++

CCCXX都可以在FreeBSD系统中的/etc/make.conf中定义。第一个示例在之前未在/etc/make.conf中设置值的情况下定义一个值,保留任何系统范围的定义。第二个示例覆盖之前定义的任何内容。

13.9. 尊重CFLAGS

端口必须尊重CFLAGS。我们的意思是,端口不得绝对设置此变量的值,覆盖现有值。相反,它可以将它需要的任何值附加到现有值。这样,影响所有端口的构建选项可以在全局范围内设置。

如果它没有这样做,请将NO_PACKAGE=ignores cflags添加到Makefile中。

这是一个尊重CFLAGSMakefile示例。请注意+=

CFLAGS+= -Wall -Werror

这是一个不尊重CFLAGS的示例

CFLAGS= -Wall -Werror

CFLAGS在FreeBSD系统中的/etc/make.conf中定义。第一个示例将其他标志附加到CFLAGS,保留任何系统范围的定义。第二个示例覆盖之前定义的任何内容。

从第三方Makefile中删除优化标志。系统CFLAGS包含系统范围的优化标志。来自未修改Makefile的示例

CFLAGS= -O3 -funroll-loops -DHAVE_SOUND

使用系统优化标志,Makefile看起来类似于此示例

CFLAGS+= -DHAVE_SOUND

13.10. 详细的构建日志

使端口构建系统显示在构建阶段执行的所有命令。完整的构建日志对于调试端口问题至关重要。

非信息性构建日志示例(错误)

  CC     source1.o
  CC     source2.o
  CCLD   someprogram

详细构建日志示例(正确)

cc -O2 -pipe -I/usr/local/include -c -o source1.o source1.c
cc -O2 -pipe -I/usr/local/include -c -o source2.o source2.c
cc -o someprogram source1.o source2.o -L/usr/local/lib -lsomelib

某些构建系统(例如CMake、ninja和GNU configure)由端口框架设置为详细记录。在其他情况下,端口可能需要单独的调整。

13.11. 反馈

请将适用的更改和补丁发送给上游维护者,以便将其包含在代码的下一个版本中。这使得更新到下一个版本变得更加容易。

13.12. README.html

README.html不是端口的一部分,而是由make readme生成的。不要在补丁或提交中包含此文件。

如果make readme失败,请确保端口未修改ECHO_MSG的默认值。

13.13. 使用BROKENFORBIDDENIGNORE标记端口不可安装

在某些情况下,必须阻止用户安装端口。端口的Makefile中可以使用多个变量来告诉用户该端口无法安装。这些make变量的值将是向用户显示的端口拒绝安装自身的原因。请使用正确的make变量。每个变量都向用户和依赖于Makefile的自动化系统(例如端口构建集群FreshPorts)传达截然不同的含义。

13.13.1. 变量

  • BROKEN保留用于当前无法正确编译、安装、卸载或运行的端口。将其用于认为问题是暂时的端口。

    如果得到指示,构建集群仍将尝试构建它们以查看底层问题是否已解决。(但是,通常情况下,集群在没有此功能的情况下运行。)

    例如,当端口

    • 无法编译

    • 其配置或安装过程失败

    • ${PREFIX}之外安装文件

    • 在卸载时无法干净地删除所有文件(但是,端口保留用户修改的文件可能是可以接受的,也是理想的)

    • 在应该正常运行的系统上存在运行时问题。

  • FORBIDDEN用于包含安全漏洞或引发对安装了给定端口的FreeBSD系统安全性的严重担忧的端口(例如,声誉不佳的不安全程序或提供易于利用的服务的程序)。一旦某个软件存在漏洞并且没有发布升级,就将端口标记为FORBIDDEN。理想情况下,在发现安全漏洞后尽快升级端口,以减少易受攻击的FreeBSD主机数量(我们希望以安全著称),但是有时在公开漏洞和发布易受攻击软件的更新版本之间存在明显的时差。不要出于任何其他安全原因以外的任何原因将端口标记为FORBIDDEN

  • IGNORE保留用于必须出于其他原因而未构建的端口。将其用于认为问题是结构性的端口。构建集群在任何情况下都不会构建标记为IGNORE的端口。例如,当端口

    • 在已安装的FreeBSD版本上不起作用

    • 具有可能由于许可限制而无法自动获取的distfile

    • 与其他一些已安装的端口不兼容(例如,端口依赖于www/drupal7,但安装了www/drupal8

      如果端口与当前已安装的端口发生冲突(例如,如果它们在执行不同功能的同一位置安装文件),请改用CONFLICTSCONFLICTS将自行设置IGNORE

13.13.2. 实现说明

不要引用BROKENIGNORE和相关变量的值。由于向用户显示信息的方式,每个变量的消息措辞会有所不同

BROKEN=	fails to link with base -lcrypto
IGNORE=	unsupported on recent versions

导致make describe输出以下内容

===>  foobar-0.1 is marked as broken: fails to link with base -lcrypto.
===>  foobar-0.1 is unsupported on recent versions.

13.14. 体系结构注意事项

13.14.1. 体系结构的一般说明

FreeBSD 在比众所周知的基于 x86 的架构更多的处理器架构上运行。某些端口具有特定于这些体系结构之一或更多体系结构的约束。

要查看支持的体系结构列表,请运行

cd ${SRCDIR}; make targets

这些值以TARGET/TARGET_ARCH的形式显示。端口只读makevar ARCH根据TARGET_ARCH的值设置。端口Makefile应该测试此Makevar的值。

13.14.2. 将端口标记为体系结构中立

通过设置NO_ARCH=yes来识别没有任何体系结构相关文件或要求的端口。

从这些端口构建的软件包的体系结构字符串以:*(通配符体系结构)结尾,而不是例如freebsd:13:x86:64(amd64体系结构)。

NO_ARCH旨在指示无需为每个支持的体系结构构建软件包。目标是减少构建和分发软件包所花费的资源,例如网络带宽和镜像和分发介质上的磁盘空间。但是,目前,我们的软件包基础设施(例如,软件包管理器、镜像和软件包构建器)尚未设置为充分利用NO_ARCH

13.14.3. 将端口标记为仅在某些体系结构上被忽略

  • 要将端口标记为仅在某些体系结构上被IGNORE,还有两个其他便捷变量会自动设置IGNOREONLY_FOR_ARCHSNOT_FOR_ARCHS。示例

    ONLY_FOR_ARCHS=	i386 amd64
    NOT_FOR_ARCHS=	ia64 sparc64

    可以使用ONLY_FOR_ARCHS_REASONNOT_FOR_ARCHS_REASON设置自定义IGNORE消息。可以使用ONLY_FOR_ARCHS_REASON_ARCHNOT_FOR_ARCHS_REASON_ARCH进行每个体系结构条目。

  • 如果端口获取 i386 二进制文件并安装它们,则设置IA32_BINARY_PORT。如果设置了此变量,则必须存在/usr/lib32以用于 IA32 版本的库,并且内核必须支持 IA32 兼容性。如果这两个依赖项之一未满足,则IGNORE将自动设置。

13.14.4. 集群特定注意事项

  • 某些端口尝试通过向编译器指定-march=native来自动调整到其正在构建的确切机器上。应避免这种情况:要么将其列在默认关闭的选项下,要么完全删除它。

    否则,构建集群生成的默认包可能无法在该ARCH的每一台机器上运行。

13.15. 使用DEPRECATEDEXPIRATION_DATE标记要删除的端口

请记住,如果端口无法工作,BROKENFORBIDDEN仅应作为临时解决方案使用。永久损坏的端口将完全从树中删除。

在有意义的情况下,可以使用DEPRECATEDEXPIRATION_DATE警告用户即将删除端口。前者是一个字符串,说明为什么计划删除该端口;后者是 ISO 8601 格式(YYYY-MM-DD)的字符串。两者都将显示给用户。

可以设置DEPRECATED而没有EXPIRATION_DATE(例如,推荐端口的更新版本),但反过来没有任何意义。

在将端口标记为DEPRECATED时,如果存在任何可作为被弃用端口替代的备用端口,则在提交消息中提及它们会很方便。

关于需要给出多少通知没有既定的策略。目前的做法似乎是针对安全相关问题一个月,针对构建问题两个月。这也给了任何感兴趣的提交者一些时间来解决问题。

13.16. 避免使用.error构造

Makefile指示由于某些外部因素(例如,用户指定了构建选项的非法组合)而无法安装端口的正确方法是将非空白值设置为IGNOREmake install将格式化此值并显示给用户。

为此目的使用.error是一个常见的错误。这样做的问题在于,许多与端口树一起工作的自动化工具在这种情况下都会失败。最常见的发生情况是在尝试构建/usr/ports/INDEX时(请参阅运行make describe)。但是,即使是更简单的命令,如make maintainer,在这种情况下也会失败。这是不可接受的。

示例 1. 如何避免使用.error

接下来的两个Makefile代码段中的第一个将导致make index失败,而第二个则不会。

.error "option is not supported"
IGNORE=option is not supported

13.17. sysctl 的用法

不鼓励使用sysctl,除非在目标中。这是因为任何makevar的评估(例如,在make index期间使用)必须运行该命令,从而进一步减慢该过程。

仅通过SYSCTL使用sysctl(8),因为它包含完整限定路径并且可以被覆盖,如果有人有这样的特殊需求。

13.18. 重新滚动发行版文件

有时软件作者会更改已发布发行版文件的内容,而不更改文件名称。验证更改是否为官方更改,并且是由作者执行的。过去曾发生过发行版文件在下载服务器上被静默更改,目的是造成损害或危害最终用户安全的情况。

将旧的发行版文件放在一边,下载新的文件,解压缩它们并使用diff(1)比较内容。如果没有可疑之处,请更新distinfo

请务必在 PR 和提交日志中总结差异,以便其他人知道没有任何不良事件发生。

联系软件作者并与他们确认更改。

13.19. 使用 POSIX 标准

FreeBSD 端口通常期望符合 POSIX 标准。某些软件和构建系统基于特定操作系统或环境做出假设,这在端口中使用时可能会导致问题。

如果还有其他获取信息的方法,请不要使用/proc。例如,在main()中使用setprogname(argv[0]),然后使用getprogname(3)来了解可执行文件名。

不要依赖 POSIX 未记录的行为。

如果应用程序也可以在没有时间戳的情况下工作,请不要在应用程序的关键路径中记录时间戳。获取时间戳可能会很慢,具体取决于操作系统中时间戳的准确性。如果确实需要时间戳,请确定它们需要多精确,并使用一个 API,该 API 文档记录了仅提供所需精度的功能。

一些简单的系统调用(例如gettimeofday(2)getpid(2))在 Linux® 上比在任何其他操作系统上都快得多,这是由于缓存和 vsyscall 性能优化。不要依赖它们在性能关键型应用程序中很便宜。一般来说,如果可能,请尽量避免使用系统调用。

不要依赖 Linux® 特定的套接字行为。特别是,默认套接字缓冲区大小不同(使用SO_SNDBUFSO_RCVBUF调用setsockopt(2),并且当套接字缓冲区已满时,Linux® 的send(2)会阻塞,而 FreeBSD 的会失败并在 errno 中设置ENOBUFS

如果需要依赖非标准行为,请将其正确封装到通用 API 中,在配置阶段检查该行为,如果缺少则停止。

查看手册页以查看所使用的函数是否是 POSIX 接口(在手册页的“标准”部分)。

不要假设/bin/sh是 bash。确保传递给system(3)的命令行可以在符合 POSIX 标准的 shell 中工作。

常见的 bashisms 列表可在此处找到。

检查头文件是否以 POSIX 或手册页推荐的方式包含。例如,经常会忘记sys/types.h,这对 Linux® 来说不是什么大问题,但对 FreeBSD 来说却是一个问题。

13.20. 杂项

始终仔细检查pkg-descrpkg-plist。如果正在审查端口并且可以获得更好的措辞,请这样做。

请注意任何法律问题!不要让我们非法分发软件!


最后修改于:2024 年 3 月 9 日,作者:Danilo G. Baio