Rust 软件打包准则
32 位 – CLR – CMake – Cross – DKMS – Eclipse – Electron – Font – Free Pascal – GNOME – Go – Haskell – Java – KDE – 内核模块 – Lisp – Meson – MinGW – Node.js – Nonfree – OCaml – Perl – PHP – Python – R – Ruby – Rust – VCS – Web – Wine
本文档涵盖了为 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
进行编译。目前 cargo 和 rustc 都由 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#arch 和 Rust 平台支持)。
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 环境构建时受用户配置影响。
检查[编辑 | 编辑源代码]
大多数 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。