6.5.编译机制

6.5.1. 平行构建 Port

FreeBSD ports 框架支持使用多个 make 子进程进行并行联编, 这使得 SMP 系统能够利用其所有可用的 CPU 能力, 使得 port 联编更加快速和有效。

这可以通过向运行在供应商代码上的 make(1) 传递 -jX 标志来实现。这是 ports 的默认联编行为。不幸的是, 并非所有的 port 都能很好地处理并行联编, 因此可能需要通过加入 MAKE_JOBS_UNSAFE=yes 变量来明确地禁用这一功能。当已知某个 port 由于竞赛条件导致间歇性联编失败而被 -jX 破坏时, 就会使用这个变量。

重要

在设置 MAKE_JOBS_UNSAFE 时, 非常重要的一点是在 Makefile 中的注释, 或至少在提交消息中解释为什么在启用时 Port 不能生成。否则, 就不可能修复这个问题, 或在以后提交更新时测试它是否被修复了。

6.5.2. make, gmake, and imake

存在几种不同的 make 实现。被移植的软件通常需要一个特定的实现,比如 GNUmake,在 FreeBSD 中被称为 gmake

如果 port 使用 GNU make, 应在 USES 中加入 gmake

MAKE_CMD 可以用来引用在 port 的 Makefile 中通过 USES 设置配置的特定命令。只能在 WRKSRC 中的应用程序 Makefile 中使用 MAKE_CMD 来调用被移植软件所期望的 make 实现。

如果 port 是一个使用 imake 来从 Imakefile 创建 Makefile 的 X 应用程序, 则应设置 USES= imake。请参阅 Using USES Macros 中的 USES=imake 一节, 以了解更多细节。

如果 port 的源码 Makefile 中的主要联编目标不是 all, 则应相应地设置 ALL_TARGETinstallINSTALL_TARGET 也是如此。

## 6.5.3. 配置脚本

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

表9. 使用 configure 的 Port 的变量

变化的手段

GNU_CONFIGURE

该 Port 使用 configure 脚本来准备构建。

HAS_CONFIGURE

GNU_CONFIGURE相同,只是默认的配置目标没有添加到CONFIGURE_ARGS中。

CONFIGURE_ARGS

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

CONFIGURE_ENV

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

CONFIGURE_TARGET

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

6.5.4. Using cmake

对于使用 CMake 的 Port , 应定义 USES= cmake

表 10. 使用 cmake 的 Port 的变量

变化的手段

CMAKE_ARGS

传递给 cmake 二进制文件的特定 CMake Port 标志。

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 二进制文件设置的额外环境变量。

表 11. 用户可以为 cmake 构建定义的变量

VariableMeans

CMAKE_NOCOLOR

禁用彩色构建输出。默认不设置,除非设置了 BATCHPACKAGE_BUILDING

CMake 支持这些构建配置文件: Debug, Release, RelWithDebInfoMinSizeRelDebugRelease 配置文件尊重系统 *FLAGSRelWithDebInfoMinSizeRel 将相应地把 CFLAGS 设置为 -O2 -g-Os -DNDEBUGCMAKE_BUILD_TYPE 的小写值会被导出到 PLIST_SUB, 如果 port 根据联编类型安装 *.cmake, 就必须使用它 (参见 devel/kf5-kcrash 的例子)。请注意, 有些项目可能会通过在 CMakeLists.txt 中设置 CMAKE_BUILD_TYPE 来定义自己的联编配置文件和 / 或强制使用特定的联编类型。要为这样的项目制作一个尊重 CFLAGSWITH_DEBUGport, 必须从这些文件中删除 CMAKE_BUILD_TYPE 的定义。

大多数基于 CMake 的项目都支持源外构建的方法。port 的源外联编是默认设置。可以通过使用 :insource 后缀来请求源内联编。在进行源外联编时, CONFIGURE_WRKSRCBUILD_WRKSRCINSTALL_WRKSRC 将被设置为 ${WRKDIR}/.build, 这个目录将被用来保存所有在配置和联编阶段生成的文件, 而源目录则保持不变。

例55. USES= cmake 示例

这个片段演示了 CMake 在 port 中的使用。CMAKE_SOURCE_PATH 通常不是必需的, 但当源代码不在顶层目录中, 或只有项目的一个子集打算由 port 构建时, 可以设置它。

USES=			cmake
CMAKE_SOURCE_PATH=	${WRKSRC}/subproject

例56. CMAKE_ON 和 CMAKE_OFF

当向 CMAKE_ARGS 添加布尔值时,使用 CMAKE_ONCMAKE_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.5.5. 使用scons

如果这个 Port 使用 SCons, 则应定义 USES=scons

为了使第三方 SConstruct 尊重环境中传递给 SCons 的一切(也就是最重要的 CC/CXX/CFLAGS/CXXFLAGS),给 SConstruct 打上补丁,使构建环境的方式是这样的:

env = Environment(**ARGUMENTS)

6.5.6. 用货物构建Rust应用程序

对于使用货物的 Ports ,定义 USES=cargo

表12. 用户可以为货物构建定义的变量

VariableDefaultDescription

CARGO_CRATES

此 port 所依赖的 crates 的列表。每个条目都需要有类似 cratename-semver 的格式, 例如, libc-0.2.40。 Port 维护者可以使用 make cargo-cratesCargo.lock 中生成这个列表。可以手动调整板条箱的版本,但要注意跨平台的依赖关系。如果由 make cargo-crates 生成的列表很大, 把它放在顶层 port 目录中的 Makefile.crates 文件中可能会比较方便。如果有的话, ports 框架会自动将这个文件作为源代码。这有助于将主 port 的 Makefile 保持在一个可管理的大小。

CARGO_FEATURES

要建立的应用功能列表(空格分隔的列表)。要停用所有的默认功能,请在 CARGO_FEATURES 中加入特殊标记 --no-default-features。不需要手动传递给 CARGO_BUILD_ARGSCARGO_INSTALL_ARGSCARGO_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

.

要安装的箱体的路径。这是通过 --路径参数传递给 cargo install 的。如果指定了多个路径,cargo install 会被多次运行。

CARGO_TEST

yes

使用默认的 do-test

CARGO_TEST_ARGS

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

CARGO_TARGET_DIR

${WRKDIR}/target

货物输出目录的位置。

CARGO_DIST_SUBDIR

rust/crates

相对于 DISTDIR 的目录,该目录将存储 crate 分布文件。

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

例57. 为一个简单的 Rust 应用程序创建一个 Port

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

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

MAINTAINER=	tobik@FreeBSD.org
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 中解压 crate 依赖:

% 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=	tobik@FreeBSD.org
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 需要重新生成,以包含所有的 crate 分布文件:

% 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/.
[...]

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

如果您不是在像 Poudriere 那样的干净环境中测试您的 port, 请记得在进行任何测试之前运行 make clean

例58. 启用额外的应用功能

一些应用程序在其 Cargo.toml 中定义了额外的功能。它们可以通过在 port 中设置 CARGO_FEATURES 而被编译进来。

这里我们启用 Tokei 的 jsonyaml 功能:

CARGO_FEATURES=	json yaml

例59. 将应用功能编码为 Port 选项

Cargo.toml 中的 [功能] 部分的例子可以是这样的:

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

pulseaudio_backend 是一个默认功能。除非我们通过在 CARGO_FEATURES 中加入 --no-default-features 来明确地关闭默认功能, 否则它总是被启用。这里我们把 portaudio_backend 和 pulseaudio_backend 特性变成了 Port 选项:

CARGO_FEATURES=	--no-default-features

OPTIONS_DEFINE=	PORTAUDIO PULSEAUDIO

PORTAUDIO_VARS=		CARGO_FEATURES+=portaudio_backend
PULSEAUDIO_VARS=	CARGO_FEATURES+=pulseaudio_backend

例60. 列出箱体许可

Crates 有自己的许可证。在向 port 添加 LICENSE 块时, 必须知道它们是什么 (参见 Licenses)。辅助工具 target 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
[...]

注意

cargo-crates-licenses 输出的许可证名称是 SPDX 2.1 许可证表达式, 与 ports 框架中定义的许可证名称不一致。它们需要被翻译成预定义许可证列表中的名称。

6.5.7. 使用介子

对于使用 Meson 的 Port , 应定义 USES=meson

表 13. 使用 meson 的 Port 的变量

VariableDescription

MESON_ARGS

传递给 meson 二进制的特定 Port Meson 标志。

MESON_BUILD_DIR

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

例61. USES=meson 例子

这个片段演示了 Meson 在一个 Port 的使用。

USES=		meson
MESON_ARGS=	-Dfoo=enabled

6.5.8. 构建围棋应用

对于使用 Go 的 port, 应定义 USES=go。参考 go 以了解可以用来控制联编过程的变量列表。

例62. 为基于 Go 模块的应用程序创建一个 Port

在大多数情况下,将 GO_MODULE 变量设置为 go.mod 中的模块指令所指定的值即可:

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

MAINTAINER=     dmgk@FreeBSD.org
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 的 Port 是一个五阶段的过程。首先我们需要提供一个 ports 模板,以获取应用程序的分发文件:

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

MAINTAINER=	tobik@FreeBSD.org
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=	tobik@FreeBSD.org
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
[...]

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

如果您不是在像 Poudriere 那样的干净环境中测试您的 port, 请记得在进行任何测试之前运行 make clean

例63. 设置输出二进制名称或安装路径

有些 port 需要将生成的二进制文件安装在不同的名字下, 或安装到默认的 ${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.5.9. 用 cabal 构建 Haskell 应用程序

对于使用 Cabal 的 port, 联编系统会定义 USES=cabal。请参阅 cabal 以了解可以用来控制联编过程的变量列表。

例64. 为 Hackage 托管的 Haskell 应用程序创建一个 Port

在准备 Haskell Cabal 移植时,需要用到 devel/hs-cabal-installports-mgmt/hs-cabal2tuple 程序,所以要确保它们事先安装好。首先,我们需要定义常见的 ports 变量,以便 cabal-install 能够获取软件包的分发文件:

PORTNAME=	ShellCheck
DISTVERSION=	0.6.0
CATEGORIES=	devel

MAINTAINER=	haskell@FreeBSD.org
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 来生成构建计划:

[...]
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 ports 一样。修订可能只影响 .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
[...]

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

如果您不是在像 Poudriere 那样的干净环境中测试您的 port, 请记得在进行任何测试之前运行 make clean

一些 Haskell port 会在 share/${PORTNAME} 下安装各种数据文件。对于这种情况, 需要在 port 端进行特殊处理。 Port 应该定义 CABAL_WRAPPER_SCRIPTS 旋钮, 列出每个要使用数据文件的可执行程序。此外, 在极少数情况下, 被移植的程序会使用其他 Haskell 包的数据文件, 在这种情况下, FOO_DATADIR_VARS 就会发挥作用。

例 65. 在 Haskell Port 中处理数据文件

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>

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

除了运行程序并检查是否一切正常外,没有简单的方法可以找出 FOO_DATADIR_VARS 旋钮的适当值。幸运的是,需要使用 FOO_DATADIR_VARS 的情况非常少。

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

例66. 用 VCS 的依赖关系移植 Haskell 应用程序

net-p2p/cardano-node 是一个极其复杂的软件。在其 cabal.project 中,有很多像这样的块:

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

source-repository-package 类型的依赖在构建过程中会被 cabal 自动拉入。不幸的是, 这将在获取阶段之后使用网络。这是 ports 框架所不允许的。这些源代码需要在 port 的 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 项目与其他项目分开, 以方便更新 port, 可能会很有用:

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 port 也暂时需要以下的 hack:

BINARY_ALIAS=	git=true

最后更新于

FreeBSD 中文社区