来自 Arch Linux 中文维基


Arch 打包准则

32 位CLRCMakeCrossDKMSEclipseElectronFontFree PascalGNOMEGoHaskellJavaKDEKernelLispMesonMinGWNode.jsNonfreeOCamlPerlPHPPythonRRubyRustVCSWebWine

本文档涵盖了为 Rust 软件编写 PKGBUILD 的标准和指南。

软件包命名

打包 Rust 项目时,软件包的名称应基本与生成的二进制文件名一致。请注意,打包库单元包 (library crate) 没有任何意义,只有带二进制文件的单元包 (crate) 才需要打包。对于生成多个二进制文件的包,通常使用上游单元包 (crate) 的名称较为合适。在任何情况下软件包的名称都应该小写。

源码

大多数 Rust 项目可以从 tarball、源归档文件(例如 GitHub Release 上的源链接)或其他已发布的源构建。另外,许多项目发布在 crates.io 上,该网站给 cargo 提供了稳定的 URL 下载方案。如果需要,PKGBUILD#source 可使用以下模板:

source=("$pkgname-$pkgver.tar.gz::https://static.crates.io/crates/$pkgname/$pkgname-$pkgver.crate")

依赖关系

虽然有些 Rust 项目有外部依赖,但大多数项目只使用在最终二进制文件中静态链接的 Rust 生态系统库。因此,大多数项目不需要指定很多 depends (依赖),只需要 makedepends (构建依赖)。绝大多数 Rust 项目都使用 cargo 依赖管理器构建,它会协调下载库以满足编译时的依赖关系,并执行所有必要的调用,使用真正的 Rust 编译器 rustc 进行编译。目前 cargorustc 都由 rust 提供,但也有其他方法可同时获取或单独获取这两个包,包括 rustup。因此,大多数 PKGBUILD 都会调用 cargo 工具,应该直接依赖它。

makedepends=(cargo)

如果项目需要使用开发版 Rust 工具链,请使用:

makedepends=(cargo-nightly)

准备工作

Rust 依赖管理器 cargo 能提前下载构建项目所需的所有库。在 prepare() 阶段进行下载,能使后续的 build() 和其他阶段完全离线运行。

prepare() {
    export RUSTUP_TOOLCHAIN=stable
    cargo fetch --locked --target "$CARCH-unknown-linux-gnu"
}

其中:

  • RUSTUP_TOOLCHAIN=stable 确保默认工具链被设置为稳定版,以防用户改变默认值。当然,如果在上游项目有特殊要求,则应被设置为开发版。此操作可避免在未使用 chroot 环境构建时受用户配置影响。另外,如果上游项目的源代码中有 rust-toolchain 文件或 rust-toolchain.toml 文件可实现此目的,则无需此步骤。
  • --locked 确保严格遵守 Cargo.lock 文件中指定的版本,防止其更新依赖关系。这对可重现构建很重要。
  • --target "$CARCH-unknown-linux-gnu" 确保只获取正在构建的特定目标平台所需的依赖项,从而减少下载量(参见 PKGBUILD#archRust 平台支持)。
注意: 在为上游源项目构建 VCS 软件包时,如果该项目在发布周期之间未保持 Cargo.lock 文件与 Cargo.toml 同步,请在运行 cargo fetch 之前添加 cargo update 。尽管结果并非完全可重现,但有关构建的其他所有方面都应符合上述内容,因为依赖关系将在构建时得到解决。

构建

构建 Rust 软件包。

build() {
    export RUSTUP_TOOLCHAIN=stable
    export CARGO_TARGET_DIR=target
    cargo build --frozen --release --all-features
}

其中:

  • --release 确保使用发布模式编译 (默认使用调试模式编译)
  • --frozen 确保 cargo 保持离线状态,只使用 Cargo.lock 文件中指定的版本和 prepare() 阶段缓存的版本。这在功能上与 --locked --offline 一致。这对可重现构建很重要。
  • --all-features 确保编译时启用软件包的所有特性。另外,如果只需启用指定特性,可使用 --features FEATURE1, FEATURE2
  • CARGO_TARGET_DIR=target 指定输出路径为当前目录下的 target 目录,以防未使用 chroot 环境构建时受用户配置影响。
注意: 对于 Arch 仓库的软件包来说不需要这两个环境变量,因为 Arch 仓库的软件包总是在 chroot 环境下使用默认设置下构建。但为了方便 AUR 用户,此处仍提到了上述环境变量,因为 AUR 用户可能没有意识到改变用户默认设置和在构建软件包时不使用 chroot 的后果。

检查

大多数 Rust 项目提供了运行测试的简单方法。

check() {
    export RUSTUP_TOOLCHAIN=stable
    cargo test --frozen --all-features
}

还应该检查仓库是否是 cargo 工作空间。只需打开 /Cargo.toml,检查是否包含 [workspace] 部分。如果包含 [workspace],则应当在 cargo test 后添加 --workspace,以确保所有工作区成员的测试都能运行。

运行测试时应避免使用 --release 标志,否则二进制文件将会使用 bench 参数重新编译,并覆盖 build() 生成的文件。或者也可以保留 --release 标志,但使用不同的 CARGO_TARGET_DIR。但需要注意的是,使用发布模式也会启用编译器优化,并禁用一些功能,如整数溢出检查和 debug_assert!() 宏,所以理论上可能最终问题会更少。这两种方法都会重新编译依赖项,从而使总编译时间略微增加。

打包

Rust 在 target/release 目录内构建二进制文件,将二进制文件安装到 /usr/bin 很容易。

package() {
    install -Dm0755 -t "$pkgdir/usr/bin/" "target/release/$pkgname"
}

如果一个软件包在 /usr/bin 内有多个可执行文件,可使用 find 命令:

package() {
    find target/release \
        -maxdepth 1 \
        -executable \
        -type f \
        -exec install -Dm0755 -t "$pkgdir/usr/bin/" {} +
}

使用 cargo install 的注意事项

有些软件包需要安装更多的文件,如手册页面或其他必要的文件。如果没有其他方式来安装这些文件,可使用 cargo install。在这种情况下不必使用 build(),因为即使该软件包已通过 cargo build 构建,cargo install 仍会强制重新构建。但仍然可使用 prepare() 提前获取源代码:

package() {
    cd "$pkgname-$pkgver"
    export RUSTUP_TOOLCHAIN=stable 
    cargo install --no-track --frozen --all-features --root "$pkgdir/usr/" --path .
}

应始终使用 --no-track 参数,否则 cargo install 将创建不必要的文件,如 /usr/.crates.toml/usr/.crates2.json

软件包示例

PKGBUILD 样例请参阅软件包页面上的 Package Actions > Source Files