第 6 章. 特殊注意事项

本节解释了创建端口时需要考虑的最常见事项。

6.1. 拆分长文件

有时,端口的 Makefiles 可能非常长。例如,Rust 端口可能有一个非常长的 CARGO_CRATES 列表。在其他情况下,Makefile 可能包含根据架构而变化的代码。在这种情况下,将原始的 Makefile 拆分为多个文件可能会很方便。 bsd.port.mk 会自动将某些类型的 Makefiles 包含到主端口的 Makefile 中。

以下是框架在找到时会自动处理的文件

  • Makefile.crates。可以在 audio/ebur128 中找到示例。

  • Makefile.inc。可以在 net/ntp 中找到示例。

  • Makefile.${ARCH}-${OPSYS}

  • Makefile.${OPSYS}。可以在 net/cvsup-static 中找到示例。

  • Makefile.${ARCH}

  • Makefile.local

将端口的打包列表拆分为多个文件也是常见的做法,如果列表在不同架构之间存在很大差异或取决于所选的风格。在这种情况下,每个架构的 pkg-plist 文件将按照 pkg-plist.${ARCH}pkg-plist.${FLAVOR} 的模式命名。如果存在多个 pkg-plist 文件,框架不会自动创建打包列表。端口维护者有责任选择合适的 pkg-plist 并将其分配给 PLIST 变量。有关如何处理此问题的示例可以在 audio/logitechmediaserverdeskutils/libportal 中找到。

6.2. 暂存

bsd.port.mk 期望端口使用“暂存目录”。这意味着端口不能直接将文件安装到常规目标目录(例如,在 PREFIX 下),而是安装到一个单独的目录中,然后从该目录中构建包。在许多情况下,这不需要 root 权限,从而可以使用非特权用户构建包。使用暂存,端口将被构建并安装到暂存目录 STAGEDIR 中。从暂存目录中创建包,然后将其安装到系统中。Automake 工具将此概念称为 DESTDIR,但在 FreeBSD 中,DESTDIR 具有不同的含义(参见 PREFIXDESTDIR)。

没有端口真正需要 root 权限。它可以通过使用 USES=uidfix 来避免。如果端口仍然运行诸如 chown(8)chgrp(1) 之类的命令,或者使用 install(1) 强制所有者或组,那么可以使用 USES=fakeroot 来伪造这些调用。需要对端口的 Makefiles 进行一些修补。

元端口,或本身不安装文件但只依赖于其他端口的端口,必须避免不必要地将 mtree(8) 提取到暂存目录。这是包的基本目录布局,这些空目录将被视为孤儿。为了防止 mtree(8) 提取,请添加以下行

NO_MTREE=	yes

元端口应该使用 USES=metaport。它为不获取、构建或安装任何内容的端口设置默认值。

暂存通过在 pre-installdo-installpost-install 目标中使用的路径前添加 STAGEDIR 来启用(参见本书中的示例)。通常,这包括 PREFIXETCDIRDATADIREXAMPLESDIRDOCSDIR 等等。目录应作为 post-install 目标的一部分创建。尽可能避免使用绝对路径。

安装内核模块的端口必须在其目标路径前添加 STAGEDIR,默认情况下为 /boot/modules.

创建符号链接时,强烈建议使用相对链接。使用 ${RLN} 创建相对符号链接。它在幕后使用 install(1) 自动找出要创建的相对链接。

示例 1. 自动创建相对符号链接

${RLN} 使用 install(1) 的相对符号功能,这使端口维护者无需计算相对路径。

${RLN} ${STAGEDIR}${PREFIX}/lib/libfoo.so.42 ${STAGEDIR}${PREFIX}/lib/libfoo.so
${RLN} ${STAGEDIR}${PREFIX}/libexec/foo/bar ${STAGEDIR}${PREFIX}/bin/bar
${RLN} ${STAGEDIR}/var/cache/foo ${STAGEDIR}${PREFIX}/share/foo

将生成

% ls -lF ${STAGEDIR}${PREFIX}/lib
lrwxr-xr-x  1 nobody  nobody    181 Aug  3 11:27 libfoo.so@ -> libfoo.so.42
-rwxr-xr-x  1 nobody  nobody     15 Aug  3 11:24 libfoo.so.42*
% ls -lF ${STAGEDIR}${PREFIX}/bin
lrwxr-xr-x  1 nobody  nobody    181 Aug  3 11:27 bar@ -> ../libexec/foo/bar
% ls -lF ${STAGEDIRDIR}${PREFIX}/share
lrwxr-xr-x  1 nobody  nobody    181 Aug  3 11:27 foo@ -> ../../../var/cache/foo

6.3. 捆绑库

本节解释了为什么捆绑依赖项被认为不好以及如何处理它们。

6.3.1. 为什么捆绑库不好

一些软件要求端口维护者找到第三方库并将所需的依赖项添加到端口中。其他软件将所有必要的库捆绑到分发文件中。第二种方法乍一看似乎更容易,但有一些严重的缺点

此列表松散地基于 FedoraGentoo wiki,两者都根据 CC-BY-SA 3.0 许可证授权。

安全性

如果在上游库中发现漏洞并在上游库中修复,这些漏洞可能不会在与端口捆绑在一起的库中修复。一个原因可能是作者没有意识到这个问题。这意味着端口维护者必须修复它们,或者升级到一个非易受攻击的版本,并将补丁发送给作者。所有这些都需要时间,导致软件比必要的时间更长地处于易受攻击状态。这反过来使得在不泄露有关漏洞信息的情况下协调修复变得更加困难。

错误

这个问题与上一段中提到的安全问题类似,但通常不那么严重。

分叉

一旦库被捆绑,作者更容易分叉上游库。虽然乍一看很方便,但这意味着代码与上游代码分离,使解决软件的安全问题或其他问题变得更加困难。原因是修补变得更加困难。

分叉的另一个问题是,由于代码与上游代码分离,错误被反复解决,而不是只在一个中心位置解决一次。这从根本上否定了开源软件的理念。

符号冲突

当库安装到系统上时,它可能会与捆绑的版本发生冲突。这可能会在编译或链接时导致立即错误。它还可能导致运行程序时发生错误,这些错误可能更难以追踪。后一个问题可能是由于两个库的版本不兼容造成的。

许可证

捆绑来自不同来源的项目时,许可证问题更容易出现,尤其是在许可证不兼容时。

浪费资源

捆绑库在多个级别上浪费资源。构建实际应用程序需要更长的时间,尤其是如果这些库已经存在于系统上。在运行时,当系统范围内的库已经被一个程序加载,而捆绑的库被另一个程序加载时,它们会占用不必要的内存。

浪费精力

当库需要为 FreeBSD 打补丁时,这些补丁必须在捆绑库中再次复制。这浪费了开发人员的时间,因为补丁可能无法干净地应用。也可能很难注意到这些补丁最初是必需的。

6.3.2. 如何处理捆绑库

只要有可能,请通过将 LIB_DEPENDS 添加到端口中来使用库的非捆绑版本。如果这样的端口还不存在,请考虑创建它。

仅当上游具有良好的安全记录,并且使用非捆绑版本会导致过于复杂的补丁时,才使用捆绑库。

在一些非常特殊的情况下,例如模拟器,如 Wine,端口必须捆绑库,因为它们在不同的架构中,或者它们已被修改以适合软件的使用。在这种情况下,这些库不应该被暴露给其他端口以进行链接。将 BUNDLE_LIBS=yes 添加到端口的 Makefile 中。这将告诉 pkg(8) 不要计算提供的库。在将此添加到端口之前,请务必咨询端口管理团队 <[email protected]>。

6.4. 共享库

如果端口安装了一个或多个共享库,请定义一个 USE_LDCONFIG make 变量,该变量将指示 bsd.port.mkpost-install 目标期间在安装新库的目录(通常为 PREFIX/lib)上运行 ${LDCONFIG} -m,以将其注册到共享库缓存中。此变量在定义时,还会方便地在 pkg-plist 中添加一个相应的 @exec /sbin/ldconfig -m@unexec /sbin/ldconfig -R 对,以便安装了该包的用户可以立即开始使用共享库,并且卸载不会导致系统仍然认为该库存在。

USE_LDCONFIG=	yes

默认目录可以通过将 USE_LDCONFIG 设置为要安装共享库的目录列表来覆盖。例如,如果端口将共享库安装到 PREFIX/lib/fooPREFIX/lib/bar 中,请在 Makefile 中使用以下内容

USE_LDCONFIG=	${PREFIX}/lib/foo ${PREFIX}/lib/bar

请仔细检查,通常这根本不需要,或者可以通过 -rpath 或在链接期间设置 LD_RUN_PATH 来避免(参见 lang/mosml 的示例),或者通过一个设置 LD_LIBRARY_PATH 然后调用二进制文件的 shell 包装器,例如 www/seamonkey 所做的那样。

在 64 位系统上安装 32 位库时,请改用 USE_LDCONFIG32

如果软件使用 autotools,特别是 libtool,请添加 USES=libtool

当更新到新端口版本时主要库版本号增加时,所有链接到受影响库的其他端口都必须将其 PORTREVISION 增加,以强制使用新库版本重新编译。

6.5. 具有分发限制或法律问题端口

许可证各不相同,其中一些许可证对应用程序如何打包、是否可以盈利销售等方面进行限制。

端口维护者有责任阅读软件的许可条款,并确保 FreeBSD 项目不会因通过 FTP/HTTP 或 CD-ROM 重新分发源代码或编译后的二进制文件而违反这些条款。如果有疑问,请联系 FreeBSD 端口邮件列表

在这种情况下,可以使用下一节中描述的变量。

6.5.1. NO_PACKAGE

此变量表示我们可能不会生成应用程序的二进制包。例如,许可证可能不允许二进制分发,或者可能禁止分发从修补的源代码创建的包。

但是,端口的 DISTFILES 可以自由地镜像在 FTP/HTTP 上。它们也可以分发到 CD-ROM(或类似介质)上,除非 NO_CDROM 也被设置。

如果二进制包一般不可用,并且必须始终从源代码编译应用程序,请使用 NO_PACKAGE。例如,如果应用程序具有在编译时硬编码到其中的站点特定的配置信息,请设置 NO_PACKAGE

NO_PACKAGE 设置为一个字符串,描述为什么不能生成该包。

6.5.2. NO_CDROM

仅此变量表示,虽然我们允许生成二进制包,但我们既不能将这些包,也不能将端口的 `DISTFILES` 放入 CD-ROM(或类似媒体)中进行转售。但是,二进制包和端口的 `DISTFILES` 仍然可以通过 FTP/HTTP 获得。

如果此变量与 `NO_PACKAGE` 一起设置,则只有端口的 `DISTFILES` 可用,并且仅通过 FTP/HTTP 可用。

将 `NO_CDROM` 设置为一个字符串,描述为什么该端口不能在 CD-ROM 上重新分发。例如,如果端口的许可证仅供“非商业”使用,则使用此方法。

6.5.3. `NOFETCHFILES`

在 `NOFETCHFILES` 中定义的文件不能从任何 `MASTER_SITES` 获取。此类文件的一个例子是,该文件由供应商在 CD-ROM 上提供。

检查这些文件在 `MASTER_SITES` 上是否可用的工具必须忽略这些文件,并且不报告它们。

6.5.4. `RESTRICTED`

如果应用程序的许可证既不允许镜像应用程序的 `DISTFILES`,也不允许以任何方式分发二进制包,则单独设置此变量。

不要将 `NO_CDROM` 或 `NO_PACKAGE` 与 `RESTRICTED` 一起设置,因为后一个变量隐含前两个变量。

将 `RESTRICTED` 设置为一个字符串,描述为什么该端口不能重新分发。通常,这表示该端口包含专有软件,用户需要手动下载 `DISTFILES`,可能需要在注册软件或同意接受 EULA 条款后才能下载。

6.5.5. `RESTRICTED_FILES`

当 `RESTRICTED` 或 `NO_CDROM` 设置时,此变量默认为 `${DISTFILES} ${PATCHFILES}`,否则为空。如果只有部分分发文件受限,则将此变量设置为列出这些文件。

如果端口存在上述变量未解决的法律问题,则将 `LEGAL_TEXT` 设置为一个字符串,解释此问题。例如,如果 FreeBSD 获得了重新分发二进制文件的特殊许可,则此变量必须指示这一点。

设置任何上述变量的端口也必须添加到 /usr/ports/LEGAL 中。第一列是一个 glob,与受限的 distfiles 匹配。第二列是端口的来源。第三列是 `make -VLEGAL` 的输出。

6.5.8. 示例

说明“此端口的 distfiles 必须手动获取”的首选方法如下

.if !exists(${DISTDIR}/${DISTNAME}${EXTRACT_SUFX})
IGNORE=	may not be redistributed because of licensing reasons. Please visit some-website to accept their license and download ${DISTFILES} into ${DISTDIR}
.endif

这既通知用户,又在用户的机器上设置了用于自动化程序的适当元数据。

请注意,此节必须以包含 bsd.port.pre.mk 为前缀。

6.6. 构建机制

6.6.1. 并行构建端口

FreeBSD 端口框架支持使用多个 `make` 子进程进行并行构建,这允许 SMP 系统利用所有可用的 CPU 能力,从而使端口构建更快、更有效。

这是通过将 `-jX` 标志传递给在供应商代码上运行的 make(1) 来实现的。这是端口的默认构建行为。不幸的是,并非所有端口都能很好地处理并行构建,可能需要通过添加 `MAKE_JOBS_UNSAFE=yes` 变量来显式禁用此功能。当已知端口在 `-jX` 下存在问题时使用它,因为竞争条件会导致间歇性构建失败。

设置 `MAKE_JOBS_UNSAFE` 时,非常重要的一点是,在 Makefile 中的注释中,或者至少在提交消息中,解释为什么端口在启用时无法构建。否则,几乎不可能在稍后日期提交更新时修复问题,或者测试问题是否已修复。

6.6.2. `make`、`gmake` 和 `imake`

存在几种不同的 `make` 实现。移植的软件通常需要特定的实现,例如 GNU `make`,在 FreeBSD 中称为 `gmake`。

如果端口使用 GNU make,请将 `gmake` 添加到 `USES` 中。

可以使用 `MAKE_CMD` 来引用端口的 Makefile 中 `USES` 设置配置的特定命令。仅在 `WRKSRC` 中的应用程序 Makefile 中使用 `MAKE_CMD` 来调用移植的软件期望的 `make` 实现。

如果端口是使用 imake 从 Imakefile 创建 Makefile 的 X 应用程序,请设置 `USES= imake`。有关更多详细信息,请参见 USES=imake 部分的 使用 USES

如果端口的源 Makefile 中使用除 `all` 之外的其他内容作为主构建目标,请相应地设置 `ALL_TARGET`。对于 `install` 和 `INSTALL_TARGET` 也是如此。

6.6.3. `configure` 脚本

如果端口使用 `configure` 脚本从 Makefile.in 生成 Makefile,请设置 `GNU_CONFIGURE=yes`。要为 `configure` 脚本提供额外的参数(默认参数是 `--prefix=${PREFIX} --infodir=${PREFIX}/${INFO_PATH} --mandir=${PREFIX}/man --build=${CONFIGURE_TARGET}`),请在 `CONFIGURE_ARGS` 中设置这些额外参数。可以使用 `CONFIGURE_ENV` 传递额外的环境变量。

表 1. 使用 `configure` 的端口的变量
变量含义

GNU_CONFIGURE

端口使用 `configure` 脚本准备构建。

HAS_CONFIGURE

与 `GNU_CONFIGURE` 相同,只是默认配置目标未添加到 `CONFIGURE_ARGS` 中。

CONFIGURE_ARGS

传递给 `configure` 脚本的额外参数。

CONFIGURE_ENV

要为 `configure` 脚本运行设置的额外环境变量。

CONFIGURE_TARGET

覆盖默认配置目标。默认值为 `${MACHINE_ARCH}-portbld-freebsd${OSREL}`。

6.6.4. 使用 `cmake`

对于使用 CMake 的端口,请定义 `USES= cmake`。

表 2. 使用 `cmake` 的端口的变量
变量含义

CMAKE_ARGS

要传递给 `cmake` 二进制文件的端口特定 CMake 标志。

CMAKE_ON

对于 `CMAKE_ON` 中的每个条目,都会将一个已启用的布尔值添加到 `CMAKE_ARGS` 中。请参见 CMAKE_ONCMAKE_OFF

CMAKE_OFF

对于 `CMAKE_OFF` 中的每个条目,都会将一个已禁用的布尔值添加到 `CMAKE_ARGS` 中。请参见 CMAKE_ONCMAKE_OFF

CMAKE_BUILD_TYPE

构建类型(CMake 预定义的构建配置文件)。默认值为 `Release`,如果设置了 `WITH_DEBUG`,则为 `Debug`。

CMAKE_SOURCE_PATH

源目录的路径。默认值为 `${WRKSRC}`。

CONFIGURE_ENV

要为 `cmake` 二进制文件设置的额外环境变量。

表 3. 用户可以为 `cmake` 构建定义的变量
变量含义

CMAKE_NOCOLOR

禁用彩色构建输出。默认情况下未设置,除非设置了 `BATCH` 或 `PACKAGE_BUILDING`。

CMake 支持以下构建配置文件:`Debug`、`Release`、`RelWithDebInfo` 和 `MinSizeRel`。`Debug` 和 `Release` 配置文件会尊重系统 `*FLAGS`,`RelWithDebInfo` 和 `MinSizeRel` 会将 `CFLAGS` 分别设置为 `-O2 -g` 和 `-Os -DNDEBUG`。`CMAKE_BUILD_TYPE` 的小写值将导出到 `PLIST_SUB`,并且如果端口安装了根据构建类型而定的 *.cmake 文件,则必须使用它(请参见 devel/kf5-kcrash 了解示例)。请注意,某些项目可能会定义自己的构建配置文件,或者通过在 CMakeLists.txt 中设置 `CMAKE_BUILD_TYPE` 来强制执行特定的构建类型。要使此类项目的端口尊重 `CFLAGS` 和 `WITH_DEBUG`,必须从这些文件中删除 `CMAKE_BUILD_TYPE` 定义。

大多数基于 CMake 的项目支持源外构建方法。端口的源外构建是默认设置。可以使用 `:insource` 后缀请求源内构建。对于源外构建,`CONFIGURE_WRKSRC`、`BUILD_WRKSRC` 和 `INSTALL_WRKSRC` 将设置为 `${WRKDIR}/.build`,并且此目录将用于保存配置和构建阶段中生成的所有文件,保持源目录完好无损。

示例 2. `USES= cmake` 示例

此代码片段演示了在端口中使用 CMake。通常不需要 `CMAKE_SOURCE_PATH`,但可以在源代码未位于顶层目录中,或者仅希望端口构建项目的一部分时设置。

USES=			cmake
CMAKE_SOURCE_PATH=	${WRKSRC}/subproject
示例 3. `CMAKE_ON` 和 `CMAKE_OFF`

将布尔值添加到 `CMAKE_ARGS` 时,最好使用 `CMAKE_ON` 和 `CMAKE_OFF` 变量。这

CMAKE_ON=	VAR1 VAR2
CMAKE_OFF=	VAR3

等效于

CMAKE_ARGS=	-DVAR1:BOOL=TRUE -DVAR2:BOOL=TRUE -DVAR3:BOOL=FALSE

这仅适用于 `CMAKE_ARGS` 的默认值。在 OPT_CMAKE_BOOLOPT_CMAKE_BOOL_OFF 中描述的帮助程序使用相同的语义,但用于可选值。

6.6.5. 使用 `scons`

如果端口使用 SCons,请定义 `USES=scons`。

要使第三方 SConstruct 尊重传递给 SCons 环境中的所有内容(即,最重要的是,`CC/CXX/CFLAGS/CXXFLAGS`),请修补 SConstruct,以便构建 `Environment` 的方式如下

env = Environment(**ARGUMENTS)

然后可以使用 `env.Append` 和 `env.Replace` 进行修改。

6.6.6. 使用 `cargo` 构建 Rust 应用程序

对于使用 Cargo 的端口,请定义 `USES=cargo`。

表 4. 用户可以为 `cargo` 构建定义的变量
变量默认描述

CARGO_CRATES

端口依赖的箱子列表。每个条目需要使用类似 `cratename-semver` 的格式,例如,`libc-0.2.40`。端口维护者可以使用 `make cargo-crates` 从 Cargo.lock 生成此列表。手动升级箱子版本是可行的,但要注意传递依赖。如果 `make cargo-crates` 生成的列表很大,则可以方便地将其放在顶层端口目录中的 `Makefile.crates` 文件中。如果存在,端口框架会自动获取该文件。这有助于保持主端口 Makefile 的大小可控。

CARGO_FEATURES

要构建的应用程序功能列表(以空格分隔的列表)。要停用所有默认功能,请将特殊标记 `--no-default-features` 添加到 `CARGO_FEATURES` 中。无需手动将其传递给 `CARGO_BUILD_ARGS`、`CARGO_INSTALL_ARGS` 和 `CARGO_TEST_ARGS`。

CARGO_CARGOTOML

${WRKSRC}/Cargo.toml

要使用的 Cargo.toml 的路径。

CARGO_CARGOLOCK

${WRKSRC}/Cargo.lock

要用于 `make cargo-crates` 的 Cargo.lock 的路径。如果需要,可以指定多个锁定文件。

CARGO_ENV

要传递给 Cargo 的环境变量列表,类似于 `MAKE_ENV`。

RUSTFLAGS

要传递给 Rust 编译器的标志。

CARGO_CONFIGURE

yes

使用默认的 `do-configure`。

CARGO_UPDATE_ARGS

在配置阶段传递给 Cargo 的额外参数。可以使用 `cargo update --help` 查看有效参数。

CARGO_BUILDDEP

yes

lang/rust 上添加构建依赖关系。

CARGO_CARGO_BIN

${LOCALBASE}/bin/cargo

cargo 二进制文件的路径。

CARGO_BUILD

yes

使用默认的 do-build

CARGO_BUILD_ARGS

在构建阶段传递给 Cargo 的额外参数。可以使用 cargo build --help 查看有效参数。

CARGO_INSTALL

yes

使用默认的 do-install

CARGO_INSTALL_ARGS

在安装阶段传递给 Cargo 的额外参数。可以使用 cargo install --help 查看有效参数。

CARGO_INSTALL_PATH

.

要安装的板条箱的路径。这将通过 --path 参数传递给 cargo install。当指定多个路径时,cargo install 会运行多次。

CARGO_TEST

yes

使用默认的 do-test

CARGO_TEST_ARGS

在测试阶段传递给 Cargo 的额外参数。可以使用 cargo test --help 查看有效参数。

CARGO_TARGET_DIR

${WRKDIR}/target

Cargo 输出目录的路径。

CARGO_DIST_SUBDIR

rust/crates

相对于 DISTDIR 的目录,板条箱分发文件将存储在此目录中。

CARGO_VENDOR_DIR

${WRKSRC}/cargo-crates

供应商目录的路径,所有板条箱都将提取到此目录中。尝试将此目录保留在 PATCH_WRKSRC 下,以便可以轻松地应用补丁。

CARGO_USE_GITHUB

no

启用通过 GH_TUPLE 获取锁定到 GitHub 上特定 Git 提交的板条箱。这将尝试修补 WRKDIR 下的所有 Cargo.toml 文件,以指向离线源,而不是在构建期间从 Git 存储库中获取它们。

CARGO_USE_GITLAB

no

CARGO_USE_GITHUB 相同,但适用于 GitLab 实例和 GL_TUPLE

示例 4. 为简单的 Rust 应用程序创建端口

创建基于 Cargo 的端口是一个三阶段过程。首先,我们需要提供一个端口模板,用于获取应用程序分发文件。

PORTNAME=	tokei
DISTVERSIONPREFIX=	v
DISTVERSION=	7.0.2
CATEGORIES=	devel

MAINTAINER=	[email protected]
COMMENT=	Display statistics about your code
WWW=		https://github.com/XAMPPRocky/tokei/

USES=		cargo
USE_GITHUB=	yes
GH_ACCOUNT=	Aaronepower

.include <bsd.port.mk>

生成一个初始的 distinfo

% make makesum
=> Aaronepower-tokei-v7.0.2_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://codeload.github.com/Aaronepower/tokei/tar.gz/v7.0.2?dummy=/Aaronepower-tokei-v7.0.2_GH0.tar.gz
fetch: https://codeload.github.com/Aaronepower/tokei/tar.gz/v7.0.2?dummy=/Aaronepower-tokei-v7.0.2_GH0.tar.gz: size of remote file is not known
Aaronepower-tokei-v7.0.2_GH0.tar.gz                     45 kB  239 kBps 00m00s

现在分发文件已准备好使用,我们可以继续从捆绑的 Cargo.lock 文件中提取板条箱依赖项。

% make cargo-crates
CARGO_CRATES=   aho-corasick-0.6.4 \
                ansi_term-0.11.0 \
                arrayvec-0.4.7 \
                atty-0.2.9 \
                bitflags-1.0.1 \
                byteorder-1.2.2 \
                [...]

此命令的输出需要直接粘贴到 Makefile 中。

PORTNAME=	tokei
DISTVERSIONPREFIX=	v
DISTVERSION=	7.0.2
CATEGORIES=	devel

MAINTAINER=	[email protected]
COMMENT=	Display statistics about your code
WWW=		https://github.com/XAMPPRocky/tokei/

USES=		cargo
USE_GITHUB=	yes
GH_ACCOUNT=	Aaronepower

CARGO_CRATES=   aho-corasick-0.6.4 \
                ansi_term-0.11.0 \
                arrayvec-0.4.7 \
                atty-0.2.9 \
                bitflags-1.0.1 \
                byteorder-1.2.2 \
                [...]

.include <bsd.port.mk>

distinfo 需要重新生成以包含所有板条箱分发文件。

% make makesum
=> rust/crates/aho-corasick-0.6.4.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://crates.io/api/v1/crates/aho-corasick/0.6.4/download?dummy=/rust/crates/aho-corasick-0.6.4.tar.gz
rust/crates/aho-corasick-0.6.4.tar.gz         100% of   24 kB 6139 kBps 00m00s
=> rust/crates/ansi_term-0.11.0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://crates.io/api/v1/crates/ansi_term/0.11.0/download?dummy=/rust/crates/ansi_term-0.11.0.tar.gz
rust/crates/ansi_term-0.11.0.tar.gz           100% of   16 kB   21 MBps 00m00s
=> rust/crates/arrayvec-0.4.7.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://crates.io/api/v1/crates/arrayvec/0.4.7/download?dummy=/rust/crates/arrayvec-0.4.7.tar.gz
rust/crates/arrayvec-0.4.7.tar.gz             100% of   22 kB 3237 kBps 00m00s
=> rust/crates/atty-0.2.9.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://crates.io/api/v1/crates/atty/0.2.9/download?dummy=/rust/crates/atty-0.2.9.tar.gz
rust/crates/atty-0.2.9.tar.gz                 100% of 5898  B   81 MBps 00m00s
=> rust/crates/bitflags-1.0.1.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
[...]

现在端口已准备好进行测试构建和进一步调整,例如创建 plist、编写描述、添加许可证信息、选项等,就像平常一样。

如果您不在像 poudriere 这样的干净环境中测试您的端口,请记住在进行任何测试之前运行 make clean

示例 5. 启用其他应用程序功能

某些应用程序在其 Cargo.toml 文件中定义了其他功能。可以通过在端口中设置 CARGO_FEATURES 来编译它们。

这里,我们启用 Tokei 的 jsonyaml 功能。

CARGO_FEATURES=	json yaml
示例 6. 将应用程序功能编码为端口选项

Cargo.toml 文件中 [features] 部分的示例如下所示:

[features]
pulseaudio_backend = ["librespot-playback/pulseaudio-backend"]
portaudio_backend = ["librespot-playback/portaudio-backend"]
default = ["pulseaudio_backend"]

pulseaudio_backend 是一个默认功能。它始终处于启用状态,除非我们通过将 --no-default-features 添加到 CARGO_FEATURES 中来明确关闭默认功能。在这里,我们将 portaudio_backendpulseaudio_backend 功能转换为端口选项。

CARGO_FEATURES=	--no-default-features

OPTIONS_DEFINE=	PORTAUDIO PULSEAUDIO

PORTAUDIO_VARS=		CARGO_FEATURES+=portaudio_backend
PULSEAUDIO_VARS=	CARGO_FEATURES+=pulseaudio_backend
示例 7. 列出板条箱许可证

板条箱有自己的许可证。在向端口添加 LICENSE 块时,了解这些许可证非常重要(请参阅 许可证)。辅助目标 cargo-crates-licenses 将尝试列出 CARGO_CRATES 中定义的所有板条箱的许可证。

% make cargo-crates-licenses
aho-corasick-0.6.4  Unlicense/MIT
ansi_term-0.11.0    MIT
arrayvec-0.4.7      MIT/Apache-2.0
atty-0.2.9          MIT
bitflags-1.0.1      MIT/Apache-2.0
byteorder-1.2.2     Unlicense/MIT
[...]

make cargo-crates-licenses 输出的许可证名称是 SPDX 2.1 许可证表达式,它与端口框架中定义的许可证名称不匹配。它们需要转换为来自 预定义许可证列表 的名称。

6.6.7. 使用 meson

对于使用 Meson 的端口,请定义 USES=meson

表 5. 使用 meson 的端口的变量
变量描述

MESON_ARGS

要传递给 meson 二进制文件的端口特定 Meson 标记。

MESON_BUILD_DIR

相对于 WRKSRC 的构建目录的路径。默认值为 _build

示例 8. USES=meson 示例

此代码段演示了在端口中使用 Meson。

USES=		meson
MESON_ARGS=	-Dfoo=enabled

6.6.8. 构建 Go 应用程序

对于使用 Go 的端口,请定义 USES=go。请参阅 go 以获取可以设置以控制构建过程的变量列表。

示例 9. 为基于 Go 模块的应用程序创建端口

在大多数情况下,将 GO_MODULE 变量设置为 go.mod 文件中 module 指令指定的值就足够了。

PORTNAME=       hey
DISTVERSIONPREFIX=	v
DISTVERSION=    0.1.4
CATEGORIES=     benchmarks

MAINTAINER=     [email protected]
COMMENT=        Tiny program that sends some load to a web application
WWW=            https://github.com/rakyll/hey/

LICENSE=        APACHE20
LICENSE_FILE=   ${WRKSRC}/LICENSE

USES=           go:modules
GO_MODULE=      github.com/rakyll/hey

PLIST_FILES=    bin/hey

.include <bsd.port.mk>

如果“简单”方法不适用或需要更多地控制依赖项,则下面介绍了完整的移植过程。

创建基于 Go 的端口是一个五阶段过程。首先,我们需要提供一个端口模板,用于获取应用程序分发文件。

PORTNAME=	ghq
DISTVERSIONPREFIX=	v
DISTVERSION=	0.12.5
CATEGORIES=	devel

MAINTAINER=	[email protected]
COMMENT=	Remote repository management made easy
WWW=		https://github.com/x-motemen/ghq/

USES=		go:modules
USE_GITHUB=	yes
GH_ACCOUNT=	motemen

.include <bsd.port.mk>

生成一个初始的 distinfo

% make makesum
===>  License MIT accepted by the user
=> motemen-ghq-v0.12.5_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://codeload.github.com/motemen/ghq/tar.gz/v0.12.5?dummy=/motemen-ghq-v0.12.5_GH0.tar.gz
fetch: https://codeload.github.com/motemen/ghq/tar.gz/v0.12.5?dummy=/motemen-ghq-v0.12.5_GH0.tar.gz: size of remote file is not known
motemen-ghq-v0.12.5_GH0.tar.gz                          32 kB  177 kBps    00s

现在分发文件已准备好使用,我们可以提取所需的 Go 模块依赖项。此步骤需要安装 ports-mgmt/modules2tuple

% make gomod-vendor
[...]
GH_TUPLE=	\
		Songmu:gitconfig:v0.0.2:songmu_gitconfig/vendor/github.com/Songmu/gitconfig \
		daviddengcn:go-colortext:186a3d44e920:daviddengcn_go_colortext/vendor/github.com/daviddengcn/go-colortext \
		go-yaml:yaml:v2.2.2:go_yaml_yaml/vendor/gopkg.in/yaml.v2 \
		golang:net:3ec191127204:golang_net/vendor/golang.org/x/net \
		golang:sync:112230192c58:golang_sync/vendor/golang.org/x/sync \
		golang:xerrors:3ee3066db522:golang_xerrors/vendor/golang.org/x/xerrors \
		motemen:go-colorine:45d19169413a:motemen_go_colorine/vendor/github.com/motemen/go-colorine \
		urfave:cli:v1.20.0:urfave_cli/vendor/github.com/urfave/cli

此命令的输出需要直接粘贴到 Makefile 中。

PORTNAME=	ghq
DISTVERSIONPREFIX=	v
DISTVERSION=	0.12.5
CATEGORIES=	devel

MAINTAINER=	[email protected]
COMMENT=	Remote repository management made easy
WWW=		https://github.com/x-motemen/ghq/

USES=		go:modules
USE_GITHUB=	yes
GH_ACCOUNT=	motemen
GH_TUPLE=	Songmu:gitconfig:v0.0.2:songmu_gitconfig/vendor/github.com/Songmu/gitconfig \
		daviddengcn:go-colortext:186a3d44e920:daviddengcn_go_colortext/vendor/github.com/daviddengcn/go-colortext \
		go-yaml:yaml:v2.2.2:go_yaml_yaml/vendor/gopkg.in/yaml.v2 \
		golang:net:3ec191127204:golang_net/vendor/golang.org/x/net \
		golang:sync:112230192c58:golang_sync/vendor/golang.org/x/sync \
		golang:xerrors:3ee3066db522:golang_xerrors/vendor/golang.org/x/xerrors \
		motemen:go-colorine:45d19169413a:motemen_go_colorine/vendor/github.com/motemen/go-colorine \
		urfave:cli:v1.20.0:urfave_cli/vendor/github.com/urfave/cli

.include <bsd.port.mk>

distinfo 需要重新生成以包含所有分发文件。

% make makesum
=> Songmu-gitconfig-v0.0.2_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://codeload.github.com/Songmu/gitconfig/tar.gz/v0.0.2?dummy=/Songmu-gitconfig-v0.0.2_GH0.tar.gz
fetch: https://codeload.github.com/Songmu/gitconfig/tar.gz/v0.0.2?dummy=/Songmu-gitconfig-v0.0.2_GH0.tar.gz: size of remote file is not known
Songmu-gitconfig-v0.0.2_GH0.tar.gz                    5662  B  936 kBps    00s
=> daviddengcn-go-colortext-186a3d44e920_GH0.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://codeload.github.com/daviddengcn/go-colortext/tar.gz/186a3d44e920?dummy=/daviddengcn-go-colortext-186a3d44e920_GH0.tar.gz
fetch: https://codeload.github.com/daviddengcn/go-colortext/tar.gz/186a3d44e920?dummy=/daviddengcn-go-colortext-186a3d44e920_GH0.tar.gz: size of remote file is not known
daviddengcn-go-colortext-186a3d44e920_GH0.tar.        4534  B 1098 kBps    00s
[...]

现在端口已准备好进行测试构建和进一步调整,例如创建 plist、编写描述、添加许可证信息、选项等,就像平常一样。

如果您不在像 poudriere 这样的干净环境中测试您的端口,请记住在进行任何测试之前运行 make clean

示例 10. 设置输出二进制文件名或安装路径

某些端口需要将生成的二进制文件安装在不同的名称下或安装到默认的 ${PREFIX}/bin 目录之外的路径。这可以通过使用 GO_TARGET 元组语法来实现,例如:

GO_TARGET=  ./cmd/ipfs:ipfs-go

ipfs 二进制文件安装为 ${PREFIX}/bin/ipfs-go,以及

GO_TARGET=  ./dnscrypt-proxy:${PREFIX}/sbin/dnscrypt-proxy

dnscrypt-proxy 安装到 ${PREFIX}/sbin

6.6.9. 使用 cabal 构建 Haskell 应用程序

对于使用 Cabal 的端口,构建系统定义 USES=cabal。请参阅 cabal 以获取可以设置以控制构建过程的变量列表。

示例 11. 为 Hackage 托管的 Haskell 应用程序创建端口

在准备 Haskell Cabal 端口时,需要 devel/hs-cabal-installports-mgmt/hs-cabal2tuple 程序,因此请确保事先安装了它们。首先,我们需要定义允许 cabal-install 获取软件包分发文件的通用端口变量。

PORTNAME=	ShellCheck
DISTVERSION=	0.6.0
CATEGORIES=	devel

MAINTAINER=	[email protected]
COMMENT=	Shell script analysis tool
WWW=		https://www.shellcheck.net/

USES=		cabal

.include <bsd.port.mk>

此最小 Makefile 使用 cabal-extract 辅助目标获取分发文件。

% make cabal-extract
[...]
Downloading the latest package list from hackage.haskell.org
cabal get ShellCheck-0.6.0
Downloading  ShellCheck-0.6.0
Downloaded   ShellCheck-0.6.0
Unpacking to ShellCheck-0.6.0/

现在我们已经在 ${WRKSRC} 中有了 ShellCheck.cabal 软件包描述文件,我们可以使用 cabal-configure 生成构建计划。

% make cabal-configure
[...]
Resolving dependencies...
Build profile: -w ghc-8.10.7 -O1
In order, the following would be built (use -v for more details):
 - Diff-0.4.1 (lib) (requires download & build)
 - OneTuple-0.3.1 (lib) (requires download & build)
[...]

完成之后,可以生成所需依赖项的列表。

% make make-use-cabal
USE_CABAL=	QuickCheck-2.12.6.1 \
		hashable-1.3.0.0 \
		integer-logarithms-1.0.3 \
[...]

Haskell 软件包可能包含修订版,就像 FreeBSD 端口一样。修订版可能会影响 .cabal 文件。请注意 _ 符号之后的附加版本号。将新生成的 USE_CABAL 列表替换为旧列表。

最后,distinfo 需要重新生成以包含所有分发文件。

% make makesum
=> ShellCheck-0.6.0.tar.gz doesn't seem to exist in /usr/local/poudriere/ports/git/distfiles/cabal.
=> Attempting to fetch https://hackage.haskell.org/package/ShellCheck-0.6.0/ShellCheck-0.6.0.tar.gz
ShellCheck-0.6.0.tar.gz                                136 kB  642 kBps    00s
=> QuickCheck-2.12.6.1/QuickCheck-2.12.6.1.tar.gz doesn't seem to exist in /usr/local/poudriere/ports/git/distfiles/cabal.
=> Attempting to fetch https://hackage.haskell.org/package/QuickCheck-2.12.6.1/QuickCheck-2.12.6.1.tar.gz
QuickCheck-2.12.6.1/QuickCheck-2.12.6.1.tar.gz          65 kB  361 kBps    00s
[...]

现在端口已准备好进行测试构建和进一步调整,例如创建 plist、编写描述、添加许可证信息、选项等,就像平常一样。

如果您不在像 poudriere 这样的干净环境中测试您的端口,请记住在进行任何测试之前运行 make clean

某些 Haskell 端口在 share/${PORTNAME} 下安装各种数据文件。对于这种情况,端口侧需要特殊处理。端口应定义 CABAL_WRAPPER_SCRIPTS 选项,列出将使用数据文件的每个可执行文件。此外,在极少数情况下,移植的程序使用其他 Haskell 软件包的数据文件,在这种情况下,FOO_DATADIR_VARS 可以派上用场。

示例 12. 处理 Haskell 端口中的数据文件

devel/hs-profiteur 是一个 Haskell 应用程序,它生成一个包含某些内容的单页 HTML 文件。

PORTNAME=	profiteur

[...]

USES=		cabal

USE_CABAL=	OneTuple-0.3.1_2 \
		QuickCheck-2.14.2 \
		[...]

.include <bsd.port.mk>

它在 share/profiteur 下安装 HTML 模板,因此我们需要添加 CABAL_WRAPPER_SCRIPTS 选项。

[...]

USE_CABAL=	OneTuple-0.3.1_2 \
		QuickCheck-2.14.2 \
		[...]


CABAL_WRAPPER_SCRIPTS=		${CABAL_EXECUTABLES}

.include <bsd.port.mk>

该程序还尝试访问 jquery.js 文件,该文件是 js-jquery-3.3.1 Haskell 软件包的一部分。为了找到该文件,我们需要让包装器脚本也查找 share/profiteur 中的 js-jquery 数据文件。我们使用 profiteur_DATADIR_VARS 来实现这一点。

[...]

CABAL_WRAPPER_SCRIPTS=		${CABAL_EXECUTABLES}
profiteur_DATADIR_VARS=		js-jquery

.include <bsd.port.mk>

现在,端口将把实际的二进制文件安装到 libexec/cabal/profiteur 中,并将脚本安装到 bin/profiteur 中。

除了运行程序并检查一切是否正常之外,没有简单的方法可以找到 FOO_DATADIR_VARS 选项的适当值。幸运的是,使用 FOO_DATADIR_VARS 的需求非常罕见。

移植复杂 Haskell 程序时的另一个特殊情况是 cabal.project 文件中存在 VCS 依赖项。

示例 13. 移植具有 VCS 依赖项的 Haskell 应用程序

net-p2p/cardano-node 是一个非常复杂的软件。在其 cabal.project 文件中,有很多类似于以下内容的块:

[...]
source-repository-package
  type: git
  location: https://github.com/input-output-hk/cardano-crypto
  tag: f73079303f663e028288f9f4a9e08bcca39a923e
[...]

cabal 在构建过程中会自动拉取类型为 source-repository-package 的依赖项。不幸的是,这会在 fetch 阶段之后使用网络。端口框架不允许这样做。这些源需要在端口的 Makefile 中列出。make-use-cabal 辅助目标可以简化托管在 GitHub 上的软件包的操作。在通常的 cabal-extractcabal-configure 之后运行此目标,不仅会生成 USE_CABAL 选项,还会生成 GH_TUPLE

% make make-use-cabal
USE_CABAL=	Diff-0.4.1 \
		Glob-0.10.2_3 \
		HUnit-1.6.2.0 \
		[...]

GH_TUPLE=		input-output-hk:cardano-base:0f3a867493059e650cda69e20a5cbf1ace289a57:cardano_base/dist-newstyle/src/cardano-b_-c8db9876882556ed \
		input-output-hk:cardano-crypto:f73079303f663e028288f9f4a9e08bcca39a923e:cardano_crypto/dist-newstyle/src/cardano-c_-253fd88117badd8f \
		[...]

将来自 make-use-cabalGH_TUPLE 项目与其他项目分开可能很有用,以便于更新端口。

GH_TUPLE=	input-output-hk:cardano-base:0f3a867493059e650cda69e20a5cbf1ace289a57:cardano_base/dist-newstyle/src/cardano-b_-c8db9876882556ed \
		input-output-hk:cardano-crypto:f73079303f663e028288f9f4a9e08bcca39a923e:cardano_crypto/dist-newstyle/src/cardano-c_-253fd88117badd8f \
		[...]

GH_TUPLE+=	bitcoin-core:secp256k1:ac83be33d0956faf6b7f61a60ab524ef7d6a473a:secp

具有 VCS 依赖项的 Haskell 端口目前还需要以下 hack。

BINARY_ALIAS=	git=true

6.7. 使用 GNU Autotools

如果端口需要任何 GNU Autotools 软件,请添加 USES=autoreconf。有关更多信息,请参阅 autoreconf

6.8. 使用 GNU gettext

6.8.1. 基本用法

如果端口需要 gettext,请设置 USES= gettext,并且端口将从 devel/gettext 继承对 libintl.so 的依赖关系。gettext 用法的其他值列在 USES=gettext 中。

一个相当常见的案例是使用 gettextconfigure 的端口。通常情况下,GNU configure 应该能够自动定位 gettext

USES=	gettext
GNU_CONFIGURE=	yes

如果它始终无法定位,则可以使用 localbaseCPPFLAGSLDFLAGS 中传递有关 gettext 位置的提示,如下所示:

USES=	gettext localbase:ldflags
GNU_CONFIGURE=	yes

6.8.2. 可选用法

某些软件产品允许禁用 NLS。例如,通过向 configure 传递 --disable-nls 来禁用 NLS。在这种情况下,端口必须有条件地使用 gettext,具体取决于 NLS 选项的状态。对于低到中等复杂度的端口,可以使用以下习惯用法:

GNU_CONFIGURE=		yes

OPTIONS_DEFINE=		NLS
OPTIONS_SUB=		yes

NLS_USES=		gettext
NLS_CONFIGURE_ENABLE=	nls

.include <bsd.port.mk>

或使用较旧的选项使用方式:

GNU_CONFIGURE=		yes

OPTIONS_DEFINE=		NLS

.include <bsd.port.options.mk>

.if ${PORT_OPTIONS:MNLS}
USES+=			gettext
PLIST_SUB+=		NLS=""
.else
CONFIGURE_ARGS+=	--disable-nls
PLIST_SUB+=		NLS="@comment "
.endif

.include <bsd.port.mk>

待办事项列表中的下一项是安排将消息目录文件有条件地包含在打包列表中。此任务的 Makefile 部分已由习惯用法提供。在有关 高级 pkg-plist 实践 的部分中对此进行了说明。简而言之,在 pkg-plist 中,%%NLS%% 的每次出现都将被替换为“`@comment `”,如果 NLS 被禁用,则替换为一个空字符串,如果 NLS 被启用。因此,如果 NLS 被关闭,则以 `%%NLS%%` 为前缀的行将变成最终打包列表中的简单注释;否则,将只删除前缀。然后在 pkg-plist 中的每个消息目录文件路径之前插入 %%NLS%%。例如:

%%NLS%%share/locale/fr/LC_MESSAGES/foobar.mo
%%NLS%%share/locale/no/LC_MESSAGES/foobar.mo

在高复杂度的案例中,可能需要更高级的技术,例如 动态打包列表生成

6.8.3. 处理消息目录

关于安装消息目录文件,需要注意一点。这些文件位于 LOCALBASE/share/locale 下的目录,不能被端口创建和删除。最流行的语言的目录都在 PORTSDIR/Templates/BSD.local.dist 中列出。许多其他语言的目录由 devel/gettext 端口控制。查看它的 pkg-plist 文件,看看该端口是否要为一种独特的语言安装消息目录文件。

6.9. 使用 Perl

如果 MASTER_SITES 设置为 CPAN,通常会自动选择正确的子目录。如果默认子目录错误,可以使用 CPAN/Module 来更改它。 MASTER_SITES 也可以设置为旧的 MASTER_SITE_PERL_CPAN,然后 MASTER_SITE_SUBDIR 的首选值为顶级层次结构名称。例如,p5-Module-Name 的推荐值为 Module。可以在 cpan.org 上检查顶级层次结构。这样可以使端口在模块作者更改时继续工作。

此规则的例外情况是,当相关目录不存在或 distfile 在该目录中不存在时。在这种情况下,可以使用作者的 ID 作为 MASTER_SITE_SUBDIR。可以使用 CPAN:AUTHOR 宏,它将被转换为散列的作者目录。例如,CPAN:AUTHOR 将被转换为 authors/id/A/AU/AUTHOR

当端口需要 Perl 支持时,必须设置 USES=perl5,并使用 perl5 USES 说明 中描述的可选 USE_PERL5

表 6. 使用 Perl 的端口的只读变量
只读变量含义

PERL

Perl 5 解释器的完整路径,无论是在系统中还是从端口中安装,但不包括版本号。当软件需要 Perl 解释器路径时,使用它。要替换脚本中的 "#!" 行,请使用 shebangfix

PERL_VERSION

安装的 Perl 版本的完整版本(例如,5.8.9)。

PERL_LEVEL

安装的 Perl 版本,以 MNNNPP 格式的整数表示(例如,500809)。

PERL_ARCH

Perl 存储与体系结构相关的库的位置。默认为 ${ARCH}-freebsd

PERL_PORT

安装的 Perl 端口的名称(例如,perl5)。

SITE_PERL

特定于站点的 Perl 包所在的目录名称。此值将添加到 PLIST_SUB 中。

没有官方网站的 Perl 模块端口必须在 Makefile 的 WWW 行中链接到 cpan.org。首选的 URL 格式是 https://search.cpan.org/dist/Module-Name/(包括尾部斜杠)。

不要在依赖项声明中使用 ${SITE_PERL}。这样做会假设已经包含了 perl5.mk,而这并非总是如此。如果此端口的文件在升级时被移动,那么依赖此端口的端口将具有不正确的依赖项。声明 Perl 模块依赖项的正确方法如下所示。

示例 14. Perl 依赖项示例
p5-IO-Tee>=0.64:devel/p5-IO-Tee

对于安装手册页的 Perl 端口,可以使用 pkg-plist 中的宏 PERL5_MAN3PERL5_MAN1。例如,

lib/perl5/5.14/man/man1/event.1.gz
lib/perl5/5.14/man/man3/AnyEvent::I3.3.gz

可以替换为

%%PERL5_MAN1%%/event.1.gz
%%PERL5_MAN3%%/AnyEvent::I3.3.gz

其他部分(PERL5_MAN_x_ 中的 x249)没有 PERL5_MAN_x_ 宏,因为这些部分被安装在常规目录中。

示例 15. 一个只需要 Perl 才能构建的端口

由于默认的 USE_PERL5 值为 build 和 run,因此将其设置为

USES=		perl5
USE_PERL5=	build
示例 16. 一个也需要 Perl 才能进行修补的端口

有时,使用 sed(1) 进行修补是不够的。当使用 perl(1) 更容易时,请使用

USES=		perl5
USE_PERL5=	patch build run
示例 17. 需要 ExtUtils::MakeMaker 才能构建的 Perl 模块

大多数 Perl 模块都带有一个 Makefile.PL 配置脚本。在这种情况下,请设置

USES=		perl5
USE_PERL5=	configure
示例 18. 需要 Module::Build 才能构建的 Perl 模块

当 Perl 模块带有一个 Build.PL 配置脚本时,它可能需要 Module::Build,在这种情况下,请设置

USES=		perl5
USE_PERL5=	modbuild

如果它需要 Module::Build::Tiny,请设置

USES=		perl5
USE_PERL5=	modbuildtiny

6.10. 使用 X11

6.10.1. X.Org 组件

端口集合中提供的 X11 实现是 X.Org。如果应用程序依赖于 X 组件,请添加 USES= xorg 并将 USE_XORG 设置为所需的组件列表。完整的列表可以在 xorg 中找到。

Mesa 项目是提供免费 OpenGL 实现的努力。要指定对该项目各种组件的依赖关系,请使用 USES= glUSE_GL。有关可用组件的完整列表,请参见 gl。为了向后兼容,yes 的值映射到 glu

示例 19. USE_XORG 示例
USES=		gl xorg
USE_GL=		glu
USE_XORG=	xrender xft xkbfile xt xaw
表 7. 使用 X 的端口的变量

USES= imake

该端口使用 imake

XMKMF

如果 xmkmf 不在 PATH 中,则将其设置为 xmkmf 的路径。默认为 xmkmf -a

示例 20. 使用 X11 相关变量
# Use some X11 libraries
USES=		xorg
USE_XORG=	x11 xpm

6.10.2. 需要 Motif 的端口

如果端口需要 Motif 库,请在 Makefile 中定义 USES= motif。默认的 Motif 实现是 x11-toolkits/open-motif。用户可以通过在他们的 make.conf 中设置 WANT_LESSTIF 来选择 x11-toolkits/lesstif。类似地,可以通过在 make.conf 中设置 WANT_OPEN_MOTIF_DEVEL 来选择 x11-toolkits/open-motif-devel

MOTIFLIB 将由 motif.mk 设置,以引用适当的 Motif 库。请修补端口的源代码,以便在原始 MakefileImakefile 中引用 Motif 库的任何地方使用 ${MOTIFLIB}

有两种常见情况

  • 如果端口在 MakefileImakefile 中将 Motif 库引用为 -lXm,请用 ${MOTIFLIB} 替换它。

  • 如果端口在 Imakefile 中使用 XmClientLibs,请将其更改为 ${MOTIFLIB} ${XTOOLLIB} ${XLIB}

请注意,MOTIFLIB 通常扩展为 -L/usr/local/lib -lXm -lXp/usr/local/lib/libXm.a,因此不需要在前面添加 -L-l

6.10.3. X11 字体

如果端口为 X 窗口系统安装字体,请将它们放在 LOCALBASE/lib/X11/fonts/local 中。

6.10.4. 使用 Xvfb 获取虚拟 DISPLAY

某些应用程序需要一个工作的 X11 显示才能成功编译。这对无头运行的机器来说是一个问题。当使用此变量时,构建基础结构将启动虚拟帧缓冲区 X 服务器。然后将工作的 DISPLAY 传递给构建。有关可能的参数,请参见 USES=display

USES=	display

6.10.5. 桌面条目

桌面条目(Freedesktop 标准)提供了一种方法,可以在安装新程序时自动调整桌面功能,而无需用户干预。例如,新安装的程序会自动出现在兼容桌面环境的应用程序菜单中。桌面条目起源于 GNOME 桌面环境,但现在已成为一种标准,也适用于 KDE 和 Xfce。这种自动化功能为用户带来了真正的益处,并且鼓励为可以在桌面环境中使用的应用程序创建桌面条目。

6.10.5.1. 使用预定义的 .desktop 文件

包含预定义 *.desktop 的端口必须在 pkg-plist 中包含这些文件,并将它们安装在 $LOCALBASE/share/applications 目录中。 INSTALL_DATA 可用于安装这些文件。

6.10.5.2. 更新桌面数据库

如果端口在其 portname.desktop 中有 MimeType 条目,则必须在安装和卸载后更新桌面数据库。为此,请定义 USES= desktop-file-utils。

6.10.5.3. 使用 DESKTOP_ENTRIES 创建桌面条目

可以通过使用 DESKTOP_ENTRIES 轻松地为应用程序创建桌面条目。系统会自动创建一个名为 name.desktop 的文件,并将其安装并添加到 pkg-plist 中。语法为

DESKTOP_ENTRIES=	"NAME" "COMMENT" "ICON" "COMMAND" "CATEGORY" StartupNotify

可以在 Freedesktop 网站 上找到可能的类别列表。StartupNotify 指示应用程序是否与启动通知兼容。这些通常是在鼠标指针、菜单或面板上显示的图形指示器,例如时钟,以便在程序启动时给用户一个指示。与启动通知兼容的程序在启动后会清除指示器。与启动通知不兼容的程序永远不会清除指示器(可能会让用户感到困惑和恼怒),因此必须将 StartupNotify 设置为 false,这样指示器就不会显示。

示例

DESKTOP_ENTRIES=	"ToME" "Roguelike game based on JRR Tolkien's work" \
			"${DATADIR}/xtra/graf/tome-128.png" \
			"tome -v -g" "Application;Game;RolePlaying;" \
			false

DESKTOP_ENTRIES 安装在 DESKTOPDIR 变量指向的目录中。DESKTOPDIR 默认为 ${PREFIX}/share/applications

6.11. 使用 GNOME

6.11.1. 简介

本章介绍端口使用的 GNOME 框架。该框架可以大致分为基础组件、GNOME 桌面组件,以及一些简化端口维护人员工作的特殊宏。

6.11.2. 使用 USE_GNOME

将此变量添加到端口中,允许使用 bsd.gnome.mk 中定义的宏和组件。 bsd.gnome.mk 中的代码添加了所需的构建时、运行时或库依赖项,或特殊文件的处理。FreeBSD 上的 GNOME 应用程序使用 USE_GNOME 基础结构。包含所有所需的组件,以空格分隔的列表形式。USE_GNOME 组件分为以下虚拟列表:基本组件、GNOME 3 组件和旧版组件。如果端口只需要 GTK3 库,这是定义它的最短方式

USE_GNOME=	gtk30

USE_GNOME 组件会自动添加它们所需的依赖项。请参阅 GNOME 组件,以获取所有 USE_GNOME 组件的完整列表,以及它们隐含的其他组件及其依赖项。

以下是一个使用本文档中概述的许多技术的 GNOME 端口的示例 Makefile。请将其用作创建新端口的指南。

PORTNAME=	regexxer
DISTVERSION=	0.10
CATEGORIES=	devel textproc gnome
MASTER_SITES=	GNOME

MAINTAINER=	[email protected]
COMMENT=	Interactive tool for performing search and replace operations
WWW=		http://regexxer.sourceforge.net/

USES=		gettext gmake localbase:ldflags pathfix pkgconfig tar:xz
GNU_CONFIGURE=	yes
USE_GNOME=	gnomeprefix intlhack gtksourceviewmm3

GLIB_SCHEMAS=	org.regexxer.gschema.xml

.include <bsd.port.mk>

USE_GNOME 宏不带任何参数,不会向端口添加任何依赖项。USE_GNOME 不能在 bsd.port.pre.mk 之后设置。

6.11.3. 变量

本节介绍了哪些宏可用以及如何使用它们,就像在上面的示例中一样。GNOME 组件 提供了更深入的解释。要使用这些宏,必须设置 USE_GNOME

GLIB_SCHEMAS

端口安装的所有 glib 模式文件列表。该宏将文件添加到端口 plist,并在安装和卸载时处理这些文件的注册。

glib 模式文件是用 XML 编写的,以 gschema.xml 扩展名结尾。它们安装在 share/glib-2.0/schemas/ 目录中。这些模式文件包含所有应用程序配置值及其默认设置。应用程序使用的实际数据库由 glib-compile-schema 构建,该程序由 GLIB_SCHEMAS 宏运行。

GLIB_SCHEMAS=foo.gschema.xml

不要将 glib 模式添加到 pkg-plist。如果它们列在 pkg-plist 中,它们将不会被注册,应用程序可能无法正常工作。

GCONF_SCHEMAS

列出所有 gconf 模式文件。该宏将模式文件添加到端口 plist,并在安装和卸载时处理它们的注册。

GConf 是一个基于 XML 的数据库,几乎所有 GNOME 应用程序都使用它来存储其设置。这些文件安装到 etc/gconf/schemas 目录中。该数据库由安装的模式文件定义,这些模式文件用于生成 %gconf.xml 键文件。对于端口安装的每个模式文件,在 Makefile 中必须有一项条目

GCONF_SCHEMAS=my_app.schemas my_app2.schemas my_app3.schemas

Gconf 模式列在 GCONF_SCHEMAS 宏中,而不是 pkg-plist 中。如果它们列在 pkg-plist 中,它们将不会被注册,应用程序可能无法正常工作。

INSTALLS_OMF

开源元数据框架 (OMF) 文件通常由 GNOME 2 应用程序使用。这些文件包含应用程序帮助文件信息,需要 ScrollKeeper/rarian 进行特殊处理。为了在从软件包安装 GNOME 应用程序时正确注册 OMF 文件,请确保 omf 文件列在 pkg-plist 中,并且端口 Makefile 定义了 INSTALLS_OMF

INSTALLS_OMF=yes

设置后,bsd.gnome.mk 会自动扫描 pkg-plist 并为每个 .omf 添加适当的 @exec@unexec 指令,以便在 OMF 注册数据库中进行跟踪。

6.12. GNOME 组件

有关 GNOME 端口的更多帮助,请查看一些 现有端口 以获取示例。FreeBSD GNOME 页面 包含联系信息,如果您需要更多帮助。这些组件分为目前正在使用的 GNOME 组件和遗留组件。如果组件支持参数,则将在描述中以括号列出。第一个是默认值。如果组件默认为添加到构建和运行依赖项中,则显示“Both”。

表 8. GNOME 组件
组件关联程序描述

atk

accessibility/atk

辅助技术工具包 (ATK)

atkmm

accessibility/atkmm

atk 的 c++ 绑定

cairo

graphics/cairo

具有跨设备输出支持的矢量图形库

cairomm

graphics/cairomm

cairo 的 c++ 绑定

dconf

devel/dconf

配置数据库系统 (both, build, run)

evolutiondataserver3

databases/evolution-data-server

Evolution 集成邮件/PIM 套件的数据后端

gdkpixbuf2

graphics/gdk-pixbuf2

GTK+ 的图形库

glib20

devel/glib20

GNOME 核心库 glib20

glibmm

devel/glibmm

glib20 的 c++ 绑定

gnomecontrolcenter3

sysutils/gnome-control-center

GNOME 3 控制中心

gnomedesktop3

x11/gnome-desktop

GNOME 3 桌面 UI 库

gsound

audio/gsound

用于播放系统声音的 GObject 库 (both, build, run)

gtk-update-icon-cache

graphics/gtk-update-icon-cache

Gtk+ 工具包中的 Gtk-update-icon-cache 实用程序

gtk20

x11-toolkits/gtk20

Gtk+ 2 工具包

gtk30

x11-toolkits/gtk30

Gtk+ 3 工具包

gtkmm20

x11-toolkits/gtkmm20

gtk20 工具包的 c++ 绑定 2.0

gtkmm24

x11-toolkits/gtkmm24

gtk20 工具包的 c++ 绑定 2.4

gtkmm30

x11-toolkits/gtkmm30

gtk30 工具包的 c++ 绑定 3.0

gtksourceview2

x11-toolkits/gtksourceview2

向 GtkTextView 添加语法高亮显示的小部件

gtksourceview3

x11-toolkits/gtksourceview3

文本小部件,向 GtkTextView 小部件添加语法高亮显示

gtksourceviewmm3

x11-toolkits/gtksourceviewmm3

gtksourceview3 库的 c++ 绑定

gvfs

devel/gvfs

GNOME 虚拟文件系统

intltool

textproc/intltool

用于国际化的工具(另请参见 intlhack)

introspection

devel/gobject-introspection

基本的内省绑定和工具,用于生成内省绑定。大多数情况下,:build 就足够了,:both/:run 仅适用于使用内省绑定的应用程序。 (both, build, run)

libgda5

databases/libgda5

提供对不同类型数据源的统一访问

libgda5-ui

databases/libgda5-ui

来自 libgda5 库的 UI 库

libgdamm5

databases/libgdamm5

libgda5 库的 c++ 绑定

libgsf

devel/libgsf

可扩展的 I/O 抽象,用于处理结构化文件格式

librsvg2

graphics/librsvg2

用于解析和渲染 SVG 矢量图形文件的库

libsigc++20

devel/libsigc++20

C++ 的回调框架

libxml++26

textproc/libxml++26

libxml2 库的 c++ 绑定

libxml2

textproc/libxml2

XML 解析器库 (both, build, run)

libxslt

textproc/libxslt

XSLT C 库 (both, build, run)

metacity

x11-wm/metacity

来自 GNOME 的窗口管理器

nautilus3

x11-fm/nautilus

GNOME 文件管理器

pango

x11-toolkits/pango

用于 i18n 文本布局和渲染的开源框架

pangomm

x11-toolkits/pangomm

pango 库的 c++ 绑定

py3gobject3

devel/py3-gobject3

Python 3,GObject 3.0 绑定

pygobject3

devel/py-gobject3

Python 2,GObject 3.0 绑定

vte3

x11-toolkits/vte3

具有改进的辅助功能和 I18N 支持的终端小部件

表 9. GNOME 宏组件
组件描述

gnomeprefix

configure 提供一些默认位置。

intlhack

与 intltool 相同,但进行了修补以确保使用 share/locale/。请仅在 intltool 单独不足够的情况下使用。

referencehack

该宏用于帮助将 API 或参考文档拆分为单独的端口。

表 10. GNOME 遗留组件
组件关联程序描述

atspi

accessibility/at-spi

辅助技术服务提供者接口

esound

audio/esound

Enlightenment 声音包

gal2

x11-toolkits/gal2

从 GNOME 2 gnumeric 中提取的小部件集合

gconf2

devel/gconf2

GNOME 2 的配置数据库系统

gconfmm26

devel/gconfmm26

gconf2 的 c++ 绑定

gdkpixbuf

graphics/gdk-pixbuf

GTK+ 的图形库

glib12

devel/glib12

glib 1.2 核心库

gnomedocutils

textproc/gnome-doc-utils

GNOME 文档实用程序

gnomemimedata

misc/gnome-mime-data

GNOME 2 的 MIME 和应用程序数据库

gnomesharp20

x11-toolkits/gnome-sharp20

GNOME 2 .NET 运行时接口

gnomespeech

accessibility/gnome-speech

GNOME 2 文本转语音 API

gnomevfs2

devel/gnome-vfs

GNOME 2 虚拟文件系统

gtk12

x11-toolkits/gtk12

Gtk+ 1.2 工具包

gtkhtml3

www/gtkhtml3

轻量级 HTML 渲染/打印/编辑引擎

gtkhtml4

www/gtkhtml4

轻量级 HTML 渲染/打印/编辑引擎

gtksharp20

x11-toolkits/gtk-sharp20

GTK+ 和 GNOME 2 .NET 运行时接口

gtksourceview

x11-toolkits/gtksourceview

向 GtkTextView 添加语法高亮显示的小部件

libartgpl2

graphics/libart_lgpl

用于高性能 2D 图形的库

libbonobo

devel/libbonobo

GNOME 2 的组件和复合文档系统

libbonoboui

x11-toolkits/libbonoboui

GNOME 2 libbonobo 组件的 GUI 前端

libgda4

databases/libgda4

提供对不同类型数据源的统一访问

libglade2

devel/libglade2

GNOME 2 glade 库

libgnome

x11/libgnome

GNOME 2(GNU 桌面环境)的库

libgnomecanvas

graphics/libgnomecanvas

GNOME 2 的图形库

libgnomekbd

x11/libgnomekbd

GNOME 2 键盘共享库

libgnomeprint

print/libgnomeprint

Gnome 2 打印支持库

libgnomeprintui

x11-toolkits/libgnomeprintui

Gnome 2 打印支持库

libgnomeui

x11-toolkits/libgnomeui

GNOME 2 GUI(GNU 桌面环境)的库

libgtkhtml

www/libgtkhtml

轻量级 HTML 渲染/打印/编辑引擎

libgtksourceviewmm

x11-toolkits/libgtksourceviewmm

GtkSourceView 的 c++ 绑定

libidl

devel/libIDL

用于创建 CORBA IDL 文件树的库

libsigc++12

devel/libsigc++12

C++ 的回调框架

libwnck

x11-toolkits/libwnck

用于编写页面和任务列表的库

libwnck3

x11-toolkits/libwnck3

用于编写页面和任务列表的库

orbit2

devel/ORBit2

支持 C 语言的高性能 CORBA ORB

pygnome2

x11-toolkits/py-gnome2

GNOME 2 的 Python 绑定

pygobject

devel/py-gobject

Python 2,GObject 2.0 绑定

pygtk2

x11-toolkits/py-gtk2

一套用于 GTK+ 的 Python 绑定

pygtksourceview

x11-toolkits/py-gtksourceview

GtkSourceView 2 的 Python 绑定

vte

x11-toolkits/vte

具有改进的辅助功能和 I18N 支持的终端小部件

表 11. 已弃用的组件:请勿使用
组件描述

pangox-compat

pangox-compat 已被弃用,并从 pango 包中分离出来。

6.13. 使用 Qt

对于作为 Qt 自身一部分的端口,请参阅 qt-dist

6.13.1. 需要 Qt 的端口

Ports Collection 分别使用 USES+=qt:5USES+=qt:6 为 Qt 5 和 Qt 6 提供支持。将 USE_QT 设置为所需 Qt 组件(库、工具、插件)的列表。

Qt 框架导出许多变量,这些变量可供端口使用,其中一些变量列在下面

表 12. 提供给使用 Qt 的端口的变量

QMAKE

qmake 二进制文件的完整路径。

LRELEASE

lrelease 实用程序的完整路径。

MOC

moc 的完整路径。

RCC

rcc 的完整路径。

UIC

uic 的完整路径。

QT_INCDIR

Qt 包含目录。

QT_LIBDIR

Qt 库路径。

QT_PLUGINDIR

Qt 插件路径。

6.13.2. 组件选择

必须在 USE_QT 中指定各个 Qt 工具和库依赖项。每个组件都可以加上 _build_run 后缀,后缀表示组件的依赖项是构建时还是运行时。如果未加后缀,则在构建时和运行时都依赖于该组件。通常,库组件是未加后缀指定的,工具组件大多使用 _build 后缀指定,插件组件使用 _run 后缀指定。最常用的组件列在下面(所有可用组件都列在 _USE_QT_ALL 中,该组件是从 /usr/ports/Mk/Uses/qt.mk 中的 _USE_QT_COMMON_USE_QT[56]_ONLY 生成的)。

表 13. 可用的 Qt 库组件
名称描述

3d

Qt3D 模块

5compat

Qt 6 的 Qt 5 兼容模块

assistant

Qt 5 文档浏览器

base

Qt 6 基本模块

canvas3d

Qt canvas3d 模块

charts

Qt 5 图表模块

concurrent

Qt 多线程模块

connectivity

Qt 连接性(蓝牙/NFC)模块

core

Qt 核心非图形模块

datavis3d

Qt 5 3D 数据可视化模块

dbus

Qt D-Bus 进程间通信模块

declarative

Qt 声明式框架,用于动态用户界面

designer

Qt 5 图形用户界面设计器

diag

用于报告有关 Qt 及其环境的诊断信息的工具

doc

Qt 5 文档

examples

Qt 5 示例源代码

gamepad

Qt 5 游戏手柄模块

graphicaleffects

Qt Quick 图形效果

gui

Qt 图形用户界面模块

help

Qt 在线帮助集成模块

l10n

Qt 本地化消息

languageserver

Qt 6 语言服务器协议实现

linguist

Qt 5 翻译工具

location

Qt 位置模块

lottie

Qt 6 QML API,用于渲染图形和动画

multimedia

Qt 音频、视频、广播和相机支持模块

network

Qt 网络模块

networkauth

Qt 网络身份验证模块

opengl

Qt 5 兼容 OpenGL 支持模块

paths

QStandardPaths 的命令行客户端

phonon4

KDE 多媒体框架

pixeltool

Qt 5 屏幕放大镜

plugininfo

Qt 5 插件元数据转储器

positioning

Qt 6 定位 API,来自卫星、WiFi 或文本文件等来源。

printsupport

Qt 打印支持模块

qdbus

Qt 对 D-Bus 的命令行接口

qdbusviewer

Qt 5 对 D-Bus 的图形界面

qdoc

Qt 文档生成器

qdoc-data

QDoc 配置文件

qev

Qt QWidget 事件内省工具

qmake

Qt Makefile 生成器

quickcontrols

用于在 Qt Quick 中构建完整界面的控件集

quickcontrols2

用于在 Qt Quick 中构建完整界面的控件集

remoteobjects

Qt 5 SXCML 模块

script

Qt 4 兼容脚本模块

scripttools

Qt Script 附加组件

scxml

Qt 5 SXCML 模块

sensors

Qt 传感器模块

serialbus

Qt 函数,用于访问工业总线系统

serialport

Qt 函数,用于访问串行端口

shadertools

Qt 6 工具,用于跨平台 Qt 着色器管道

speech

Qt5 的辅助功能

sql

Qt SQL 数据库集成模块

sql-ibase

Qt InterBase/Firebird 数据库插件

sql-mysql

Qt MySQL 数据库插件

sql-odbc

Qt 开放数据库连接插件

sql-pgsql

Qt PostgreSQL 数据库插件

sql-sqlite2

Qt SQLite 2 数据库插件

sql-sqlite3

Qt SQLite 3 数据库插件

sql-tds

Qt TDS 数据库连接数据库插件

svg

Qt SVG 支持模块

testlib

Qt 单元测试模块

tools

Qt 6 各种工具

translations

Qt 6 翻译模块

uiplugin

Qt Designer 的自定义 Qt 小部件插件接口

uitools

Qt Designer UI 表单支持模块

virtualkeyboard

Qt 5 虚拟键盘模块

wayland

Qt 5 对 Wayland 的包装器

webchannel

Qt 5 库,用于将 C++/QML 与 HTML/js 客户端集成

webengine

Qt 5 库,用于渲染 Web 内容

webkit

QtWebKit,具有更现代的 WebKit 代码库

websockets

Qt 的 WebSocket 协议实现

websockets-qml

Qt 的 WebSocket 协议实现(QML 绑定)

webview

Qt 组件,用于显示 Web 内容

widgets

Qt C++ 小部件模块

x11extras

Qt 基于 X11 的系统的平台特定功能

xml

Qt SAX 和 DOM 实现

xmlpatterns

Qt 对 XPath、XQuery、XSLT 和 XML 架构的支持

要确定应用程序依赖的库,请在成功编译后对主可执行文件运行 ldd

表 14. 可用的 Qt 工具组件
名称描述

buildtools

构建工具(mocrcc),几乎每个 Qt 应用程序都需要。

linguisttools

本地化工具:lreleaselupdate

qmake

Makefile 生成器/构建实用程序

表 15. 可用的 Qt 插件组件
名称描述

imageformats

TGA、TIFF 和 MNG 图像格式的插件

示例 21. 选择 Qt 5 组件

在此示例中,移植的应用程序使用 Qt 5 图形用户界面库、Qt 5 核心库、所有 Qt 5 代码生成工具和 Qt 5 的 Makefile 生成器。由于 gui 库隐含对核心库的依赖,因此不需要指定 core。Qt 5 代码生成工具 mocuicrcc 以及 Makefile 生成器 qmake 仅在构建时需要,因此使用 _build 后缀指定它们。

USES=	qt:5
USE_QT=	gui buildtools_build qmake_build

6.13.3. 使用 qmake

如果应用程序提供 qmake 项目文件 (*.pro),则定义 USES= qmake 以及 USE_QTUSES= qmake 已经隐含了对 qmake 的构建依赖,因此可以从 USE_QT 中省略 qmake 组件。类似于 CMake,qmake 支持源代码外构建,可以通过指定 outsource 参数来启用(请参阅 USES= qmake 示例)。另请参阅 USES qmake 的可能参数

表 16. USES= qmake 的可能参数
变量描述

no_configure

不要添加配置目标。这由 HAS_CONFIGURE=yesGNU_CONFIGURE=yes 隐含。当构建只需要来自 USES= qmake 的环境设置,但否则会自行运行 qmake 时,这是必需的。

no_env

禁止修改配置和 make 环境。仅当 qmake 用于配置软件且构建无法理解 USES= qmake 设置的环境时,才需要它。

norecursive

不要将 -recursive 参数传递给 qmake

outsource

执行源代码外构建。

表 17. 使用 qmake 的端口的变量
变量描述

QMAKE_ARGS

要传递给 qmake 二进制文件的端口特定 qmake 标志。

QMAKE_ENV

要为 qmake 二进制文件设置的环境变量。默认值为 ${CONFIGURE_ENV}

QMAKE_SOURCE_PATH

qmake 项目文件 (.pro) 的路径。如果请求源代码外构建,则默认值为 ${WRKSRC},否则为空。

使用 USES= qmake 时,将部署这些设置。

CONFIGURE_ARGS+=	--with-qt-includes=${QT_INCDIR} \
			--with-qt-libraries=${QT_LIBDIR} \
			--with-extra-libs=${LOCALBASE}/lib \
			--with-extra-includes=${LOCALBASE}/include

CONFIGURE_ENV+=	QTDIR="${QT_PREFIX}" QMAKE="${QMAKE}" \
		MOC="${MOC}" RCC="${RCC}" UIC="${UIC}" \
		QMAKESPEC="${QMAKESPEC}"

PLIST_SUB+=	QT_INCDIR=${QT_INCDIR_REL} \
		QT_LIBDIR=${QT_LIBDIR_REL} \
		QT_PLUGINDIR=${QT_PLUGINDIR_REL}

某些配置脚本不支持上述参数。要禁止修改 CONFIGURE_ENVCONFIGURE_ARGS,请设置 USES= qmake:no_env

示例 22. USES= qmake 示例

此代码段演示了使用 qmake 的 Qt 5 端口。

USES=	qmake:outsource qt:5
USE_QT=	buildtools_build

Qt 应用程序通常被编写为跨平台的,并且 X11/Unix 通常不是它们开发的平台,这反过来会导致某些疏漏,例如

  • 缺少额外的包含路径。 许多应用程序都支持系统托盘图标,但忽略了在 X11 目录中查找包含文件和/或库。 要通过命令行将目录添加到 `qmake` 的包含和库搜索路径,请使用

    QMAKE_ARGS+=	INCLUDEPATH+=${LOCALBASE}/include \
    		LIBS+=-L${LOCALBASE}/lib
  • 虚假安装路径。 有时,图标或 .desktop 文件等数据默认情况下会安装到 XDG 兼容应用程序不会扫描的目录中。 editors/texmaker 是一个例子 - 查看该端口的 files 目录中的 patch-texmaker.pro 文件,了解如何在 qmake 项目文件中直接解决此问题的模板。

6.14. 使用 KDE

6.14.1. KDE 变量定义

如果应用程序依赖于 KDE,请将 USES+=kde:5USE_KDE 设置为所需组件的列表。 _build_run 后缀可用于强制组件依赖类型(例如,baseapps_run)。 如果未设置后缀,将使用默认依赖类型。 要强制两种类型,请使用两种后缀将组件添加两次(例如,ecm_build ecm_run)。 可用组件列在下面(最新的组件也列在 /usr/ports/Mk/Uses/kde.mk 中)

表 18. 可用的 KDE 组件
名称描述

activities

KF5 运行时和库,用于在单独的活动中组织工作

activities-stats

KF5 活动统计

activitymanagerd

系统服务,用于管理用户的活动,跟踪使用模式

akonadi

KDE-Pim 的存储服务器

akonadicalendar

Akonadi 日历集成

akonadiconsole

Akonadi 管理和调试控制台

akonadiconstacts

在 Akonadi 中实现联系人管理的库和守护进程

akonadiimportwizard

将数据从其他邮件客户端导入 KMail

akonadimime

在 Akonadi 中实现基本电子邮件处理的库和守护进程

akonadinotes

用于访问 MBox 格式邮件存储的 KDE 库

akonadisearch

在 Akonadi 中实现搜索的库和守护进程

akregator

KDE 的 RSS 阅读器

alarmcalendar

KDE 的 KAlarm 闹钟 API

apidox

KF5 API 文档工具

archive

KF5 库,提供用于处理归档格式的类

attica

开放协作服务 API 库 KDE5 版本

attica5

开放协作服务 API 库 KDE5 版本

auth

KF5 对系统策略和身份验证功能的抽象

baloo

KF5 用于搜索和管理用户元数据的框架

baloo-widgets

BalooWidgets 库

baloo5

KF5 用于搜索和管理用户元数据的框架

blog

KDE 网志访问 API

bookmarks

KF5 库,用于书签和 XBEL 格式

breeze

Plasma5 的 Breeze 视觉风格的艺术作品、样式和资产

breeze-gtk

Plasma5 Breeze 视觉风格,用于 Gtk

breeze-icons

KDE 的 Breeze 图标主题

calendarcore

KDE 日历访问库

calendarsupport

KDEPim 的日历支持库

calendarutils

KDE 的实用程序和用户界面函数,用于访问日历

codecs

KF5 字符串操作库

completion

KF5 文本完成助手和部件

config

KF5 用于配置对话框的小部件

configwidgets

KF5 用于配置对话框的小部件

contacts

KDE 管理联系人信息的 API

coreaddons

KF5 对 QtCore 的附加组件

crash

KF5 库,用于处理来自应用程序的崩溃分析和错误报告

dbusaddons

KF5 对 QtDBus 的附加组件

decoration

Plasma5 库,用于创建窗口装饰

designerplugin

KF5 将 Frameworks 小部件集成到 Qt Designer/Creator 中

discover

Plasma5 包管理工具

dnssd

KF5 对系统 DNSSD 功能的抽象

doctools

KF5 从 docbook 生成文档

drkonqi

Plasma5 崩溃处理程序

ecm

CMake 的额外模块和脚本

emoticons

KF5 库,用于转换表情符号

eventviews

KDEPim 的事件查看库

filemetadata

KF5 库,用于提取文件元数据

frameworkintegration

KF5 工作区和跨框架集成插件

gapi

基于 KDE 的库,用于访问 Google 服务

globalaccel

KF5 库,用于添加对全局工作区快捷方式的支持

grantlee-editor

Grantlee 主题编辑器

grantleetheme

KDE PIM grantleetheme

gravatar

用于 Gravatar 支持的库

guiaddons

KF5 对 QtGui 的附加组件

holidays

KDE 日历节假日库

hotkeys

Plasma5 库,用于热键

i18n

KF5 高级国际化框架

iconthemes

KF5 库,用于处理应用程序中的图标

identitymanagement

KDE pim 身份

idletime

KF5 库,用于监控用户活动

imap

KDE 的 IMAP 支持 API

incidenceeditor

KDEPim 的事件编辑库

infocenter

Plasma5 实用程序,提供系统信息

init

KF5 进程启动器,用于加速启动 KDE 应用程序

itemmodels

KF5 用于 Qt 模型/视图系统的模型

itemviews

KF5 用于 Qt 模型/视图的小部件附加组件

jobwidgets

KF5 小部件,用于跟踪 KJob 实例

js

KF5 库,提供 ECMAScript 解释器

jsembed

KF5 库,用于将 JavaScript 对象绑定到 QObjects

kaddressbook

KDE 联系人管理器

kalarm

个人闹钟调度程序

kalarm

个人闹钟调度程序

kate

KDE 系统的基本编辑器框架

kcmutils

KF5 用于处理 KCModules 的实用程序

kde-cli-tools

Plasma5 非交互式系统工具

kde-gtk-config

Plasma5 GTK2 和 GTK3 配置器

kdeclarative

KF5 库,提供 QML 和 KDE Frameworks 的集成

kded

KF5 可扩展守护进程,用于提供系统级服务

kdelibs4support

KF5 从 KDELibs4 移植的辅助工具

kdepim-addons

KDE PIM 附加组件

kdepim-apps-libs

KDE PIM 邮件相关库

kdepim-runtime5

KDE PIM 工具和服务

kdeplasma-addons

Plasma5 附加组件,用于改善 Plasma 体验

kdesu

KF5 与 su 集成,用于提升权限

kdewebkit

KF5 库,提供 QtWebKit 的集成

kgamma5

Plasma5 监视器的伽马设置

khtml

KF5 KTHML 渲染引擎

kimageformats

KF5 库,提供对其他图像格式的支持

kio

KF5 资源和网络访问抽象

kirigami2

基于 QtQuick 的组件集

kitinerary

用于旅行预订信息的数据库模型和提取系统

kmail

KDE 邮件客户端

kmail

KDE 邮件客户端

kmail-account-wizard

KDE 邮件帐户向导

kmenuedit

Plasma5 菜单编辑器

knotes

弹出笔记

kontact

KDE 个人信息管理器

kontact

KDE 个人信息管理器

kontactinterface

KDE 胶水,用于将 KParts 嵌入 Kontact

korganizer

日历和计划程序

kpimdav

使用 KJobs 的 DAV 协议实现

kpkpass

用于处理 Apple Wallet Pass 文件的库

kross

KF5 多语言应用程序脚本

kscreen

Plasma5 屏幕管理库

kscreenlocker

Plasma5 安全锁定屏幕架构

ksmtp

基于作业的库,用于通过 SMTP 服务器发送电子邮件

ksshaskpass

Plasma5 ssh-add 前端

ksysguard

Plasma5 实用程序,用于跟踪和控制正在运行的进程

kwallet-pam

Plasma5 KWallet PAM 集成

kwayland-integration

用于基于 Wayland 的桌面的集成插件

kwin

Plasma5 窗口管理器

kwrited

Plasma5 守护进程,侦听墙和写入消息

ldap

KDE 的 LDAP 访问 API

libkcddb

KDE CDDB 库

libkcompactdisc

KDE 用于与音频 CD 交互的库

libkdcraw

LibRaw 的 KDE 接口

libkdegames

KDE 游戏使用的库

libkdepim

KDE PIM 库

libkeduvocdocument

用于读取和写入词汇文件的库

libkexiv2

Exiv2 库的 KDE 接口

libkipi

KDE 图像插件接口

libkleo

KDE 的证书管理器

libksane

SANE 库的 KDE 接口

libkscreen

Plasma5 屏幕管理库

libksieve

KDEPim 的 Sieve 库

libksysguard

Plasma5 用于跟踪和控制正在运行的进程的库

mailcommon

KDEPim 的通用库

mailimporter

将 mbox 文件导入 KMail

mailtransport

KDE 库,用于管理邮件传输

marble

KDE 的虚拟地球仪和世界地图集

mbox

用于访问 MBox 格式邮件存储的 KDE 库

mbox-importer

将 mbox 文件导入 KMail

mediaplayer

KF5 用于媒体播放器功能的插件接口

messagelib

用于处理消息的库

milou

Plasma5 用于搜索的 Plasmoid

mime

用于处理 MIME 数据的库

newstuff

KF5 库,用于从网络下载应用程序资产

notifications

KF5 对系统通知的抽象

notifyconfig

KF5 的 KNotify 配置系统

okular

KDE 通用文档查看器

oxygen

Plasma5 Oxygen 样式

oxygen-icons5

KDE 的 Oxygen 图标主题

package

KF5 库,用于加载和安装软件包

parts

KF5 基于文档的插件系统

people

KF5 库,提供对联系人的访问

pim-data-exporter

导入和导出 KDE PIM 设置

pimcommon

KDEPim 的通用库

pimtextedit

KDE 库,用于 PIM 特定的文本编辑实用程序

plasma-browser-integration

Plasma5 组件,用于将浏览器集成到桌面

plasma-desktop

Plasma5 Plasma 桌面

plasma-framework

KF5 基于插件的 UI 运行时,用于编写用户界面

plasma-integration

Plasma 工作区的 Qt 平台主题集成插件

plasma-pa

Plasma5 Plasma PulseAudio 混音器

plasma-sdk

Plasma5 应用程序,对 Plasma 开发很有用

plasma-workspace

Plasma5 Plasma 工作区

plasma-workspace-wallpapers

Plasma5 壁纸

plotting

KF5 轻量级绘图框架

polkit-kde-agent-1

Plasma5 守护进程,提供 Polkit 身份验证 UI

powerdevil

Plasma5 工具,用于管理功耗设置

prison

用于生成条形码的 API

pty

KF5 pty 抽象

purpose

提供特定用途的可用操作

qqc2-desktop-style

KDE 的 Qt QuickControl2 样式

runner

KF5 并行查询系统

service

KF5 高级插件和服务内省

solid

KF5 硬件集成和检测

sonnet

KF5 基于插件的拼写检查库

syndication

KDE RSS 提要处理库

syntaxhighlighting

KF5 用于结构化文本和代码的语法高亮引擎

systemsettings

Plasma5 系统设置

texteditor

KF5 高级可嵌入文本编辑器

textwidgets

KF5 高级文本编辑小部件

threadweaver

KF5 对 QtDBus 的附加组件

tnef

KDE 用于处理 TNEF 数据的 API

unitconversion

KF5 用于单位转换的库

user-manager

Plasma5 用户管理器

wallet

KF5 用于用户密码的安全统一容器

wayland

KF5 针对 Wayland 库的客户端和服务器库包装器

widgetsaddons

KF5 对 QtWidgets 的附加组件

windowsystem

KF5 用于访问窗口系统的库

xmlgui

KF5 用户可配置主窗口

xmlrpcclient

KF5 与 XMLRPC 服务的交互

示例 23. USE_KDE 示例

这是一个 KDE 端口的简单示例。USES= cmake 指示该端口利用 CMake,CMake 是一种广泛用于 KDE 项目的配置工具(有关详细用法,请参阅 使用 cmake)。USE_KDE 带来对 KDE 库的依赖。所需的 KDE 组件和其他依赖项可以通过配置日志确定。USE_KDE 不意味着 USE_QT。如果端口需要一些 Qt 组件,请在 USE_QT 中指定它们。

USES=		cmake kde:5 qt:5
USE_KDE=	ecm
USE_QT=		core buildtools_build qmake_build

6.15. 使用 LXQt

依赖于 LXQt 的应用程序应设置 USES+= lxqt 并将 USE_LXQT 设置为下表中所需组件的列表

表 19. 可用的 LXQt 组件
名称描述

buildtools

其他 CMake 模块的辅助程序

libfmqt

Libfm Qt 绑定

lxqt

LXQt 核心库

qtxdg

freedesktop.org XDG 规范的 Qt 实现

示例 24. USE_LXQT 示例

这是一个简单的示例,USE_LXQT 添加了对 LXQt 库的依赖。所需的 LXQt 组件和其他依赖项可以通过配置日志确定。

USES=	cmake lxqt qt:5 tar:xz
USE_QT=		core dbus widgets buildtools_build qmake_build
USE_LXQT=	buildtools libfmqt

6.16. 使用 Java

6.16.1. 变量定义

如果端口需要 Java™ 开发工具包 (JDK™) 来构建、运行或甚至提取 distfile,则定义 USE_JAVA

端口集合中有多个来自不同供应商的不同版本的 JDK。如果端口必须使用特定版本,请使用 JAVA_VERSION 变量指定它。最新版本是 java/openjdk18,以及 java/openjdk17java/openjdk16java/openjdk15java/openjdk14java/openjdk13java/openjdk12java/openjdk11java/openjdk8java/openjdk7 也可用。

表 20. 使用 Java 的端口可能设置的变量
变量含义

USE_JAVA

定义以使剩余变量生效。

JAVA_VERSION

端口适用的 Java 版本的空格分隔列表。可选的 + 允许指定版本范围(允许的值:8[+] 11[+] 17[+] 18[+] 19[+] 20[+] 21[+])。

JAVA_OS

端口适用的 JDK 端口操作系统的空格分隔列表(允许的值:native linux)。

JAVA_VENDOR

端口适用的 JDK 端口供应商的空格分隔列表(允许的值:openjdk oracle)。

JAVA_BUILD

设置后,将选定的 JDK 端口添加到构建依赖项中。

JAVA_RUN

设置后,将选定的 JDK 端口添加到运行依赖项中。

JAVA_EXTRACT

设置后,将选定的 JDK 端口添加到提取依赖项中。

以下是设置 USE_JAVA 后端口将接收的所有设置列表

表 21. 提供给使用 Java 的端口的变量
变量

JAVA_PORT

JDK 端口的名称(例如,java/openjdk6)。

JAVA_PORT_VERSION

JDK 端口的完整版本(例如,1.6.0)。只需要此版本号的前两位数字,使用 ${JAVA_PORT_VERSION:C/^([0-9])\.([0-9])(.*)$/\1.\2/}

JAVA_PORT_OS

JDK 端口使用的操作系统(例如,'native')。

JAVA_PORT_VENDOR

JDK 端口的供应商(例如,'openjdk')。

JAVA_PORT_OS_DESCRIPTION

JDK 端口使用的操作系统的描述(例如,'Native')。

JAVA_PORT_VENDOR_DESCRIPTION

JDK 端口供应商的描述(例如,'OpenJDK BSD Porting Team')。

JAVA_HOME

JDK 安装目录的路径(例如,'/usr/local/openjdk6')。

JAVAC

要使用的 Java 编译器的路径(例如,'/usr/local/openjdk6/bin/javac')。

JAR

要使用的 jar 工具的路径(例如,'/usr/local/openjdk6/bin/jar''/usr/local/bin/fastjar')。

APPLETVIEWER

appletviewer 实用程序的路径(例如,'/usr/local/openjdk6/bin/appletviewer')。

JAVA

java 可执行文件的路径。使用它来执行 Java 程序(例如,'/usr/local/openjdk6/bin/java')。

JAVADOC

javadoc 实用程序程序的路径。

JAVAH

javah 程序的路径。

JAVAP

javap 程序的路径。

JAVA_KEYTOOL

keytool 实用程序程序的路径。

JAVA_N2A

native2ascii 工具的路径。

JAVA_POLICYTOOL

policytool 程序的路径。

JAVA_SERIALVER

serialver 实用程序程序的路径。

RMIC

RMI 存根/骨架生成器 rmic 的路径。

RMIREGISTRY

RMI 注册程序 rmiregistry 的路径。

RMID

RMI 守护程序 rmid 的路径。

JAVA_CLASSES

包含 JDK 类文件的存档的路径,${JAVA_HOME}/jre/lib/rt.jar.

使用 java-debug make 目标获取调试端口的信息。它将显示前面列出的大多数变量的值。

此外,定义了这些常量,以便所有 Java 端口都可以以一致的方式安装

表 22. 为使用 Java 的端口定义的常量
常量

JAVASHAREDIR

与 Java 相关的所有内容的基目录。默认值:${PREFIX}/share/java.

JAVAJARDIR

安装 JAR 文件的目录。默认值:${JAVASHAREDIR}/classes.

JAVALIBDIR

其他端口安装的 JAR 文件所在的目录。默认值:${LOCALBASE}/share/java/classes.

相关条目在 PLIST_SUB(在 根据 Make 变量更改 pkg-plist 中有说明)和 SUB_LIST 中定义。

6.16.2. 使用 Ant 构建

当端口要使用 Apache Ant 构建时,它必须定义 USE_ANT。因此,Ant 被视为子 make 命令。当端口没有定义 do-build 目标时,将设置一个默认目标,该目标根据 MAKE_ENVMAKE_ARGSALL_TARGET 运行 Ant。这类似于 构建机制 中记录的 USES= gmake 机制。

6.16.3. 最佳实践

移植 Java 库时,端口必须将 JAR 文件安装到 ${JAVAJARDIR} 中,并将所有其他内容安装到 ${JAVASHAREDIR}/${PORTNAME} 下(文档除外,见下文)。为了减小打包文件大小,请在 Makefile 中直接引用 JAR 文件。使用以下语句(其中 myport.jar 是作为端口一部分安装的 JAR 文件的名称)

PLIST_FILES+=	${JAVAJARDIR}/myport.jar

移植 Java 应用程序时,端口通常将所有内容安装到单个目录下(包括其 JAR 依赖项)。在这方面,强烈建议使用 ${JAVASHAREDIR}/${PORTNAME}。由移植者决定端口是将额外的 JAR 依赖项安装到此目录下,还是使用已经安装的依赖项(来自 ${JAVAJARDIR})。

移植需要应用程序服务器(如 www/tomcat7)来运行服务的 Java™ 应用程序时,供应商通常会分发一个 .war.war 是 Web 应用程序存档,在应用程序调用时会进行提取。避免将 .war 添加到 pkg-plist 中。这被认为不是最佳实践。应用程序服务器将扩展 war 存档,但在端口被删除时不会正确清理它。处理此文件的更可取方法是提取存档,然后安装文件,最后将这些文件添加到 pkg-plist 中。

TOMCATDIR=	${LOCALBASE}/apache-tomcat-7.0
WEBAPPDIR=	myapplication

post-extract:
	@${MKDIR} ${WRKDIR}/${PORTDIRNAME}
	@${TAR} xf ${WRKDIR}/myapplication.war -C ${WRKDIR}/${PORTDIRNAME}

do-install:
	cd ${WRKDIR} && \
	${INSTALL} -d -o ${WWWOWN} -g ${WWWGRP} ${TOMCATDIR}/webapps/${PORTDIRNAME}
	cd ${WRKDIR}/${PORTDIRNAME} && ${COPYTREE_SHARE} \* ${WEBAPPDIR}/${PORTDIRNAME}

无论端口类型(库或应用程序),附加文档都安装在与 其他任何端口 相同的位置。众所周知,Javadoc 工具会根据使用的 JDK 版本生成不同的文件集。对于没有强制使用特定 JDK 的端口,因此很难指定打包列表 (pkg-plist)。这就是强烈鼓励移植者使用 PORTDOCS 的原因之一。此外,即使可以预测 javadoc 将生成的 文件集,结果 pkg-plist 的大小也支持使用 PORTDOCS

DATADIR 的默认值为 ${PREFIX}/share/${PORTNAME}。对于 Java 端口,将 DATADIR 覆盖为 ${JAVASHAREDIR}/${PORTNAME} 是一个好主意。实际上,DATADIR 会自动添加到 PLIST_SUB(在 根据 Make 变量更改 pkg-plist 中有说明)中,因此请在 pkg-plist 中直接使用 %%DATADIR%%

至于从源代码构建 Java 端口还是直接从二进制发行版安装 Java 端口,在撰写本文时,还没有明确的政策。但是,来自 FreeBSD Java 项目 的人员鼓励移植者在构建工作量很小的情况下从源代码构建他们的端口。

本节中介绍的所有功能都已在 bsd.java.mk 中实现。如果端口需要更复杂的 Java 支持,请先查看 bsd.java.mk Git 日志,因为它通常需要一段时间来记录最新的功能。然后,如果缺乏的所需支持对许多其他 Java 端口都有益,请随时在 freebsd-java 上进行讨论。

虽然有一个用于 PR 的 java 类别,但它指的是来自 FreeBSD Java 项目的 JDK 移植工作。因此,请将 Java 端口提交到 ports 类别中,就像任何其他端口一样,除非问题与 JDK 实现或 bsd.java.mk 相关。

类似地,对于 Java 端口的 CATEGORIES,也存在一个定义好的策略,详细介绍在 分类 中。

6.17. Web 应用程序、Apache 和 PHP

6.17.1. Apache

表 23. 使用 Apache 的端口变量

USE_APACHE

端口需要 Apache。可能的值:yes(获取任何版本)、222422-2422+ 等。默认的 APACHE 版本为 22。更多详细信息,请参阅 ports/Mk/bsd.apache.mkwiki.freebsd.org/Apache/

APXS

apxs 二进制文件的完整路径。可以在端口中覆盖。

HTTPD

httpd 二进制文件的完整路径。可以在端口中覆盖。

APACHE_VERSION

当前 Apache 安装的版本(只读变量)。此变量仅在包含 bsd.port.pre.mk 后可用。可能的值:2224

APACHEMODDIR

Apache 模块的目录。此变量会在 pkg-plist 中自动扩展。

APACHEINCLUDEDIR

Apache 头文件的目录。此变量会在 pkg-plist 中自动扩展。

APACHEETCDIR

Apache 配置文件的目录。此变量会在 pkg-plist 中自动扩展。

表 24. 用于移植 Apache 模块的有用变量

MODULENAME

模块的名称。默认值为 PORTNAME。例如:mod_hello

SHORTMODNAME

模块的简短名称。自动从 MODULENAME 中推断,但可以覆盖。例如:hello

AP_FAST_BUILD

使用 apxs 编译和安装模块。

AP_GENPLIST

还会自动创建一个 pkg-plist

AP_INC

在编译期间将目录添加到头文件搜索路径。

AP_LIB

在编译期间将目录添加到库搜索路径。

AP_EXTRAS

传递给 apxs 的附加标志。

6.17.2. Web 应用程序

Web 应用程序必须安装到 PREFIX/www/appname 中。此路径在 Makefilepkg-plist 中都可用,名为 WWWDIR,相对于 PREFIX 的路径在 Makefile 中可用,名为 WWWDIR_REL

Web 服务器进程的用户和组在 WWWOWNWWWGRP 中可用,如果需要更改某些文件的归属。这两个变量的默认值都是 www。如果端口需要不同的值,请使用 WWWOWN?= myuserWWWGRP?= mygroup。这允许用户轻松覆盖它们。

谨慎使用 WWWOWNWWWGRP。请记住,Web 服务器可以写入的每个文件都是潜在的安全风险。

除非 Web 应用程序明确需要 Apache,否则不要依赖 Apache。请尊重用户可能希望在除 Apache 之外的其他 Web 服务器上运行 Web 应用程序。

6.17.3. PHP

PHP Web 应用程序使用 USES=php 声明它们对它的依赖关系。有关更多信息,请参阅 php

6.17.4. PEAR 模块

移植 PEAR 模块是一个非常简单的过程。

USES=pear 添加到端口的 Makefile 中。框架将在正确的位置安装相关的文件,并在安装时自动生成 plist。

示例 25. PEAR 类的示例 Makefile
PORTNAME=       Date
DISTVERSION=	1.4.3
CATEGORIES=	devel www pear

MAINTAINER=	[email protected]
COMMENT=	PEAR Date and Time Zone Classes
WWW=		https://pear.php.net/package/Date/

USES=	pear

.include <bsd.port.mk>

PEAR 模块将使用 PHP 样式 自动进行风格化。

如果使用非默认 PEAR_CHANNEL,则会自动添加构建和运行时依赖项。

PEAR 模块不需要定义 PKGNAMESUFFIX,它会使用 PEAR_PKGNAMEPREFIX 自动填充。如果端口需要添加到 PKGNAMEPREFIX,它也必须使用 PEAR_PKGNAMEPREFIX 来区分不同的风格。

6.17.4.1. Horde 模块

同样,移植 Horde 模块也是一个简单的过程。

USES=horde 添加到端口的 Makefile 中。框架将在正确的位置安装相关的文件,并在安装时自动生成 plist。

USE_HORDE_BUILDUSE_HORDE_RUN 变量可用于添加对其他 Horde 模块的构建时和运行时依赖关系。有关可用模块的完整列表,请参阅 Mk/Uses/horde.mk

示例 26. Horde 模块的示例 Makefile
PORTNAME=	Horde_Core
DISTVERSION=	2.14.0
CATEGORIES=	devel www pear

MAINTAINER=	[email protected]
COMMENT=	Horde Core Framework libraries
WWW=		https://pear.horde.org/

OPTIONS_DEFINE=	KOLAB SOCKETS
KOLAB_DESC=	Enable Kolab server support
SOCKETS_DESC=	Depend on sockets PHP extension

USES=	horde
USE_PHP=	session

USE_HORDE_BUILD=	Horde_Role
USE_HORDE_RUN=	Horde_Role Horde_History Horde_Pack \
		Horde_Text_Filter Horde_View

KOLAB_USE=	HORDE_RUN=Horde_Kolab_Server,Horde_Kolab_Session
SOCKETS_USE=	PHP=sockets

.include <bsd.port.mk>

由于 Horde 模块也是 PEAR 模块,因此它们也将使用 PHP 样式 自动进行风格化。

6.18. 使用 Python

Ports 集合支持并行安装多个 Python 版本。端口必须使用正确的 python 解释器,根据用户可设置的 PYTHON_VERSION。最重要的是,这意味着将脚本中 python 可执行文件的路径替换为 PYTHON_CMD 的值。

PYTHON_SITELIBDIR 下安装文件的端口必须使用 pyXY- 包名称前缀,以便它们的包名称包含它们安装的 Python 版本。

PKGNAMEPREFIX=	${PYTHON_PKGNAMEPREFIX}
表 25. 使用 Python 的端口中最有用的变量

USES=python

端口需要 Python。可以使用 3.10+ 等值来指定最小所需版本。版本范围也可以通过用破折号分隔两个版本号来指定:USES=python:3.8-3.9。请注意,USES=python 包含 Python 2.7,它需要使用 USES=python:2.7+ 显式请求。

USE_PYTHON=distutils

使用 Python distutils 进行配置、编译和安装。如果端口附带 setup.py,则需要此选项。这会覆盖 do-builddo-install 目标,如果未定义 GNU_CONFIGURE,还会覆盖 do-configure。此外,它还暗示 USE_PYTHON=flavors

USE_PYTHON=autoplist

自动创建打包列表。这还要求设置 USE_PYTHON=distutils

USE_PYTHON=concurrent

端口将使用唯一的 前缀,通常是 PYTHON_PKGNAMEPREFIX,用于某些目录,例如 EXAMPLESDIRDOCSDIR,还会将后缀(来自 PYTHON_VER 的 Python 版本)附加到要安装的二进制文件和脚本。这允许端口同时安装在不同的 Python 版本中,否则会安装冲突的文件。

USE_PYTHON=flavors

端口不使用 distutils,但仍然支持多个 Python 版本。FLAVORS 将设置为支持的 Python 版本。有关更多信息,请参阅 USES=python 和 Styles

USE_PYTHON=optsuffix

如果当前的 Python 版本不是默认版本,端口将获得 PKGNAMESUFFIX=${PYTHON_PKGNAMESUFFIX}。仅对 Styles 有用。

PYTHON_PKGNAMEPREFIX

用作 PKGNAMEPREFIX 来区分不同 Python 版本的包。例如:py27-

PYTHON_SITELIBDIR

site-packages 树的位置,包含 Python 的安装路径(通常是 LOCALBASE)。PYTHON_SITELIBDIR 在安装 Python 模块时非常有用。

PYTHONPREFIX_SITELIBDIR

PYTHON_SITELIBDIR 的 PREFIX 清理变体。尽可能在 pkg-plist 中始终使用 %%PYTHON_SITELIBDIR%%%%PYTHON_SITELIBDIR%% 的默认值为 lib/python%%PYTHON_VERSION%%/site-packages

PYTHON_CMD

Python 解释器命令行,包括版本号。

表 26. Python 模块依赖项助手

PYNUMERIC

数值扩展的依赖项行。

PYNUMPY

新的数值扩展 numpy 的依赖项行。(PYNUMERIC 已被上游供应商弃用)。

PYXML

XML 扩展的依赖项行(对于 Python 2.0 及更高版本不需要,因为它也在基本发行版中)。

PY_ENUM34

根据 Python 版本对 devel/py-enum34 的条件依赖关系。

PY_ENUM_COMPAT

根据 Python 版本对 devel/py-enum-compat 的条件依赖关系。

PY_PATHLIB

根据 Python 版本对 devel/py-pathlib 的条件依赖关系。

PY_IPADDRESS

根据 Python 版本对 net/py-ipaddress 的条件依赖关系。

PY_FUTURES

根据 Python 版本对 devel/py-futures 的条件依赖关系。

可在 /usr/ports/Mk/Uses/python.mk 中找到可用变量的完整列表。

使用 Python Styles(使用 USE_PYTHON=distutilsUSE_PYTHON=flavors)对 Python 端口的所有依赖关系,都必须在其来源中追加 Python 样式,使用 @${PY_FLAVOR}。请参阅 简单 Python 模块的 Makefile

示例 27. 简单 Python 模块的 Makefile
PORTNAME=	sample
DISTVERSION=	1.2.3
CATEGORIES=	devel

MAINTAINER=	[email protected]
COMMENT=	Python sample module
WWW=		https://example.com/project/sample/

RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}six>0:devel/py-six@${PY_FLAVOR}

USES=		python
USE_PYTHON=	autoplist distutils

.include <bsd.port.mk>

一些 Python 应用程序声称支持 DESTDIR(这将是分段所需的),但它已损坏(例如,Mailman 最多 2.1.16)。这可以通过重新编译脚本来解决。这可以在 post-build 目标中完成。假设 Python 脚本应该在安装后驻留在 PYTHONPREFIX_SITELIBDIR 中,可以应用此解决方案

(cd ${STAGEDIR}${PREFIX} \
  && ${PYTHON_CMD} ${PYTHON_LIBDIR}/compileall.py \
   -d ${PREFIX} -f ${PYTHONPREFIX_SITELIBDIR:S;${PREFIX}/;;})

这会使用相对于阶段目录的路径重新编译源代码,并将 PREFIX 的值附加到由 -d 记录在字节编译输出文件中的文件名。-f 必须强制重新编译,并且 :S;${PREFIX}/;; 会从 PYTHONPREFIX_SITELIBDIR 的值中剥离前缀,使其相对于 PREFIX

6.19. 使用 Tcl/Tk

Ports 集合支持并行安装多个 Tcl/Tk 版本。端口应尝试至少支持默认的 Tcl/Tk 版本以及更高版本,使用 USES=tcl。可以通过追加 :_xx_ 来指定所需的 tcl 版本,例如 USES=tcl:85

表 27. 使用 Tcl/Tk 的端口中最有用的只读变量

TCL_VER

选择的 Tcl 主版本号。

TCLSH

Tcl 解释器的完整路径。

TCL_LIBDIR

Tcl 库的路径。

TCL_INCLUDEDIR

Tcl C 头文件的路径。

TCL_PKG_LIB_PREFIX

库前缀,根据 TIP595。

TCL_PKG_STUB_POSTFIX

存根库后缀。

TK_VER

选择的 Tk 主版本号。

WISH

Tk 解释器的完整路径。

TK_LIBDIR

Tk 库的路径。

TK_INCLUDEDIR

Tk C 头文件的路径。

有关这些变量的完整描述,请参阅 USES=tclUSES=tk,以及 使用 USES。这些变量的完整列表可在 /usr/ports/Mk/Uses/tcl.mk 中找到。

6.20. 使用 SDL

USE_SDL 用于自动配置使用基于 SDL 的库的端口的依赖项,例如 devel/sdl12graphics/sdl_image

以下 SDL 库(版本 1.2)已得到识别

这些 SDL 库的 2.0 版本被识别

因此,如果某个端口依赖于 net/sdl_netaudio/sdl_mixer,语法将是

USE_SDL=	net mixer

依赖项 devel/sdl12,它被 net/sdl_netaudio/sdl_mixer 所需,也会被自动添加。

使用 USE_SDL 为 SDL 1.2 添加条目,它会自动

  • BUILD_DEPENDS 中添加对 sdl12-config 的依赖

  • CONFIGURE_ENV 中添加变量 SDL_CONFIG

  • 将选定库的依赖项添加到 LIB_DEPENDS

使用 USE_SDL 为 SDL 2.0 添加条目,它会自动

  • BUILD_DEPENDS 中添加对 sdl2-config 的依赖

  • CONFIGURE_ENV 中添加变量 SDL2_CONFIG

  • 将选定库的依赖项添加到 LIB_DEPENDS

6.21. 使用 wxWidgets

本节介绍端口树中 wxWidgets 库的状态及其与端口系统的集成。

6.21.1. 简介

wxWidgets 库存在多个版本,它们之间存在冲突(安装文件使用相同的名称)。在端口树中,这个问题通过在不同的名称下安装每个版本,并使用版本号后缀来解决。

这种方法的明显缺点是每个应用程序都必须修改才能找到预期的版本。幸运的是,大多数应用程序调用 wx-config 脚本以确定必要的编译器和链接器标志。每个可用版本都使用不同的脚本名称。大多数应用程序会尊重一个环境变量,或者接受一个配置参数,以指定要调用的 wx-config 脚本。否则,它们需要进行修补。

6.21.2. 版本选择

为了让端口使用 wxWidgets 的特定版本,可以使用两个变量来定义(如果只定义一个变量,另一个变量将被设置为默认值)

表 28. 选择 wxWidgets 版本的变量
变量描述默认值

USE_WX

端口可以使用版本的列表

所有可用版本

USE_WX_NOT

端口不能使用的版本的列表

端口树中可用的 wxWidgets 版本和相应的端口为

表 29. 可用的 wxWidgets 版本
版本端口

2.8

x11-toolkits/wxgtk28

3.0

x11-toolkits/wxgtk30

这些变量在 选择 wxWidgets 版本的变量 可以设置为一个或多个组合,用空格隔开

表 30. wxWidgets 版本规范
描述示例

单个版本

2.8

升序范围

2.8+

降序范围

3.0-

完整范围(必须为升序)

2.8-3.0

还有一些变量用于从可用版本中选择首选版本。它们可以设置为版本的列表,第一个版本具有更高的优先级。

表 31. 选择首选 wxWidgets 版本的变量
名称为...设计

WANT_WX_VER

端口

WITH_WX_VER

用户

6.21.3. 组件选择

还有一些其他应用程序,虽然不是 wxWidgets 库,但与它们相关。这些应用程序可以在 WX_COMPS 中指定。这些组件是可用的

表 32. 可用的 wxWidgets 组件
名称描述版本限制

wx

主库

contrib

贡献库

python

wxPython (Python 绑定)

2.8-3.0

每个组件的依赖项类型可以通过添加以分号分隔的后缀来选择。如果不存在,则使用默认类型(见 默认的 wxWidgets 依赖项类型)。这些类型是可用的

表 33. 可用的 wxWidgets 依赖项类型
名称描述

build

构建组件所需,等效于 BUILD_DEPENDS

run

运行组件所需,等效于 RUN_DEPENDS

lib

构建和运行组件所需,等效于 LIB_DEPENDS

组件的默认值在该表中详细说明

表 34. 默认的 wxWidgets 依赖项类型
组件依赖项类型

wx

lib

contrib

lib

python

run

mozilla

lib

svg

lib

示例 28. 选择 wxWidgets 组件

此片段对应于使用 wxWidgets 2.4 版本及其贡献库的端口。

USE_WX=		2.8
WX_COMPS=	wx contrib

6.21.4. 检测已安装的版本

要检测已安装的版本,请定义 WANT_WX。如果未将其设置为特定版本,则组件将具有版本后缀。HAVE_WX 将在检测后填充。

示例 29. 检测已安装的 wxWidgets 版本和组件

如果已安装 wxWidgets,或者选择了某个选项,则此片段可以在使用 wxWidgets 的端口中使用。

WANT_WX=	yes

.include <bsd.port.pre.mk>

.if defined(WITH_WX) || !empty(PORT_OPTIONS:MWX) || !empty(HAVE_WX:Mwx-2.8)
USE_WX=			2.8
CONFIGURE_ARGS+=	--enable-wx
.endif

如果已安装 wxPython,或者选择了某个选项,以及 wxWidgets 版本 2.8,则此片段可以在启用 wxPython 支持的端口中使用。

USE_WX=		2.8
WX_COMPS=	wx
WANT_WX=	2.8

.include <bsd.port.pre.mk>

.if defined(WITH_WXPYTHON) || !empty(PORT_OPTIONS:MWXPYTHON) || !empty(HAVE_WX:Mpython)
WX_COMPS+=		python
CONFIGURE_ARGS+=	--enable-wxpython
.endif

6.21.5. 定义的变量

这些变量在端口中可用(在从 选择 wxWidgets 版本的变量 定义一个变量后)。

表 35. 为使用 wxWidgets 的端口定义的变量
名称描述

WX_CONFIG

wxWidgets`wx-config` 脚本的路径(使用不同的名称)

WXRC_CMD

wxWidgets`wxrc` 程序的路径(使用不同的名称)

WX_VERSION

将要使用的 wxWidgets 版本(例如,2.6

6.21.6. 在 bsd.port.pre.mk 中的处理

定义 WX_PREMK 可以在包含 bsd.port.pre.mk 后立即使用这些变量。

当定义 WX_PREMK 时,如果在包含 bsd.port.pre.mk 之后修改 wxWidgets 端口变量,版本、依赖项、组件和定义的变量将不会改变。

示例 30. 在命令中使用 wxWidgets 变量

此片段说明了通过运行 wx-config 脚本获取完整的版本字符串、将其分配给变量并将其传递给程序,从而使用 WX_PREMK

USE_WX=		2.8
WX_PREMK=	yes

.include <bsd.port.pre.mk>

.if exists(${WX_CONFIG})
VER_STR!=	${WX_CONFIG} --release

PLIST_SUB+=	VERSION="${VER_STR}"
.endif

当 wxWidgets 变量位于目标内部时,可以在命令中安全地使用它们,而无需使用 WX_PREMK

6.21.7. 附加 configure 参数

某些 GNU configure 脚本无法仅通过设置 WX_CONFIG 环境变量来找到 wxWidgets,需要额外的参数。WX_CONF_ARGS 可用于提供这些参数。

表 36. WX_CONF_ARGS 的合法值
可能的值结果参数

absolute

--with-wx-config=${WX_CONFIG}

relative

--with-wx=${LOCALBASE} --with-wx-config=${WX_CONFIG:T}

6.22. 使用 Lua

本节介绍端口树中 Lua 库的状态及其与端口系统的集成。

6.22.1. 简介

Lua 库和相应的解释器存在多个版本,它们之间存在冲突(安装文件使用相同的名称)。在端口树中,这个问题通过在不同的名称下安装每个版本,并使用版本号后缀来解决。

这种方法的明显缺点是每个应用程序都必须修改才能找到预期的版本。但这可以通过向编译器和链接器添加一些额外的标志来解决。

使用 Lua 的应用程序通常只为一个版本构建。但是,为 Lua 构建的加载模块是为每个支持的 Lua 版本在不同的风格中构建的,对这些模块的依赖项应该使用 @${LUA_FLAVOR} 后缀指定端口源。

6.22.2. 版本选择

使用 Lua 的端口应该包含以下形式的行

USES=	lua

如果需要特定的 Lua 版本或版本范围,可以以 XY(可以多次使用)、XY+-XYXY-ZA 的形式指定参数。如果默认版本的 Lua(通过 DEFAULT_VERSIONS 设置)落在请求的范围内,则使用该版本,否则使用最接近请求范围的默认版本。例如

USES=	lua:52-53

请注意,不会尝试根据任何已安装的 Lua 版本的存在来调整版本选择。

XY+ 版本规范形式应谨慎使用;Lua API 在每个版本中都会发生一些变化,并且 CMake 或 Autoconf 等配置工具通常无法在将来的 Lua 版本上工作,直到更新到支持为止。

6.22.3. 配置和编译器标志

使用 Lua 的软件可能是为了自动检测正在使用的 Lua 版本而编写的。通常,端口应该覆盖这种假设,并强制使用上面描述的特定 Lua 版本。根据正在移植的软件,这可能需要以下任何或所有操作

  • 通过 CONFIGURE_ARGSCONFIGURE_ENV(或其他构建系统的等效项)使用 LUA_VER 作为软件配置脚本的参数;

  • 根据需要将 -I${LUA_INCDIR}-L${LUA_LIBDIR}-llua-${LUA_VER} 分别添加到 CFLAGSLDFLAGSLIBS 中;

  • 修补软件的配置或构建文件以选择正确的版本。

6.22.4. 版本风格

安装 Lua 模块的端口(而不是仅仅使用 Lua 的应用程序)应该为每个支持的 Lua 版本构建一个单独的版本。这可以通过添加module参数来实现。

USES=	lua:module

也可以指定版本号或版本范围;使用逗号分隔参数。

由于每个版本都必须有不同的包名,因此提供了LUA_PKGNAMEPREFIX变量,它将被设置为一个适当的值;预期用法为

PKGNAMEPREFIX=	${LUA_PKGNAMEPREFIX}

模块端口通常只应将文件安装到LUA_MODLIBDIRLUA_MODSHAREDIRLUA_DOCSDIRLUA_EXAMPLESDIR中,所有这些目录都设置为引用特定于版本的子目录。安装任何其他文件必须谨慎,以避免不同版本之间发生冲突。

一个(非 Lua 模块)端口,希望为每个 Lua 版本构建一个单独的包,应该使用flavors参数

USES=	lua:flavors

它的操作方式与上面描述的module参数相同,但没有假设包应该被记录为 Lua 模块(因此LUA_DOCSDIRLUA_EXAMPLESDIR默认情况下未定义)。但是,该端口可以选择将LUA_DOCSUBDIR定义为一个合适的子目录名(通常是该端口的PORTNAME,只要不与任何模块的PORTNAME冲突),在这种情况下,框架将同时定义LUA_DOCSDIRLUA_EXAMPLESDIR

与模块端口一样,带有版本的端口应该避免安装会导致不同版本之间发生冲突的文件。通常,这是通过在程序名称中添加LUA_VER_STR作为后缀来实现的(例如,使用uniquefiles),并在LUA_MODLIBDIRLUA_MODSHAREDIR之外使用LUA_VERLUA_VER_STR作为任何其他文件或子目录的一部分。

6.22.5. 定义的变量

这些变量在端口中可用。

表 37. 为使用 Lua 的端口定义的变量
名称描述

LUA_VER

将要使用的 Lua 版本(例如,5.4

LUA_VER_STR

没有点的 Lua 版本(例如,54

LUA_FLAVOR

与所选 Lua 版本相对应的版本名称,用于指定依赖关系

LUA_BASE

用于查找已安装的 Lua(及其组件)的路径前缀

LUA_PREFIX

该端口将安装 Lua(及其组件)的前缀

LUA_INCDIR

安装 Lua 头文件的目录

LUA_LIBDIR

安装 Lua 库的目录

LUA_REFMODLIBDIR

已安装的 Lua 模块库(.so)的目录

LUA_REFMODSHAREDIR

已安装的 Lua 模块(.lua)的目录

LUA_MODLIBDIR

该端口将安装 Lua 模块库(.so)的目录

LUA_MODSHAREDIR

该端口将安装 Lua 模块(.lua)的目录

LUA_PKGNAMEPREFIX

Lua 模块使用的包名前缀

LUA_CMD

Lua 解释器的名称(例如,lua54

LUAC_CMD

Lua 编译器的名称(例如,luac54

以下额外变量适用于指定了module参数的端口

表 38. 为 Lua 模块端口定义的变量
名称描述

LUA_DOCSDIR

应安装模块文档的目录。

LUA_EXAMPLESDIR

应安装模块示例文件的目录。

6.22.6. 示例

示例 31. 使用 Lua 的应用程序的 Makefile

本示例展示了如何引用运行时所需的 Lua 模块。请注意,引用必须指定一个版本。

PORTNAME=	sample
DISTVERSION=	1.2.3
CATEGORIES=	whatever

MAINTAINER=	[email protected]
COMMENT=	Sample
WWW=		https://example.com/lua_sample/sample/

RUN_DEPENDS=	${LUA_REFMODLIBDIR}/lpeg.so:devel/lua-lpeg@${LUA_FLAVOR}

USES=		lua

.include <bsd.port.mk>
示例 32. 简单 Lua 模块的 Makefile
PORTNAME=	sample
DISTVERSION=	1.2.3
CATEGORIES=	whatever
PKGNAMEPREFIX=	${LUA_PKGNAMEPREFIX}

MAINTAINER=	[email protected]
COMMENT=	Sample
WWW=		https://example.com/lua_sample/sample/

USES=		lua:module

DOCSDIR=	${LUA_DOCSDIR}

.include <bsd.port.mk>

6.23. 使用 Guile

本节描述了 Guile 在端口树中的状态及其与端口系统的集成。

6.23.1. 简介

Guile 库及其对应的解释器有多个版本,这些版本之间存在冲突(在同一个名称下安装文件)。在端口树中,这个问题已经通过使用版本号后缀在不同的名称下安装每个版本来解决。在大多数情况下,应用程序应该从提供的配置变量中检测到正确的版本,并使用pkg-config来确定名称和关联的路径。但是,一些应用程序(尤其是那些使用自己的配置规则来使用cmakemeson的应用程序)将始终尝试使用最新的可用版本。在这种情况下,请修补端口或声明构建冲突(参见下面的conflicts选项),以确保在 Poudriere 之外构建时生成正确的依赖项。

使用 Guile 的应用程序通常只应该为一个版本构建,最好是DEFAULT_VERSIONS中指定的版本,或者在没有指定版本的情况下,使用它们支持的最新版本。但是,Guile 或 Scheme 库,或者 Guile 的扩展模块,是为它们支持的每个 Guile 版本构建一个单独的版本,对这些端口的依赖关系应该使用@${GUILE_FLAVOR}后缀在端口来源上指定版本。

6.23.2. 版本选择

使用 Guile 的端口应该定义USES=guile:arg,arg…​,并使用适当的参数,如下所示

表 39. 为使用 Guile 的端口定义的参数
名称描述

X.Y

声明与 Guile 版本X.Y兼容。当前可用的版本是1.8(已过时)、2.23.0。可以指定多个版本。

flavors

为每个指定的 Guile 版本创建一个版本。由DEFAULT_VERSIONS指定的版本将成为默认版本。版本名称的形式为guileXY

build

仅将 Guile 解释器添加为构建依赖项,而不是库依赖项。buildrun都可以指定。

run

仅将 Guile 解释器添加为运行时依赖项,而不是库依赖项。buildrun都可以指定。

alias

为解释器和工具添加BINARY_ALIAS值。

conflicts

为比所选版本更新的 Guile 版本声明CONFLICTS_BUILD。当端口无法配置为使用特定 Guile 版本时,请使用此选项。

一些额外的参数可用于处理异常情况;有关详细信息,请参见Mk/Uses/guile.mk

除非指定了buildrun,否则LIB_DEPENDS将接收libguile库依赖项,以及 Guile 版本所需的任何其他依赖项,例如libgc。通常,该端口不需要与 Guile 使用相关的任何其他依赖项。

6.23.3. 配置标志

使用 Guile 的软件应该使用pkg-config机制来获取编译器和链接器标志。一些旧的或奇特的端口可能使用guile-config或直接从guile获取值,这同样可以工作(在某些情况下,alias参数可能有用)。

框架试图通过以下方法通知端口所需的 Guile 版本

  • GUILE_EFFECTIVE_VERSION被添加到CONFIGURE_ENV中;

  • Guile 二进制文件的完整路径在CONFIGURE_ENVMAKE_ENVGUILE变量中指定;

  • 如果使用了alias选项,则将使用所需的 Guile 版本的二进制文件进行别名处理;

  • 如果未使用alias选项,则将所需 Guile 版本的工具(guildguile-config等)的路径添加到CONFIGURE_ENVMAKE_ENV中,作为变量GUILDGUILE_CONFIG等。

对于某些端口,可能需要通过其他方式指定版本,例如,通过CONFIGURE_ARGSMESON_ARGS,具体取决于端口。

如果这些方法都没有导致端口在存在其他版本的情况下选择指定的 Guile 版本,那么最好修补端口以使其这样做。如果无法实现,请指定conflicts选项以防止在端口将检测到错误的版本的情况下构建端口。

6.23.4. 版本版本

安装 Guile 扩展或库,或者为 Guile 预编译的 Scheme 库的端口,应该为每个支持的 Guile 版本构建一个单独的版本。这可以通过添加flavors选项来实现。

由于每个版本都必须有不同的包名,因此此类端口必须设置PKGNAMESUFFIX,通常为

PKGNAMESUFFIX=	-${FLAVOR}

此类端口必须将 Scheme 文件安装到GUILE_SITE_DIR,而不是安装到GUILE_GLOBAL_SITE_DIR,即使这些文件不是特定于版本的。这通常需要修补端口。

此外,如果此类端口安装了.pc文件,则必须将其放置在GUILE_PKGCONFIG_PATH中,而不是放置在全局pkgconfig目录中。这允许依赖的端口找到使用中的特定 Guile 版本的正确配置。

如果 Guile 扩展端口安装了.so文件,则通常必须将其放置在特定于 Guile 版本的extensions目录中。USE_LDCONFIG通常不应该使用。

带有版本的端口安装的任何其他文件也必须位于特定于版本的目录中,或者使用特定于版本的文件名。对于文档和示例,GUILE_DOCS_DIRGUILE_EXAMPLES_DIR指定了端口应该在其中创建子目录的合适位置,请参见下文。

6.23.5. 定义的变量

这些变量在端口中可用。

表 40. 为使用 Guile 的端口定义的变量
名称示例值描述

GUILE_VER

3.0

正在使用的 Guile 版本。

GUILE_SFX

3

在某些名称上使用的简短后缀。仅谨慎使用;将来可能不唯一或可能更改。

GUILE_FLAVOR

guile30

与所选版本相对应的版本名称。

GUILE_PORT

lang/guile3

指定 Guile 版本的端口来源。

GUILE_PREFIX

${PREFIX}

用于安装的目录前缀。

GUILE_CMD

guile-3.0

Guile 解释器的名称,带有版本后缀。

GUILE_CMDPATH

${LOCALBASE}/bin/guile-3.0

Guile 解释器的完整路径。

GUILD_CMD

guild-3.0

Guild 工具的名称,带有版本后缀。

GUILD_CMDPATH

${LOCALBASE}/bin/guild-3.0

Guild 工具的完整路径。

GUILE_*_CMD
GUILE_*_CMDPATH

GUILE_CMDGUILE_CMDPATH类似,但适用于其他工具二进制文件。

GUILE_PKGCONFIG_PATH

${LOCALBASE}/libdata/pkgconfig/guile/3.0

使用flavors的包应安装.pc文件的位置。

GUILE_INFO_PATH

share/info/guile3

使用flavors选项的端口的INFO_PATH的合适值。

以下内容定义为变量和PLIST_SUB条目。变量形式以_DIR结尾,是一个完整路径(以GUILE_PREFIX为前缀)。

表 41. 为使用 Guile 的端口定义的路径替换
名称示例值描述

GUILE_GLOBAL_SITE

share/guile/site

所有 Guile 版本共享的站点目录;通常不应使用此目录。

GUILE_SITE

share/guile/3.0/site

所选 Guile 版本的站点目录。

GUILE_SITE_CCACHE

lib/guile/3.0/site-ccache

编译后的字节码文件目录。

GUILE_DOCS

share/doc/guile30

特定版本文档的父目录。

GUILE_EXAMPLES

share/examples/guile30

特定版本示例的父目录。

6.23.6. 示例

示例 33. 使用 Guile 的应用程序的 Makefile

本示例演示如何引用在构建和运行时所需的 Guile 库。请注意,引用必须指定一种风格。本示例假设应用程序使用 pkg-config 来查找依赖项。

PORTNAME=	sample
DISTVERSION=	1.2.3
CATEGORIES=	whatever

MAINTAINER=	[email protected]
COMMENT=	Sample
WWW=		https://example.com/guile_sample/sample/

BUILD_DEPENDS=	guile-lib-${GUILE_FLAVOR}>=0.2.5:devel/guile-lib@${GUILE_FLAVOR}
RUN_DEPENDS=	guile-lib-${GUILE_FLAVOR}>=0.2.5:devel/guile-lib@${GUILE_FLAVOR}

USES=		guile:2.2,3.0 pkgconfig

.include <bsd.port.mk>

6.24. 使用 iconv

FreeBSD 在操作系统中具有原生 iconv

对于需要 iconv 的软件,定义 USES=iconv

当端口定义 USES=iconv 时,以下变量将可用

变量名称用途端口 iconv(使用 WCHAR_T 或 //TRANSLIT 扩展时)基础 iconv

ICONV_CMD

iconv 二进制文件所在的目录

${LOCALBASE}/bin/iconv

/usr/bin/iconv

ICONV_LIB

用于链接到 libiconv(如果需要)的 ld 参数

-liconv

(空)

ICONV_PREFIX

iconv 实现所在的目录(对配置脚本有用)

${LOCALBASE}

/usr

ICONV_CONFIGURE_ARG

为配置脚本预先构建的配置参数

--with-libiconv-prefix=${LOCALBASE}

(空)

ICONV_CONFIGURE_BASE

为配置脚本预先构建的配置参数

--with-libiconv=${LOCALBASE}

(空)

这两个示例会自动将变量填充为使用 converters/libiconv 或原生 iconv 的系统所对应的正确值。

示例 34. 简单的 iconv 用法
USES=		iconv
LDFLAGS+=	-L${LOCALBASE}/lib ${ICONV_LIB}
示例 35. 使用 configureiconv 用法
USES=		iconv
CONFIGURE_ARGS+=${ICONV_CONFIGURE_ARG}

如上所示,当存在原生 iconv 时,ICONV_LIB 为空。这可用于检测原生 iconv 并做出相应的响应。

有时,程序会在 Makefile 或配置脚本中硬编码 ld 参数或搜索路径。这种方法可以用于解决该问题。

示例 36. 修复硬编码的 -liconv
USES=		iconv

post-patch:
	@${REINPLACE_CMD} -e 's/-liconv/${ICONV_LIB}/' ${WRKSRC}/Makefile

在某些情况下,需要根据是否存在原生 iconv 设置备用值或执行操作。必须在测试 ICONV_LIB 的值之前包含 bsd.port.pre.mk

示例 37. 检查原生 iconv 的可用性
USES=		iconv

.include <bsd.port.pre.mk>

post-patch:
.if empty(ICONV_LIB)
	# native iconv detected
	@${REINPLACE_CMD} -e 's|iconv||' ${WRKSRC}/Config.sh
.endif

.include <bsd.port.post.mk>

6.25. 使用 Xfce

需要 Xfce 库或应用程序的端口设置 USES=xfce

使用分配给 USE_XFCE 的值设置特定的 Xfce 库和应用程序依赖项。它们在 /usr/ports/Mk/Uses/xfce.mk 中定义。可能的值如下:

示例 38. USES=xfce 示例
USES=		xfce
USE_XFCE=	libmenu
示例 39. 使用 Xfce 自身的 GTK2 小部件

在本示例中,移植的应用程序使用 GTK2 特定的窗口小部件 x11/libxfce4menux11/xfce4-conf

USES=		xfce:gtk2
USE_XFCE=	libmenu xfconf

以这种方式包含的 Xfce 组件会自动包含它们需要的任何依赖项。不再需要指定整个列表。如果端口只需要 x11-wm/xfce4-panel,则使用

USES=		xfce
USE_XFCE=	panel

无需像这样列出 x11-wm/xfce4-panel 本身需要的组件

USES=		xfce
USE_XFCE=	libexo libmenu libutil panel

但是,必须明确包含 Xfce 组件和端口的非 Xfce 依赖项。不要指望 Xfce 组件为主要端口提供除自身以外的子依赖项。

6.26. 使用 Budgie

依赖 Budgie 桌面的应用程序或库应设置 USES= budgie 并将 USE_BUDGIE 设置为所需组件的列表。

名称描述

libbudgie

桌面核心(库)

libmagpie

Budgie 的 X11 窗口管理器和合成器库

raven

面板中用于访问不同应用程序小部件的全功能中心

screensaver

特定于桌面的屏幕保护程序

所有应用程序小部件都通过 org.budgie_desktop.Raven 服务进行通信。

默认依赖项是 lib 和 run-time,可以使用 :build:run 进行更改,例如

USES=		budgie
USE_BUDGIE=	screensaver:build
示例 40. USE_BUDGIE 示例
USES=		budgie gettext gnome meson pkgconfig
USE_BUDGIE=	libbudgie

6.27. 使用数据库

使用 数据库 USES 中的某个 USES 宏来添加对数据库的依赖项。

表 42. 数据库 USES
数据库USES 宏

Berkeley DB

bdb

MariaDB、MySQL、Percona

mysql

PostgreSQL

pgsql

SQLite

sqlite

示例 41. 使用 Berkeley DB 6
USES=	bdb:6

有关更多信息,请参见 bdb

示例 42. 使用 MySQL

当端口需要 MySQL 客户端库时,添加

USES=	mysql

有关更多信息,请参见 mysql

示例 43. 使用 PostgreSQL

当端口需要 PostgreSQL 服务器版本 9.6 或更高版本时,添加

USES=		pgsql:9.6+
WANT_PGSQL=	server

有关更多信息,请参见 pgsql

示例 44. 使用 SQLite 3
USES=	sqlite:3

有关更多信息,请参见 sqlite

6.28. 启动和停止服务(rc 脚本)

rc.d 脚本用于在系统启动时启动服务,并为管理员提供一种标准方法来停止、启动和重启服务。端口会集成到系统 rc.d 框架中。有关其用法的详细信息,请参见 rc.d 手册章节。有关可用命令的详细说明,请参见 rc(8)rc.subr(8)。最后,还提供了一篇关于 rc.d 脚本的实用方面的 文章

假设有一个名为 doorman 的虚拟端口,它需要启动一个名为 doormand 的守护进程。在 Makefile 中添加以下内容:

USE_RC_SUBR=	doormand

可以列出多个脚本,并将安装这些脚本。脚本必须放在 files 子目录中,并且必须在其文件名中添加 .in 后缀。标准 SUB_LIST 扩展将针对此文件运行。强烈建议使用 %%PREFIX%%%%LOCALBASE%% 扩展。有关 SUB_LIST 的更多信息,请参见 相关部分

从 FreeBSD 6.1-RELEASE 开始,本地 rc.d 脚本(包括端口安装的脚本)将包含在基础系统的整体 rcorder(8) 中。

用于启动 doormand 守护进程的简单示例 rc.d 脚本

#!/bin/sh

# PROVIDE: doormand
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# Add these lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# doormand_enable (bool):	Set to NO by default.
#				Set it to YES to enable doormand.
# doormand_config (path):	Set to %%PREFIX%%/etc/doormand/doormand.cf
#				by default.

. /etc/rc.subr

name=doormand
rcvar=doormand_enable

load_rc_config $name

: ${doormand_enable:="NO"}
: ${doormand_config="%%PREFIX%%/etc/doormand/doormand.cf"}

command=%%PREFIX%%/sbin/${name}
pidfile=/var/run/${name}.pid

command_args="-p $pidfile -f $doormand_config"

run_rc_command "$1"

除非有充分的理由提前启动服务或它以特定用户(root 以外)身份运行,否则所有端口脚本都必须使用

REQUIRE: LOGIN

如果启动脚本启动必须关闭的守护进程,以下操作将在系统关闭时触发服务的停止

KEYWORD: shutdown

如果脚本没有启动持久服务,则不需要此操作。

对于可选的配置元素,使用 "=" 风格的默认变量分配优于此处使用的 ":=" 风格,因为前者仅在变量未设置时设置默认值,而后者在变量未设置或为 null 时设置默认值。用户可能会在他们的 rc.conf.local 中包含类似于以下的内容:

doormand_flags=""

而使用 ":=" 进行变量替换将不适当地覆盖用户的意图。_enable 变量不是可选的,必须使用 ":" 来设置默认值。

端口绝不能在安装和卸载时启动和停止其服务。不要通过运行修改当前正在运行的系统的命令(包括启动或停止服务)来滥用 @preexec 命令、@postexec 命令、@preunexec 命令、@postunexec 命令部分 中描述的 plist 关键字。

6.28.1. 提交前检查清单

在贡献包含 rc.d 脚本的端口,更重要的是,在提交此类脚本之前,请参阅此检查清单,确保它已准备好。

devel/rclint 端口可以检查大多数问题,但它不能代替适当的审查。

  1. 如果这是一个新文件,它是否具有 .sh 扩展名?如果是,则必须将其更改为仅 file.in,因为 rc.d 文件不能以该扩展名结尾。

  2. 文件名称(减去 .in)、PROVIDE 行和 $ name 是否都匹配?文件名称匹配 PROVIDE 使调试更容易,特别是对于 rcorder(8) 问题。文件名称和 `$`name 匹配使确定 rc.conf[.local] 中哪些变量相关更加容易。它也是所有新脚本(包括基础系统中的脚本)的策略。

  3. REQUIRE 行是否设置为 LOGIN?对于以非 root 用户身份运行的脚本,这是强制性的。如果它以 root 身份运行,是否有一个充分的理由让它在 LOGIN 之前运行?如果没有,它必须在之后运行,以便本地脚本可以在 rcorder(8) 中的某个点之后运行,该点位于基础系统中大多数内容已运行之后。

  4. 脚本是否启动持久服务?如果是,则必须具有 KEYWORD: shutdown

  5. 确保没有 KEYWORD: FreeBSD 存在。多年来,这既不必要也不可取。它也表明新脚本是从旧脚本复制粘贴的,因此必须格外小心地进行审查。

  6. 如果脚本使用解释性语言(如 perlpythonruby),请确保 command_interpreter 设置正确,例如,对于 Perl,通过将 PERL=${PERL} 添加到 SUB_LIST 并使用 %%PERL%%。否则,

    # service name stop

    可能无法正常工作。有关更多信息,请参见 service(8)

  7. 是否已将所有 /usr/local 出现的情况替换为 %%PREFIX%%

  8. 默认变量分配是否在 load_rc_config 之后出现?

  9. 是否存在对空字符串的默认分配?它们应该被删除,但请仔细检查该选项是否在文件开头的注释中记录。

  10. 在变量中设置的内容是否在脚本中实际使用?

  11. 默认 name`_flags` 中列出的选项是否实际上是强制性的?如果是,则它们必须在 command_args 中。-d 在这里是一个危险信号(双关语),因为它通常是将进程“守护进程化”的选项,因此实际上是强制性的。

  12. _name__flags 绝不能包含在 command_args 中(反之亦然,尽管这种情况不太常见)。

  13. 脚本是否无条件执行任何代码?这种做法是不被推荐的。通常,这些事情必须通过 start_precmd 来处理。

  14. 所有布尔测试必须使用 checkyesno 函数。不要手动测试 [Yy][Ee][Ss] 等。

  15. 如果存在循环(例如,等待某个东西启动),它是否包含一个计数器来终止循环?如果出现错误,我们不希望引导过程永远卡住。

  16. 脚本是否创建需要特定权限的文件或目录,例如,一个需要由运行该进程的用户拥有的 pid?与传统的 touch(1)/chown(8)/chmod(1) 例程相比,请考虑使用 install(1) 以及适当的命令行参数,一步完成整个过程。

6.29. 添加用户和组

一些端口需要存在特定用户帐户,通常用于以该用户身份运行的守护进程。对于这些端口,请从 50 到 999 中选择一个唯一 的 UID,并在 ports/UIDs(对于用户)和 ports/GIDs(对于组)中注册它。用户和组的唯一标识应该相同。

如果需要为端口创建新的用户或组,请包含针对这两个文件的补丁。

然后在 Makefile 中使用 USERSGROUPS,在安装端口时会自动创建该用户。

USERS=	pulse
GROUPS=	pulse pulse-access pulse-rt

当前的保留 UID 和 GID 列表可以在 ports/UIDsports/GIDs 中找到。

6.30. 依赖内核源代码的端口

一些端口(如内核可加载模块)需要内核源代码文件才能编译。以下是确定用户是否已安装内核源代码的正确方法

USES=	kmod

除了此检查之外,kmod 功能还处理了这些端口需要考虑的大多数项目。

6.31. Go 库

端口不得打包或安装 Go 库或源代码。Go 端口必须在正常的获取时间获取所需的依赖项,并且只应安装用户需要的程序和东西,而不是 Go 开发人员需要的東西。

端口应(按优先级排序)

  • 使用打包源代码中包含的供应商依赖项。

  • 获取上游指定的依赖项版本(在 go.mod、vendor.json 或类似文件中)。

  • 作为最后的手段(依赖项未包含或版本未完全指定),获取上游开发/发布时可用的依赖项版本。

6.32. Haskell 库

与 Go 语言一样,端口不得打包或安装 Haskell 库。Haskell 端口必须静态链接到其依赖项,并在获取阶段获取所有分发文件。

6.33. Shell 自动完成文件

许多现代 Shell(包括 bash、fish、tcsh 和 zsh)支持参数和/或选项的 Tab 自动完成。这种支持通常来自自动完成文件,其中包含关于某个命令如何进行 Tab 自动完成的定义。端口有时会附带自己的自动完成文件,或者移植者可能自己创建了这些文件。

如果可用,自动完成文件应始终安装。没有必要为此创建一个选项。如果使用了一个选项,则始终在 OPTIONS_DEFAULT 中启用它。

表 43. 完整的 Shell 自动完成文件名

bash

${PREFIX}/etc/bash_completion.d${PREFIX}/share/bash-completion/completions

(这些文件夹中的任何唯一文件名)

fish

${PREFIX}/share/fish/completions/${PORTNAME}.fish

zsh

${PREFIX}/share/zsh/site-functions/_${PORTNAME}

不要注册任何对 Shell 本身的依赖项。


上次修改时间:2024 年 10 月 16 日,作者 Fernando Apesteguía