入门 The Cargo Team 2026-09-13 15:48:22 · 0 阅读

第30章 Cargo 不稳定功能(Unstable Features)

实验性的 Cargo 功能只能在 nightly 通道上使用。欢迎你试用这些功能,看看能否满足需求、是否存在问题。想了解更多细节,可以查看下面对应的跟踪 issue,如果希望持续跟进更新,点击 GitHub 上的 subscribe 按钮即可。

经过一段时间后,如果某个功能没有重大问题,就可以被稳定化(stabilize)。等当前的 nightly 版本进入 stable 通道后(通常需要 6 到 12 周),该功能便会在 stable 版本中可用。

根据功能的工作方式,启用不稳定功能有以下三种方式:

  • Cargo.toml 中的新语法需要在文件顶部、所有 table 之前添加 cargo-features 键。例如:

    # 这里指定启用了哪些新的 Cargo.toml 功能。
    cargo-features = ["test-dummy-unstable"]
    
    [package]
    name = "my-package"
    version = "0.1.0"
    im-a-teapot = true  # 这是 test-dummy-unstable 启用的新选项。
    
  • 新的命令行参数、选项和子命令需要同时加上 -Z unstable-options。例如,新的 --artifact-dir 选项只能在 nightly 上使用:

    cargo +nightly build --artifact-dir=out -Z unstable-options

  • -Z 命令行参数用于启用那些还没有接口、接口尚未设计好,或者会影响 Cargo 多个部分的更复杂的功能。例如,mtime-on-use 功能可以这样启用:

    cargo +nightly build -Z mtime-on-use

    运行 cargo -Z help 可以查看所有可用参数的列表。

    凡是能通过 -Z 参数配置的选项,也都可以在 cargo 的配置文件.cargo/config.toml)的 unstable table 中设置。例如:

    [unstable]
    mtime-on-use = true
    build-std = ["core", "alloc"]
    

下面介绍每个新功能时都会说明其使用方法。

最新 nightly 版本的本页内容,请参见nightly 版本

不稳定特性列表

allow-features

这个永久不稳定的标志,使得仅允许使用指定的不稳定特性列表。具体来说,如果传入 -Zallow-features=foo,bar,你仍可向 cargo 传入 -Zfoo-Zbar,但无法传入 -Zbaz。你可以传入空字符串(-Zallow-features=)来禁止所有不稳定特性。

-Zallow-features 还限制了可在 Cargo.tomlcargo-features 条目中传入的不稳定特性。例如,如果想允许

cargo-features = ["test-dummy-unstable"]

其中 test-dummy-unstable 是不稳定的,那么当 -Zallow-features= 时该特性也会被禁止,而在 -Zallow-features=test-dummy-unstable 时会被允许。

传给 cargo 的 -Zallow-features 的特性列表,也会传递给 cargo 最终调用的其他 Rust 工具(如 rustcrustdoc)。因此,如果运行 cargo -Zallow-features=,就无法使用任何不稳定的 Cargo Rust 特性。

no-index-update

-Z no-index-update 标志让 Cargo 不去更新 registry 索引。这是为 Crater 这类会执行大量 Cargo 命令的工具设计的,可以避免每次更新索引带来的网络延迟。

mtime-on-use

  • 原始 Issue:#6477
  • 缓存使用元信息跟踪 Issue:#7150

-Z mtime-on-use 标志是一个实验性功能,让 Cargo 更新被使用文件的 mtime,方便 cargo-sweep 这类工具检测哪些文件已过期。很多工作流需要在所有 cargo 调用中都设置这个选项。为了让它更实用,可以在 .cargo/config.toml 中设置 unstable.mtime_on_use 标志(或设置对应的环境变量),这样所有 nightly cargo 的调用都会自动启用 -Z mtime-on-use。(stable 版本会忽略该配置项)

avoid-dev-deps

在运行 cargo installcargo build 等命令时,Cargo 目前要求下载 dev-dependencies,即使它们并未被使用。-Z avoid-dev-deps 标志允许 Cargo 在不需要时跳过下载 dev-dependencies。跳过 dev-dependencies 时将不会生成 Cargo.lock 文件。

minimal-versions

注意:不建议使用该功能。由于它会对所有传递依赖强制使用最低版本,而并非所有外部依赖都声明了合理的版本下限,因此其实际作用有限。未来计划将其改为只对直接依赖强制最低版本。

生成 Cargo.lock 文件时,-Z minimal-versions 标志会将依赖解析为满足要求的最低 SemVer 版本(而不是最高版本)。

该标志的预期用途是在持续集成中检查 Cargo.toml 里声明的版本是否正确反映了你实际使用的最低版本。也就是说,如果 Cargo.toml 中写着 foo = "1.0.0",就要确保你没有不小心依赖到 foo 1.5.0 才加入的功能。

direct-minimal-versions

生成 Cargo.lock 文件时,-Z direct-minimal-versions 标志会只针对直接依赖,将其解析为满足要求的最低 SemVer 版本(而不是最高版本)。

该标志的预期用途是在持续集成中检查 Cargo.toml 里声明的版本是否正确反映了你实际使用的最低版本。也就是说,如果 Cargo.toml 中写着 foo = "1.0.0",就要确保你没有不小心依赖到 foo 1.5.0 才加入的功能。

间接依赖仍按常规方式解析,以免被它们的最低版本验证问题所阻塞。

artifact-dir

该功能允许指定构建产物在编译完成后被复制到的目标目录。通常,构建产物只写入到 target/releasetarget/debug 目录中。然而,要确定确切的文件名可能会比较麻烦,因为你需要解析 JSON 输出。--artifact-dir 参数让你可以更容易地以可预测的方式访问这些产物。请注意,产物是被复制的,原始文件仍保留在 target 目录中。示例:

cargo +nightly build --artifact-dir=out -Z unstable-options

也可以在 .cargo/config.toml 文件中配置该设置。

[build]
artifact-dir = "out"

root-dir

  • 原始议题: #9887
  • 跟踪议题: 无(目前不计划稳定化)

-Zroot-dir 参数用于设置用于输出路径的根目录。这会影响诊断信息以及由 file!() 宏输出的路径。

Metabuild

Metabuild 是一种声明式构建脚本功能。它不需要你编写 build.rs 脚本,而是让你在 Cargo.tomlmetabuild 字段中列出一组构建依赖。系统会自动生成一个构建脚本,并按顺序执行这些构建依赖。Metabuild 包随后可以从 Cargo.toml 中读取元数据,以决定其具体行为。

要在 Cargo.toml 中使用 Metabuild,需要在文件顶部添加 cargo-features,在 package 部分添加 metabuild 字段,在 build-dependencies 中列出依赖,并将 Metabuild 包所需的元数据放在 package.metadata 下。示例:

cargo-features = ["metabuild"]

[package]
name = "mypackage"
version = "0.0.1"
metabuild = ["foo", "bar"]

[build-dependencies]
foo = "1.0"
bar = "1.0"

[package.metadata.foo]
extra-info = "qwerty"

Metabuild 包应当提供一个名为 metabuild 的公开函数,其功能与普通的 build.rs 构建脚本相同。

Multiple Build Scripts(多个构建脚本)

Multiple Build Scripts 特性允许在一个包中包含多个构建脚本。

Cargo.toml 顶部添加 cargo-features,并加入 multiple-build-scripts 来启用该特性。然后在 package.build 中以数组形式指定各构建脚本的路径,例如:

cargo-features = ["multiple-build-scripts"]

[package]
name = "mypackage"
version = "0.0.1"
build = ["foo.rs", "bar.rs"]

访问输出目录:每个构建脚本的输出目录可以通过 <script-name>_OUT_DIR 访问,其中 <script-name> 是构建脚本的文件名主干(不含扩展名),保持原样。例如 foo/bar.rs 对应的环境变量是 bar_OUT_DIR。(仅在编译期间设置,可通过 env! 宏访问)

Any Build Script Metadata(任意构建脚本的 metadata)

允许任意构建脚本通过 cargo::metadata=key=value 指定环境变量。

依赖它的构建脚本可以在运行时读取 CARGO_DEP_<dep>_<key> 环境变量来获取这些键值对。对于声明了 links 的 crate 构建脚本,DEP_<links>_<key>CARGO_DEP_<dep>_<key> 都会被设置。

注意,CARGO_DEP_<dep>_<key> 中的 depkey 都会转为大写,连字符(-)会被替换为下划线(_)。

public-dependency

‘public-dependency’ 特性允许把依赖标记为 ‘public’(公开)或 ‘private’(私有)。启用该特性后,cargo 会向 rustc 传递额外信息,使 exported_private_dependencies lint 能正常工作。

启用方式有两种,一是使用 -Zpublic-dependency

cargo +nightly run -Zpublic-dependency

二是使用 [unstable] 配置表,例如:

# .cargo/config.toml
[unstable]
public-dependency = true

也可以在 cargo-features 中启用 public-dependency但这种方式已废弃,很快将被移除

cargo-features = ["public-dependency"]

[dependencies]
my_dep = { version = "1.2.3", public = true }
private_dep = "2.0.0" # 默认为 'private'

文档更新:

  • 工作空间文档的 “The dependencies table” 一节中,需注明 publicworkspace.dependencies 中是不支持的字段
  • 使用 public 要求的最低 MSRV 为 1.83(参见 #14507

msrv-policy

这是 RFC 2495 下所有感知 MSRV 的 cargo 特性的统称不稳定特性。

感知 MSRV 的 cargo add

已于 1.79 稳定,见 #13608

感知 MSRV 的 resolver

已于 1.84 稳定,见 #14639

incompatible_toolchain 错误改为 lint

尚未实现

cargo addcargo update--update-rust-version 标志

尚未实现

package.rust-version = "toolchain"

尚未实现

更新 cargo new 模板以设置 package.rust-version = "toolchain"

尚未实现

precise-pre-release

precise-pre-release 特性允许使用 update --precise 选择预发布版本,即使项目的 Cargo.toml 没有指定预发布。

例如,假设 Cargo.toml 如下。

[dependencies]
my-dependency = "0.1.1"

可以通过 update -Zunstable-options my-dependency --precise 0.1.2-pre.0my-dependency 更新到预发布版本。 这是因为 0.1.2-pre.0 被视为与 0.1.1 兼容。 无法以同样的方式将版本从 0.1.1 升级到 0.2.0-pre.0

sbom

sbom 构建配置允许在每个编译产物旁生成所谓的 SBOM 前置文件。 软件物料清单(SBOM)工具可以整合这些生成的文件,以收集 cargo 构建过程中的重要信息,这些信息通过其他方式很难甚至无法获取。

要在 .cargo/config.toml 中启用此特性,请设置 sbom 字段:

[unstable]
sbom = true

[build]
sbom = true

或者将环境变量 CARGO_BUILD_SBOM 设置为 true。 该功能位于标志 -Z sbom 之后。

生成的输出文件采用 JSON 格式,遵循命名规则 <artifact>.cargo-sbom.json。JSON 文件包含依赖项、目标、特性以及使用的 rustc 编译器的信息。

所有被提升到 target 或 artifact 目录中的可执行和可链接输出,都会生成 SBOM 前置文件。

Cargo 为 crate 设置的环境变量

  • CARGO_SBOM_PATH —— 生成的 SBOM 前置文件列表,以平台 PATH 分隔符分隔。可以用 std::env::split_paths 拆分该列表。

SBOM 前置文件格式

{
  // Schema 版本。
  "version": 1,
  // 根 crate 在 crates 数组中的索引。
  "root": 0,
  // 所有 crate 的数组。如果同一个 crate 以不同方式编译(不同的 opt-level、features 等),可能出现重复。
  "crates": [
    {
      // 完整的 package ID 规格
      "id": "path+file:///sample-package#0.1.0",
      // target 类型列表:bin、lib、rlib、dylib、cdylib、staticlib、proc-macro、example、test、bench、custom-build
      "kind": ["bin"],
      // 已启用的 feature 标志。
      "features": [],
      // 此 crate 的依赖。
      "dependencies": [
        {
          // 在 crates 数组中的索引。
          "index": 1,
          // 依赖类型:
          // Normal:链接到此 crate 产出物的依赖。
          // Build:构建此 crate 时使用的编译期依赖(build-script 或 proc-macro)。
          "kind": "normal"
        },
        {
          // 一个 crate 可以同时以 normal 和 build 两种方式依赖另一个 crate。
          "index": 1,
          "kind": "build"
        }
      ]
    },
    {
      "id": "registry+https://github.com/rust-lang/crates.io-index#zerocopy@0.8.16",
      "kind": ["bin"],
      "features": [],
      "dependencies": []
    }
  ],
  // 用于执行编译的 rustc 相关信息。
  "rustc": {
    // 编译器版本
    "version": "1.86.0-nightly",
    // 编译器 wrapper
    "wrapper": null,
    // 编译器 workspace wrapper
    "workspace_wrapper": null,
    // rustc 的 commit hash
    "commit_hash": "bef3c3b01f690de16738b1c9f36470fbfc6ac623",
    // 宿主平台的 target triple
    "host": "x86_64-pc-windows-msvc",
    // 详细版本信息:`rustc -vV`
    "verbose_version": "rustc 1.86.0-nightly (bef3c3b01 2025-02-04)\nbinary: rustc\ncommit-hash: bef3c3b01f690de16738b1c9f36470fbfc6ac623\ncommit-date: 2025-02-04\nhost: x86_64-pc-windows-msvc\nrelease: 1.86.0-nightly\nLLVM version: 19.1.7\n"
  }
}

update-breaking

允许使用 --breaking 标志,在 Cargo.toml 中跨 SemVer 不兼容版本升级依赖的版本要求。

该功能只对满足以下条件的依赖生效:

  • 该 package 是某个 workspace 成员的依赖
  • 该依赖没有被重命名
  • 存在一个 SemVer 不兼容的版本
  • 使用了“SemVer 操作符”(^,这是默认值)

用户可以通过在命令行中指定特定包来进一步限制哪些包会被升级。

示例:

$ cargo +nightly -Zunstable-options update --breaking
$ cargo +nightly -Zunstable-options update --breaking clap

此功能旨在发挥类似 cargo-upgrade 的作用

build-std

build-std 功能允许 Cargo 在编译 crate 依赖图时,将标准库本身也作为其中的一部分进行编译。该功能在历史上也被称为“std-aware Cargo”。目前该功能仍处于早期开发阶段,且是一个极具潜力的重大功能扩展。即便以目前最小的形态来看,这一功能也有巨大的文档工作量,如果你希望保持关注其最新进展,建议跟踪该 跟踪仓库 及其相关 issue。

当前实现的功能位于 -Z build-std 标志之后。该标志指示 Cargo 应从源代码编译标准库,并使用与主构建相同的 profile。为了使其正常工作,你需要拥有标准库的源代码,目前唯一支持的方式是添加 rust-src rustup 组件:

$ rustup component add rust-src --toolchain nightly

用法如下:

$ cargo new foo
$ cd foo
$ cargo +nightly run -Z build-std --target x86_64-unknown-linux-gnu
   Compiling core v0.0.0 (...)
   ...
   Compiling foo v0.1.0 (...)
    Finished dev [unoptimized + debuginfo] target(s) in 21.00s
     Running `target/x86_64-unknown-linux-gnu/debug/foo`
Hello, world!

在此示例中,标准库以 debug 模式重新编译,包含 debug 断言(就像编译 src/main.rs 那样),最终所有组件被链接在一起。

使用 -Z build-std 会隐式编译稳定的 crate:corestdallocproc_macro。如果使用 cargo test,还会编译 test crate。如果你的环境不支持其中某些 crate,可以给 -Zbuild-std 传参数来指定:

$ cargo +nightly build -Z build-std=core,alloc

这里的值是一个逗号分隔的列表,指定要构建的标准库 crate。

使用要求

简单总结,目前使用 -Z build-std 需要满足以下条件:

  • 必须通过 rustup component add rust-src 安装 libstd 源码
  • 必须同时使用 nightly 版本的 Cargo 和 rustc
  • 所有 cargo 调用都必须带上 -Z build-std 标志

报告 Bug 与参与贡献

-Z build-std 功能目前还处于非常早期的开发阶段!这个 Cargo 特性历史悠久、涉及范围很大,而现在仅仅是个开始。如果你想报告 Bug,可以提交到:

另外,如果你想看到某个尚未实现的功能,或者某些地方的表现不如预期,欢迎查看跟踪仓库的 issue tracker,如果没找到相关问题,欢迎提一个新 issue!

build-std-features

该 flag 与 -Zbuild-std 功能 flag 是配套的,用于在构建标准库时配置标准库自身启用的 features。目前默认启用的 features 是 backtracepanic-unwind。该 flag 接受一个逗号分隔的列表,如果指定了它,就会覆盖默认的 features 列表。

binary-dep-depinfo

-Z binary-dep-depinfo flag 会让 Cargo 把同样的 flag 转发给 rustc,从而使 rustc 在 "dep info" 文件(扩展名为 .d)中记录所有二进制依赖的路径。Cargo 随后利用这些信息进行变更检测——只要任何一个二进制依赖发生变化,对应的 crate 就会被重新构建。这个功能最主要的用例是构建编译器本身:编译器对标准库存在隐式依赖,如果不启用该功能,这些依赖不会纳入变更检测。

checksum-freshness

-Z checksum-freshness flag 会用文件校验和取代 Cargo fingerprint 中对文件 mtime 的使用。这在 mtime 实现不可靠的系统上,或者在 CI/CD 环境中最为有用。不同 Cargo 版本之间的校验和算法可能会在不另行通知的情况下发生变化。Cargo 通过 fingerprint 来判断一个 crate 是否需要重新构建。

目前,即使启用了 checksum-freshness,build script 摄取的文件仍会继续使用 mtime。这只是临时做法,并非长期方案。

panic-abort-tests

-Z panic-abort-tests 标志允许 Nightly 版本以 -Cpanic=abort 模式编译测试框架 crate。若未设置此标志,Cargo 将以 -Cpanic=unwind 模式编译测试及其所有依赖项,因为这是 test crate 目前唯一支持的操作方式。不过,自 rust-lang/rust#64158 起,test crate 已支持基于“每进程一测试”的 -C panic=abort 模式,这有助于避免多次编译相同的依赖图。

该功能在 Cargo 中如何标准化(stabilize)目前尚不明确,但我们希望将其以某种形式稳定下来!

target-applies-to-host

历史上,Cargo 在处理构建脚本、插件及其他始终针对宿主机平台构建的产物时,对来自环境变量及[target]配置段中的 linkerrustflags 选项是否生效,其行为曾有过不一致之处。 当未传入 --target 参数时,Cargo 会对构建脚本应用与其他编译产物相同的 linkerrustflags 设置。 然而,当传入 --target 参数时,Cargo 仅从[target.<host triple>]中读取 linker 设置,而不会应用任何 rustflags 配置。 这种双重行为容易令人困惑,同时也使得难以正确配置那些宿主机三元组(host triple)与目标三元组(target triple)恰好相同、但旨在宿主机上运行的产物仍需区别配置的场景。

-Ztarget-applies-to-host 会启用 Cargo 配置文件中的顶层 target-applies-to-host 设置,让用户可以选择启用不同(也更一致)的行为。当配置文件中未设置 target-applies-to-host 或设为 true 时,Cargo 保持现有行为不变(不过要注意 -Zhost-config 会改变这个默认值)。当设为 false 时,无论是否给 Cargo 传入 --target,主机构建产物都不会应用 [target.<host triple>]RUSTFLAGS[build] 中的任何选项。若要自定义在主机上运行的构建产物,请使用 [host](参见 host-config)。

未来,target-applies-to-host 可能会将默认值改为 false,以提供更合理、更一致的默认行为。

# config.toml
target-applies-to-host = false
cargo +nightly -Ztarget-applies-to-host build --target x86_64-unknown-linux-gnu

host-config

配置文件中的 host 键可用于为主机构建目标传递参数,例如交叉编译时必须在主机系统(而非目标系统)上运行的 build script。它同时支持通用表和主机架构专属表,且匹配到的主机架构专属表优先于通用主机表。

使用该功能需要同时设置 -Zhost-config-Ztarget-applies-to-host 命令行选项,并在 Cargo 配置文件中设置 target-applies-to-host = false

# config.toml
[host]
linker = "/path/to/host/linker"
runner = "host-runner"
[host.x86_64-unknown-linux-gnu]
linker = "/path/to/host/arch/linker"
runner = "host-arch-runner"
rustflags = ["-Clink-arg=--verbose"]
[target.x86_64-unknown-linux-gnu]
linker = "/path/to/target/linker"

host.runner 配置用于包装宿主构建目标(如 build script)的执行过程,作用类似于 target.<triple>.runner 包装 cargo run/test/bench

x86_64-unknown-linux-gnu 宿主上构建时,上面通用的 host 配置表会被完全忽略,因为 host.x86_64-unknown-linux-gnu 配置表优先级更高。

设置 -Zhost-config 会把 target-applies-to-host 的默认值从 true 改为 false

cargo +nightly -Ztarget-applies-to-host -Zhost-config build --target x86_64-unknown-linux-gnu

unit-graph

--unit-graph 标志可以传给任何构建命令(buildcheckruntestbenchdoc 等),它会在 stdout 输出一个 JSON 对象,表示 Cargo 内部的 unit 图。实际上不会构建任何东西,命令在打印后立即返回。每个 "unit" 对应一次编译器执行,对象中还包含各 unit 之间的依赖关系。

cargo +nightly build --unit-graph -Z unstable-options

这种结构能更完整地展现 Cargo 所理解的依赖关系。特别是 "features" 字段支持新的 feature 解析器,即同一个依赖可以用不同的 feature 构建多次。cargo metadata 从根本上无法表示不同依赖类别之间的 feature 关系,而且 feature 现在取决于运行的命令以及选中的包和目标。此外,它还能提供包内依赖的细节,比如 build script 或测试。

以下是 JSON 结构的说明:

{
  /* JSON 输出结构的版本。如果发生向后不兼容的变更,此值会递增。 */
  "version": 1,
  /* 所有构建单元数组。 */
  "units": [
    {
      /* 一个不透明字符串,用于指示包。
         包的信息可通过 `cargo metadata` 获取。
      */
      "pkg_id": "my-package 0.1.0 (path+file:///path/to/my-package)",
      /* Cargo 目标。这些字段的更多文档说明参见 `cargo metadata`。
         https://doc.rust-lang.org/cargo/commands/cargo-metadata.html
      */
      "target": {
        "kind": ["lib"],
        "crate_types": ["lib"],
        "name": "my_package",
        "src_path": "/path/to/my-package/src/lib.rs",
        "edition": "2018",
        "test": true,
        "doctest": true
      },
      /* 此单元的 profile 设置。
         这些值可能与 manifest 中定义的 profile 不一致。
         单元可以使用修改后的 profile 设置。例如,测试可覆写 "panic"
         设置,强制设为 "unwind"。
      */
      "profile": {
        /* 这些设置所派生的 profile 名称。 */
        "name": "dev",
        /* 以字符串形式表示的优化级别。 */
        "opt_level": "0",
        /* 以字符串形式表示的 LTO 设置。 */
        "lto": "false",
        /* 以整数形式表示的 codegen units。
           若应使用编译器默认值,则为 `null`。
        */
        "codegen_units": null,
        /* 以整数形式表示的调试信息级别。
           若应使用编译器默认值 (0),则为 `null`。
        */
        "debuginfo": 2,
        /* 是否启用 debug-assertions。 */
        "debug_assertions": true,
        /* 是否启用 overflow-checks。 */
        "overflow_checks": true,
        /* 是否启用 rpath。 */
        "rpath": false,
        /* 是否启用 incremental。 */
        "incremental": true,
        /* panic 策略,"unwind" 或 "abort"。 */
        "panic": "unwind"
      },
      /* 此目标正在构建的平台。
         `null` 表示为目标主机。
         否则为目标三元组字符串(如 "x86_64-unknown-linux-gnu")。
      */
      "platform": null,
      /* 此单元的 "mode"。合法值:

         * "test" --- 使用 `rustc` 作为测试构建。
         * "build" --- 使用 `rustc` 构建。
         * "check" --- 使用 `rustc` 的 "check" 模式构建。
         * "doc" --- 使用 `rustdoc` 构建。
         * "doctest" --- 使用 `rustdoc` 测试。
         * "run-custom-build" --- 代表执行构建脚本。
      */
      "mode": "build",
      /* 此单元启用的 features 字符串数组。 */
      "features": ["somefeat"],
      /* 是否属于标准库单元,
         是未稳定的 build-std 功能的一部分。
         若未设置,视为 `false`。
      */
      "is_std": false,
      /* 此单元的依赖项数组。 */
      "dependencies": [
        {
          /* 在 "units" 数组中依赖项的索引。 */
          "index": 1,
          /* 此依赖项的引用名称。 */
          "extern_crate_name": "unicode_xid",
          /* 此依赖项是否为 "public",
             是未稳定的 public-dependency 功能的一部分。
             若未设置,未启用 public-dependency 功能。
          */
          "public": false,
          /* 此依赖项是否注入到 prelude,
             当前由 build-std 功能使用。
             若未设置,视为 `false`。
          */
          "noprelude": false
        }
      ]
    },
    // ...
  ],
  /* "units" 数组中 "roots" 的索引数组,
     即依赖图的根。
  */
  "roots": [0],
}


Profile 的 rustflags 选项

该特性在 [profile] 配置段中新增了一个选项,可以直接向 rustc 传递编译参数。启用方式如下:

cargo-features = ["profile-rustflags"]

[package]
# ...

[profile.release]
rustflags = [ "-C", "..." ]

如果要在 Cargo 配置文件的 profile 中使用它,需要通过 -Z profile-rustflags[unstable] 配置段来启用,例如:

# .cargo/config.toml
[unstable]
profile-rustflags = true

[profile.release]
rustflags = [ "-C", "..." ]

Profile 的 hint-mostly-unused 选项

该特性在 [profile] 配置段中新增了一个选项,用于启用 rustc 的 hint-mostly-unused 选项。它主要针对特定依赖启用,例如:

[profile.dev.package.huge-mostly-unused-dependency]
hint-mostly-unused = true

要启用该特性,需传入 -Zprofile-hint-mostly-unused。不过由于这个选项只是一个提示,如果没有传 -Zprofile-hint-mostly-unused,Cargo 只会发出警告并忽略该 profile 选项。引入该特性之前的 Cargo 版本会给出 "unused manifest key" 警告,但不会报错。这样即使在 crate 的 Cargo.toml 中使用了该提示,构建它时也不强制要求使用更新版本的 Cargo。

crate 也可以通过 [hints] 配置段为依赖它的 crate 自动提供该提示(旧版本 Cargo 同样会忽略它):

[hints]
mostly-unused = true

这会让该 crate 默认启用 hint-mostly-unused,除非通过 profile 覆盖——profile 的优先级更高,且只能在顶层被构建的 crate 中指定。

rustdoc-map

该特性增加了一些传递给 rustdoc 的配置项:当某个依赖没有附带文档时,rustdoc 可以为它生成指向其他托管地址的链接。首先,在 .cargo/config 中加入:

[doc.extern-map.registries]
crates-io = "https://docs.rs/"

然后在构建文档时使用以下 flag,依赖的链接就会指向 docs.rs

cargo +nightly doc --no-deps -Zrustdoc-map

registries 表用于把 registry 名称映射到要链接的 URL。URL 中可以使用 {pkg_name}{version} 标记,它们会被替换为对应的值。如果两者都未指定,Cargo 默认会在 URL 末尾追加 {pkg_name}/{version}/

还有一个配置项可以重定向标准库的链接。默认情况下,rustdoc 生成的链接指向 https://doc.rust-lang.org/nightly/。要改变这一行为,可以使用 doc.extern-map.std 配置:

[doc.extern-map]
std = "local"

值为 "local" 表示链接到 rustc sysroot 中的文档。如果你使用 rustup,可以通过 rustup component add rust-docs 安装这些文档。

默认值为 "remote"

该值也可以是自定义位置的 URL。

per-package-target

per-package-target 特性为 manifest 增加了两个键:package.default-targetpackage.forced-target。前者让包在没有传 --target 参数时默认针对某个目标平台编译;后者则让包始终针对该目标平台编译。

示例:

[package]
forced-target = "wasm32-unknown-unknown"

在此示例中,crate 始终为 wasm32-unknown-unknown 目标构建,例如它是作为运行在宿主(或由命令行指定目标)的主程序的插件使用。

artifact-dependencies

Artifact dependencies 允许 Cargo 包依赖 bincdylibstaticlib crate,并在编译时使用这些 crate 构建出的工件。

运行 cargo 并附加 -Z bindeps 参数以启用此功能。

artifact-dependencies: 依赖声明

Artifact-dependencies 在 Cargo.toml 的依赖声明中添加了以下键:

  • artifact — 指定要构建的 Cargo Target。通常没有此字段时,Cargo 仅构建依赖的 [lib] 目标。该字段允许指定构建哪个目标,并在构建时将其作为二进制文件提供:

    • "bin" — 编译后的可执行二进制文件,对应于依赖清单中所有的 [[bin]] 部分。
    • "bin:<bin-name>" — 编译后的可执行二进制文件,对应于由给定 <bin-name> 指定的特定二进制目标。
    • "cdylib" — C 兼容的动态库,对应于依赖清单中 crate-type = ["cdylib"][lib] 部分。
    • "staticlib" — C 兼容的静态库,对应于依赖清单中 crate-type = ["staticlib"][lib] 部分。

    artifact 的值可以是字符串,也可以是字符串数组以指定多个目标。

    示例:

    [dependencies]
    bar = { version = "1.0", artifact = "staticlib" }
    zoo = { version = "1.0", artifact = ["bin:cat", "bin:dog"]}
    
  • lib — 布尔值,表示是否同时将该依赖的库作为普通的 Rust lib 依赖来构建。该字段只有在指定了 artifact 时才能设置。

    指定了 artifact 时,该字段默认为 false。如果设为 true,那么该依赖的 [lib] 目标也会针对声明它的包所构建的目标平台进行构建。这样,该包除了可以把它当作 artifact 依赖使用之外,还能像普通依赖一样在 Rust 代码中使用它。

    示例:

    [dependencies]
    bar = { version = "1.0", artifact = "bin", lib = true }
    
  • target — 依赖要构建的目标平台。该字段只有在指定了 artifact 时才能设置。

    不指定时的默认值取决于依赖类型:build 依赖会针对 host 目标构建;其他类型的依赖则针对声明它的包所构建的目标平台构建。

    对于 build 依赖,还可以使用特殊值 "target",表示针对当前包所构建的目标平台来构建该依赖。

    [build-dependencies]
    bar = { version = "1.0", artifact = "cdylib", target = "wasm32-unknown-unknown"}
    same-target = { version = "1.0", artifact = "bin", target = "target" }
    

artifact-dependencies:环境变量

构建完 artifact 依赖后,Cargo 会提供以下环境变量,用于访问这些 artifact:

  • CARGO_<ARTIFACT-TYPE>_DIR_<DEP> — 包含该依赖所有 artifact 的目录。

    其中 <ARTIFACT-TYPE> 是为该依赖指定的 artifact 值(大写形式,如 CDYLIBSTATICLIBBIN),<DEP> 是依赖的名称。与其他 Cargo 环境变量一样,依赖名会转换为大写,横线替换为下划线。

    如果在 manifest 中重命名了依赖,<DEP> 对应的是你指定的名称,而不是原始的包名。

  • CARGO_<ARTIFACT-TYPE>_FILE_<DEP>_<NAME> —— 该 artifact 的完整路径。

    <ARTIFACT-TYPE> 是为该依赖指定的 artifact(按上述规则转为大写),<DEP> 是依赖的名称(按上述规则转换),<NAME> 是该依赖提供的 artifact 名称。

    注意,<NAME> 会原样使用提供 artifact 的 crate 中指定的 name,未指定时则使用 crate 名称,不做任何修改;比如它可能是小写,或者包含连字符。

    为方便起见,如果 artifact 名称与原始包名一致,Cargo 还会额外提供一个省略了 _<NAME> 后缀的同名变量。 例如,如果 cmake crate 提供了一个名为 cmake 的二进制文件,Cargo 会同时提供 CARGO_BIN_FILE_CMAKECARGO_BIN_FILE_CMAKE_cmake 两个变量。

对于每类依赖,这些变量会在构建过程中暴露给能访问该类依赖的部分:

  • 对于 build-dependencies,这些变量提供给 build.rs 脚本,可以通过 std::env::var_os 访问。 (与其他操作系统文件路径一样,其内容不一定是有效的 UTF-8。)
  • 对于普通依赖,这些变量在 crate 编译期间提供,可以通过 env! 宏访问。
  • 对于 dev-dependencies,这些变量在编译示例、测试和基准测试时提供,可以通过 env! 宏访问。

artifact-dependencies: 示例

示例:在构建脚本中使用二进制可执行文件

Cargo.toml 文件中,可以声明对某个二进制文件的依赖,供构建脚本使用:

[build-dependencies]
some-build-tool = { version = "1.0", artifact = "bin" }

然后在构建脚本中,就可以在构建时执行该二进制文件:

fn main() {
    let build_tool = std::env::var_os("CARGO_BIN_FILE_SOME_BUILD_TOOL").unwrap();
    let status = std::process::Command::new(build_tool)
        .arg("do-stuff")
        .status()
        .unwrap();
    if !status.success() {
        eprintln!("failed!");
        std::process::exit(1);
    }
}

示例:在构建脚本中使用 cdylib 产物

消费方包中的 Cargo.toml,将 bar 库作为 cdylib 构建,目标平台为…

[build-dependencies]
bar = { artifact = "cdylib", version = "1.0", target = "wasm32-unknown-unknown" }

…以及位于 build.rs 中的构建脚本。

fn main() {
    wasm::run_file(std::env::var("CARGO_CDYLIB_FILE_BAR").unwrap());
}

示例:在二进制文件中使用 binary 产物及其库

消费方包中的 Cargo.toml,将 bar 作为二进制产物构建用于包含,同时使其可作为库使用…

[dependencies]
bar = { artifact = "bin", version = "1.0", lib = true }

…以及使用 main.rs 的可执行文件。

fn main() {
    bar::init();
    command::run(env!("CARGO_BIN_FILE_BAR"));
}

publish-timeout

配置文件中的 publish.timeout 键可用于控制 cargo publish 在将包发布到 registry 后,等待其在本地索引中可用时的超时时长。

超时设置为 0 可阻止任何检查执行。当前默认值为 60 秒。

需设置 -Zpublish-timeout 命令行选项。

# config.toml
[publish]
timeout = 300  # 单位:秒

asymmetric-token

-Z asymmetric-token 标志会启用 cargo:paseto 凭证提供程序,让 Cargo 在向 registry 认证时无需在网络上传输密钥。

config.tomlcredentials.toml 文件中有一个 private-key 字段,存放以 PASERK 的 secret 子类型格式编码的私钥,用于对非对称令牌进行签名。

可以通过 cargo login --generate-keypair 生成密钥对,它会:

  • 以当前推荐的方式生成一对公钥/私钥。
  • 将私钥保存到 credentials.toml
  • PASERK public 格式打印公钥。

建议将 private-key 保存在 credentials.toml 中。也支持放在 config.toml 里,主要是为了能通过对应的环境变量来设置——这也是在 CI 环境中提供私钥的推荐方式。这个设计与现有的 token 字段(用于设置密钥令牌)是一致的。

还有一个可选字段 private-key-subject,其值由 registry 指定。该字符串会包含在非对称令牌中,不需要保密。它只用于极少数场景,比如“用加密方式证明中央 CA 服务器授权了这次操作”。Cargo 要求它的值是除空白字符外的可打印 ASCII,需要非 ASCII 数据的 registry 应将其做 base64 编码。

这两个字段都可以通过 cargo login --registry=name --private-key --private-key-subject="subject" 设置,命令会提示你输入密钥值。

每个 registry 最多只能设置 private-keytoken 中的一个。

所有 PASETO 都会包含 iat 字段,即 ISO 8601 格式的当前时间。在适用的情况下,Cargo 还会包含以下字段:

  • sub:一个可选的非机密字符串,由 registry 指定,预期会随每个请求一起声明。其值取自 config.toml 文件中的 private-key-subject
  • mutation(如果存在)表示该请求是一个修改操作(不存在则为只读操作),必须是 publishyankunyank 之一。
    • name 该请求相关的 crate 名称。
    • vers 该请求相关的 crate 版本字符串。
    • cksum crate 内容的 SHA256 哈希,为 64 位小写十六进制字符串,仅当 mutationpublish 时必须提供。
  • challenge 本次会话中从服务器 401/403 响应收到的 challenge 字符串。颁发 challenge 的 registry 必须记录哪些 challenge 已颁发/已使用,并且在同一有效期内绝不能接受同一个 challenge 多次(这样就不必记录所有颁发过的 challenge)。

"footer"(属于签名的一部分)是一个 UTF-8 编码的 JSON 字符串,包含:

  • url cargo 获取 config.json 文件时使用的符合 RFC 3986 的 URL,
    • 如果是 HTTP 索引的 registry,则为所有索引查询的基准 URL。
    • 如果是 GIT 索引的 registry,则为 Cargo 克隆索引时使用的 URL。
  • kid 签名请求所用的私钥标识符,遵循 PASERK IDs 标准。

PASETO 中包含被签名的消息本身,因此服务器无需从请求中重建原始字符串即可验证签名。但服务器需要检查该签名对 PASETO 中的字符串是否有效,以及该字符串的内容是否与请求一致。 如果某个 claim 对请求来说是必需的,但在 PASETO 中缺失,则必须拒绝该请求。

cargo config

cargo config 子命令用于显示 cargo 加载的配置文件。目前它包含 get 子命令,可接受一个可选的配置项作为要显示的内容。

cargo +nightly -Zunstable-options config get build.rustflags

如果未指定配置项,则会显示所有配置值。更多可用选项请参考 --help 输出。

rustc --print

cargo rustc --print=VAL--print 标志转发给 rustc,以提取 rustc 的相关信息。此命令会以对应的 --print 标志运行 rustc,然后立即退出而不执行编译。将其暴露为 cargo 标志,使得 cargo 可以根据当前配置注入正确的 target 和 RUSTFLAGS。

主要使用场景是运行 cargo rustc --print=cfg,以获取适用于相应 target 的配置值,并考虑其他 RUSTFLAGS 的影响。

不同的二进制名称

different-binary-name 功能允许设置二进制的文件名,而无需遵守 crate 名称的限制。例如,crate 名称只能使用 alphanumeric 字符、-_,且不能为空。

filename 参数不应包含二进制扩展名,cargo 会自动确定适当的扩展名并用于该二进制文件。

filename 参数仅在 manifest 的 [[bin]] 部分中可用。

cargo-features = ["different-binary-name"]

[package]
name =  "foo"
version = "0.0.1"

[[bin]]
name = "foo"
filename = "007bar"
path = "src/main.rs"

scrape-examples

-Z rustdoc-scrape-examples 选项会让 Rustdoc 在当前 workspace 的 crate 中搜索函数调用,并将这些调用点作为文档示例收录。用法如下:

cargo doc -Z unstable-options -Z rustdoc-scrape-examples

默认情况下,Cargo 会从被文档化的包的 example 目标中抓取示例。你可以通过 doc-scrape-examples 选项单独开启或关闭某个目标的抓取,例如:

# 从库中开启示例抓取
[lib]
doc-scrape-examples = true

# 从某个 example 目标关闭示例抓取
[[example]]
name = "my-example"
doc-scrape-examples = false

关于测试: 目前在 test 目标上开启 doc-scrape-examples 不会产生任何效果,从测试中抓取示例的功能仍在开发中。

关于 dev-dependencies: 生成库文档通常不需要 crate 的 dev-dependencies,但 example 目标是需要它们的。为了向后兼容,-Z rustdoc-scrape-examples 不会cargo doc 额外引入 dev-deps 依赖。因此在满足以下全部条件时,example 目标不会被抓取示例:

  1. 所有被文档化的目标都不需要 dev-deps,且
  2. 至少有一个被文档化的 crate 存在 dev-deps,且
  3. 所有 [[example]] 目标的 doc-scrape-examples 均未设置或为 false。

如果你想从 example 目标中抓取示例,就需要避免满足上述条件之一。例如,你可以为某个 example 目标设置 doc-scrape-examples = true,这等于告诉 Cargo:你可以接受 cargo doc 时构建 dev-deps。

rustdoc 的 output-format

该选项决定 cargo rustdoc 的输出格式,可选 htmljson,为工具提供了使用 rustdoc 实验性 JSON 格式 的途径。

用法如下:

cargo rustdoc -Z unstable-options --output-format json


codegen-backend

codegen-backend 特性允许通过 profile 选择 rustc 所使用的 codegen 后端。

示例:

[package]
name = "foo"

[dependencies]
serde = "1.0.117"

[profile.dev.package.foo]
codegen-backend = "cranelift"

要在 Cargo 配置的 profile 中使用该特性,需要先用 -Z codegen-backend[unstable] 配置表来启用它。例如:

# .cargo/config.toml
[unstable]
codegen-backend = true

[profile.dev.package.foo]
codegen-backend = "cranelift"

gitoxide

启用 'gitoxide' 不稳定特性后,所有或指定的 git 操作将由 gitoxide crate 而非 git2 来执行。

-Zgitoxide 会启用当前已实现的全部功能,也可以通过 -Zgitoxide=operation[,operationN] 语法单独选择用 gitoxide 执行哪些 git 操作。

可用操作如下:

  • fetch - 所有拉取操作都由 gitoxide 完成,包括 git 依赖和 crates 索引。
  • checkout (计划中) - 检出工作区,支持过滤器和子模块。

git

启用 'git' 不稳定特性后,gitoxidegit2 都会对 crates 索引和 git 依赖执行浅拉取(shallow fetch)。

-Zgit 会启用当前已实现的全部功能,也可以通过 -Zgit=operation[,operationN] 语法单独选择何时执行浅拉取。

可用操作如下:

  • shallow-index - 对索引执行浅克隆。
  • shallow-deps - 对 git 依赖执行浅克隆。

关于浅克隆的细节

  • 要启用浅克隆,拉取 git 依赖时添加 -Zgit=shallow-deps,拉取 registry 索引时添加 -Zgit=shallow-index
  • 浅克隆和浅签出的 git 仓库位于带有 -shallow 后缀的目录中,例如:
    • ~/.cargo/registry/index/*-shallow
    • ~/.cargo/git/db/*-shallow
    • ~/.cargo/git/checkouts/*-shallow
  • 当启用该不稳定特性时,获取或克隆 git 仓库始终执行浅获取操作,这大致等同于在所有地方执行 git fetch --depth 1
  • 即使存在 Cargo.lock 文件,或指定了提交 { rev = "…" },gitoxide 和 libgit2 仍然足够智能,能够在不解除浅获取限制的情况下完成浅获取。

script

Cargo 可以直接运行 .rs 文件,命令如下:

$ cargo +nightly -Zscript file.rs

其中 file.rs 可以非常简单,例如:

fn main() {}

用户可以在模块级注释中通过 cargo 代码栅栏可选地指定清单文件,例如:

#!/usr/bin/env -S cargo +nightly -Zscript
---cargo
[dependencies]
clap = { version = "4.2", features = ["derive"] }
---

use clap::Parser;

#[derive(Parser, Debug)]
#[clap(version)]
struct Args {
    #[clap(short, long, help = "Path to config")]
    config: Option<std::path::PathBuf>,
}

fn main() {
    let args = Args::parse();
    println!("{:?}", args);
}

Single-file packages

除了现有的多文件包(由 Cargo.toml 文件和其他 .rs 文件组成)外,我们正在引入单文件包的概念,这种包可以包含嵌入式清单。 单文件 .rs 包与其他普通 .rs 文件之间没有强制性的区别要求。

单文件包可以通过 --manifest-path 进行指定,例如 cargo test --manifest-path foo.rs。与 Cargo.toml 不同,这类文件无法被自动发现。

单文件包可以包含嵌入式清单。嵌入式清单以 TOML 格式存储在 Rust 的“前言”中,这是一种位于文件顶部的 Markdown 代码栅栏,其信息字符串以 cargo 开头。

自动推断/设置默认值的 manifest 字段:

  • package.name = <slugified file stem>
  • package.edition = <current>,这样就不必总是添加内嵌 manifest,代价是 rust 升级可能导致脚本失效
    • edition 未指定时会发出警告,提醒用户注意

不允许使用的 manifest 字段:

  • [workspace][lib][[bin]][[example]][[test]][[bench]]
  • package.workspacepackage.buildpackage.linkspackage.autolibpackage.autobinspackage.autoexamplespackage.autotestspackage.autobenches

单文件包默认的 CARGO_TARGET_DIR$CARGO_HOME/target/<hash>,这样可以:

  • 避免同一目录下多个单文件包互相冲突
  • 避免单文件包所在目录为只读时出问题
  • 避免弄乱用户目录

单文件包的 lockfile 会放在 CARGO_TARGET_DIR 中。将来支持 workspace 后,用户就能拥有持久的 lockfile。

Manifest 命令

你可以把 manifest 直接传给 cargo 命令而不用子命令,比如 foo/Cargo.toml,或单文件包如 foo.rs。这主要是为写入 #! 行而设计的。

cargo <subcommand> 的解析优先级为:

  1. 内置命令,或单文件包
  2. 别名
  3. 外部子命令

如果参数满足以下任一条件,就会被识别为 manifest 命令:

  • 包含路径分隔符
  • 扩展名为 .rs
  • 文件名为 Cargo.toml

cargo run --manifest-path <path>cargo <path> 的区别:

  • cargo <path> 使用 <path> 处的配置而非当前目录的配置,行为更接近 cargo install --path <path>
  • cargo <path> 的输出详细程度低于默认水平,传 -v 可获得正常输出。

运行带有嵌入式 manifest 的包时,arg0 会是脚本的路径。要获取可执行文件的路径,请参见 current_exe

文档更新

Profile 的 trim-paths 选项

这个功能新增了一个 profile 设置,用于控制如何清理最终生成的二进制文件中的路径。可以这样启用:

cargo-features = ["trim-paths"]

[package]
# ...

[profile.release]
trim-paths = ["diagnostics", "object"]

如果要在 Cargo 配置文件的 profile 中设置这个选项,需要使用 -Z trim-paths[unstable] 表来启用,例如:

# .cargo/config.toml
[unstable]
trim-paths = true

[profile.release]
trim-paths = ["diagnostics", "object"]

文档更新

trim-paths

作为 “Profile 设置” 中的新条目

trim-paths 是一个 profile 设置,用于启用并控制对构建产物中文件路径的清理。它接受以下取值:

  • "none"false —— 禁用路径清理
  • "macro" —— 清理 std::file!() 宏展开中的路径,内嵌 panic 消息中的路径就来自这里
  • "diagnostics" —— 清理编译器诊断输出中的路径
  • "object" —— 清理编译出的可执行文件或库中的路径
  • "all"true —— 清理所有可能位置中的路径

它也可以接受一个数组,组合使用 "macro""diagnostics""object"

默认情况下,dev 配置使用 nonerelease 配置使用 object。 你可以在 Cargo.toml 中手动指定该选项来覆盖默认值:

[profile.dev]
trim-paths = "all"

[profile.release]
trim-paths = ["object", "diagnostics"]

release 配置的默认设置(object)只清理输出可执行文件或库文件中的路径。 它总是会影响宏产生的路径(例如 panic 消息);对于调试信息,仅当这些信息与二进制文件一同嵌入时才会被清理(这是 Linux 和 windows-gnu 等 ELF 二进制平台的行为),如果它们位于单独的文件中则不会修改(这是 Windows MSVC 和 macOS 的行为)。不过,这些单独文件的路径仍会被清理。

如果 trim-paths 不是 nonefalse,那么以下路径如果出现在选定的范围内,都会被清理:

  1. 标准库和核心库(sysroot)源文件的路径将变成以 /rustc/[rustc commit hash] 开头,例如 /home/username/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs -> /rustc/fe72845f7bb6a77b9e671e6a4f32fe714962cec4/library/core/src/result.rs
  2. 当前包的路径将被移除,相对于当前工作区根目录,例如 /home/username/crate/src/lib.rs -> src/lib.rs
  3. 依赖包的路径将替换为 [package name]-[version]。例如 /home/username/deps/foo/src/lib.rs -> foo-0.1.0/src/lib.rs

如果标准库和核心库的源文件路径没有在清理范围内, 输出的路径将取决于是否存在 rust-src 组件。 如果存在,部分路径将指向你文件系统中的源文件副本; 如果不存在,它们将显示为 /rustc/[rustc commit hash]/library/... (与选择清理时的情况一样)。 其他所有源文件的路径都不会受到影响。

这不会影响源代码中硬编码的路径,例如字符串中的路径。

环境变量

作为 「Cargo 为 build script 设置的环境变量」的新增条目

  • CARGO_TRIM_PATHS_SCOPE — profile 中 trim-paths 选项的值。 false"none" 和空数组会被转换为 nonetrue"all" 变为 all; 非空数组中的值会合并为逗号分隔的列表。 如果 build script 引入了指向构建产物的绝对路径(比如调用编译器时), 用户可以要求在不同类型的产物中清理这些路径。 常见的需要清理的路径包括 OUT_DIRCARGO_MANIFEST_DIRCARGO_MANIFEST_PATH, 以及 build script 引入的其他路径,比如 include 目录。
  • CARGO_TRIM_PATHS_REMAP — Cargo 传给编译器的 <from>=<to> 路径重映射对, 以平台的路径分隔符连接。 仅在 trim-paths profile 激活时才会设置。 Build script 可以把这些映射转发给 C/C++ 编译器和其他工具, 例如通过 cc-ffile-prefix-map 选项, 使路径清理与构建的其他部分保持一致。

gc

-Zgc 标志用于启用与清理 Cargo 主目录下全局缓存相关的部分功能。

自动 gc 配置

-Zgc 标志会让 Cargo 读取与垃圾回收相关的额外配置选项。 可用设置如下:

# config.toml 示例文件。

# 用于定义全局缓存清理具体设置的子表。
[cache.global-clean]
# 超过该时长的源码缓存文件将被删除。
max-src-age = "1 month"
# 超过该时长的压缩 crate 缓存文件将被删除。
max-crate-age = "3 months"
# 超过该时长的索引缓存将被删除。
max-index-age = "3 months"
# 超过该时长的 git checkout 将从 checkout 缓存中删除。
max-git-co-age = "1 month"
# 超过该时长的 git clone 将从 git 缓存中删除。
max-git-db-age = "3 months"

注意,cache.auto-clean-frequency 选项已在 Rust 1.88 中稳定。

使用 cargo clean 手动垃圾回收

可以通过 cargo clean gc -Zgc 命令手动删除缓存。传入以下任一缓存选项即可执行删除:

  • --max-src-age=DURATION — 删除超过指定时长未使用的源码缓存文件。
  • --max-crate-age=DURATION — 删除超过指定时长未使用的 crate 缓存文件。
  • --max-index-age=DURATION — 删除超过指定时长未使用的 registry 索引(包括对应的 .cratesrc 文件)。
  • --max-git-co-age=DURATION — 删除超过指定时长未使用的 git 依赖 checkout。
  • --max-git-db-age=DURATION — 删除超过指定时长未使用的 git 依赖 clone。
  • --max-download-age=DURATION — 删除超过指定时长未使用的下载缓存数据。
  • --max-src-size=SIZE — 删除最旧的源码缓存文件,直到缓存低于指定大小。
  • --max-crate-size=SIZE — 删除最旧的 crate 缓存文件,直到缓存低于指定大小。
  • --max-git-size=SIZE — 删除最旧的 git 依赖缓存,直到缓存低于指定大小。
  • --max-download-size=SIZE — 删除最旧的下载缓存数据,直到缓存低于指定大小。

DURATION(时长)的格式为“N seconds/minutes/days/weeks/months”(秒/分钟/天/周/月),其中 N 为整数。

SIZE(大小)的格式为“N suffix”,其中 suffix 可以是 B、kB、MB、GB、kiB、MiB 或 GiB,N 为整数或浮点数。若未指定后缀,则数值表示字节数。

cargo clean gc -Zgc
cargo clean gc -Zgc --max-download-age=1week
cargo clean gc -Zgc --max-git-size=0 --max-download-size=100MB

open-namespaces

允许多个包共享同一个 API 命名空间

启用方式如下:

cargo-features = ["open-namespaces"]

[package]
# ...

panic-immediate-abort

扩展 panic 配置项,以支持 immediate-abort panic 策略。启用方式如下:

# Cargo.toml
cargo-features = ["panic-immediate-abort"]

[package]
# ...

[profile.release]
panic = "immediate-abort"

若要在 Cargo 配置文件的 profile 中设置此项,需使用 -Z panic-immediate-abort 命令行标志,或通过 [unstable] 表启用。示例如下:

# .cargo/config.toml
[unstable]
panic-immediate-abort = true

[profile.release]
panic = "immediate-abort"

fine-grain-locking

使用细粒度锁替代对整个构建缓存加锁。

注意:细粒度锁基于目录重组,因此隐式启用 build-dir-new-layout

[lints.cargo]

cargo 新增了一个 lints 工具表,在启用 -Zcargo-lints 时可用来配置 cargo 自身发出的 lint

[lints.cargo]
implicit-features = "warn"

它还可以与 RFC 2906 workspace-deduplicate 配合使用:

[workspace.lints.cargo]
implicit-features = "warn"

[lints]
workspace = true

路径基准(Path Bases)

path 依赖可以通过 base 键指定一个基准,其值为 配置[path-bases] 表里的某个路径基准名称,或某个 内置路径基准 的名称。Cargo 会把该路径基准的值拼接到 path 值前面(必要时加上路径分隔符),得到依赖的实际查找位置。

例如,Cargo.toml 中包含:

cargo-features = ["path-bases"]

[dependencies]
foo = { base = "dev", path = "foo" }

而配置中的 [path-bases] 表包含:

[path-bases]
dev = "/home/user/dev/rust/libraries/"

这样就会得到一个位于 /home/user/dev/rust/libraries/foopath 依赖 foo

路径基准可以是绝对路径,也可以是相对路径。相对路径相对于声明该基准的配置文件所在的父目录。

路径基准的名称只能包含字母数字字符、-_,必须以字母开头,且不能为空。

如果依赖中使用的路径基准名称既不在配置中,也不是内置基准,Cargo 会报错。

内置路径基准

Cargo 提供了一些隐式的 path base,无需在 [path-bases] 表中显式声明即可使用。

如果配置中也声明了与内置 path base 同名的名称,Cargo 会优先使用配置中的值。这样 Cargo 在新增内置 path base 时就不会产生兼容性问题(现有的同名定义会覆盖内置名称)。

native-completions

该特性将手写的补全脚本迁移到 Rust 原生实现,让我们能更方便地添加、扩展和测试新的补全功能。在 nightly 通道上该特性默认启用,无需额外的 -Z 选项。

特别欢迎以下方面的反馈:

  • 本应转义或加引号但处理不正确的参数
  • 信息不准确之处
  • 命令行解析中的 bug
  • 未报告补全候选的参数
  • 已知问题造成困扰的情况

反馈可以分为以下几类:

如有疑问,可在 #14520zulip 上讨论。

如何使用 native-completions 功能:

  • bash: 在 ~/.local/share/bash-completion/completions/cargo 文件中添加 source <(CARGO_COMPLETE=bash cargo +nightly)

  • zsh: 在你的 .zshrc 文件中添加 source <(CARGO_COMPLETE=zsh cargo +nightly)

  • fish: 在 $XDG_CONFIG_HOME/fish/completions/cargo.fish 文件中添加 source (CARGO_COMPLETE=fish cargo +nightly | psub)

  • elvish: 在 $XDG_CONFIG_HOME/elvish/rc.elv 文件中添加 eval (E:CARGO_COMPLETE=elvish cargo +nightly | slurp)

  • powershell: 在 $PROFILE 文件中添加 CARGO_COMPLETE=powershell cargo +nightly | Invoke-Expression

feature 统一

启用 -Z feature-unification 后,可以通过 resolver.feature-unification 配置项来控制工作区内 feature 的统一方式。 若未启用 -Z feature-unification 不稳定标志, 则 resolver.feature-unification 配置将被忽略。

resolver.feature-unification

  • 类型:字符串
  • 默认值:"selected"
  • 环境变量:CARGO_RESOLVER_FEATURE_UNIFICATION

指定哪些包参与feature 统一

  • selected:合并当前构建中指定所有包的依赖 feature。
  • workspace:合并所有工作区成员的依赖 feature, 无论当前构建指定了哪些包。
  • package:按包独立处理依赖 feature, 当不同包激活了不同的 feature 集合时,允许依赖存在重复构建。

lockfile-publish-time

使用 cargo generate-lockfile -Zunstable-options --publish-time <time> 时,包解析将不再考虑发布时间晚于指定时间的任何包。

Package message format

cargo package 中的 --message-format 标志用于控制输出消息的格式。目前它只能与 --list 标志配合使用,影响文件列表的输出格式。需要 -Zunstable-options。详见 cargo package --message-format

rustdoc depinfo

-Z rustdoc-depinfo 标志利用 rustdoc 的 dep-info 文件来判断是否需要重新生成文档。它还可以与 -Z checksum-freshness 结合使用,通过检测校验和变化而非文件 mtime 来判断。

no-embed-metadata

Rust 的默认行为是把 crate 元数据嵌入到 rlibdylib 产物中。由于 Cargo 还会为这些中间产物传递 --emit=metadata 以启用流水线编译,这导致大量元数据在磁盘上重复存储,浪费 target 目录的磁盘空间。

该特性会让 Cargo 向编译器传递 -Zembed-metadata=no 标志,指示其不要在 rlib 和 dylib 产物中嵌入元数据。这种情况下,元数据只会存储在 .rmeta 文件中。

cargo +nightly -Zno-embed-metadata build

unstable-editions

cargo-features 列表中的 unstable-editions 值允许 Cargo.toml 清单指定尚未稳定的 edition。

cargo-features = ["unstable-editions"]

[package]
name = "my-package"
edition = "future"

当新的 edition 发布时,在该 edition 稳定之前都需要启用 unstable-editions 这个 feature。

特殊的 “future” edition 用于收纳仍在开发中的新特性,它永远是unstable的。“future” edition 本身不会带来任何新行为,其中的每项改动都需要显式开启,比如添加 #![feature(...)] 属性。

fix-edition

-Zfix-edition 是一个永远unstable的标志,用于辅助测试 edition 迁移,尤其是在 crater 中使用。它只对 cargo fix 子命令有效,有两种形式:

  • -Zfix-edition=start=$INITIAL —— 检查当前 edition 是否等于给定数字。如果不等,则以成功状态退出(因为我们想忽略更旧的 edition);如果相等,则执行相当于 cargo check 的操作。它用于 crater 的 “start” 工具链,为 “before” 工具链建立基线。
  • -Zfix-edition=end=$INITIAL,$NEXT —— 检查当前 edition 是否等于给定的 $INITIAL 值。如果不等,则以成功状态退出;如果相等,则执行向 $NEXT` 所指定 edition 的迁移。之后它会修改 Cargo.toml,添加相应的 cargo-features = ["unstable-edition"],更新 edition 字段,并执行相当于 cargo check 的操作来验证迁移在新 edition 上能正常工作。

例如:

cargo +nightly fix -Zfix-edition=end=2024,future

section-timings

该特性用于扩展 cargo build --timings 的输出。它指示 rustc 生成各编译阶段的耗时数据,这些数据随后会显示在耗时的 HTML 或 JSON 输出中。

cargo +nightly -Zsection-timings build --timings

构建分析

-Zbuild-analysis 特性会将详细的构建指标记录并持久化到磁盘上,并提供用于查询历史构建的新命令。

启用后,Cargo 会以 JSONL 格式将构建日志写入 $CARGO_HOME/log/ 目录。每次调用 cargo 都会生成一个以唯一会话 ID 命名的日志文件。这些日志包含耗时信息、重新构建原因及其他构建元数据,可通过 cargo report 子命令进行分析。

要启用构建分析,请在 Cargo 配置中添加以下内容:

# 示例 config.toml 文件。

[unstable]
build-analysis = true

# 启用构建指标收集
[build.analysis]
enabled = true

在稳定版工具链上设置此项仅会发出未知配置警告,因此在 Cargo 配置中保持启用是安全的。

cargo report 命令

-Zbuild-analysis 下可用以下命令:

  • cargo report sessions — 列出之前的构建会话。使用此命令查找会话 ID 以供其他报告命令使用。
  • cargo report timings — 从之前的会话生成 HTML 耗时报告,类似于 cargo build --timings 但无需重新构建。
  • cargo report rebuilds — 报告 Crate 被重新构建的原因,有助于诊断意外的重新编译。

build-dir-new-layout

启用新的 build-dir 文件系统布局。此项布局变更为改进缓存和锁定机制扫清了障碍。

compile-time-deps

这是一个永久不稳定的标志,只构建 proc-macro 和构建脚本(及其必需的依赖),并运行构建脚本。

它供 rust-analyzer 等工具使用,永远不会被稳定化。

示例:

cargo +nightly build --compile-time-deps -Z unstable-options
cargo +nightly check --compile-time-deps --all-targets -Z unstable-options

rustc-unicode

让 Cargo 的错误信息启用 rustc 的 unicode 错误格式。

rustdoc mergeable info

-Z rustdoc-mergeable-info 利用 rustdoc 的 mergeable crate 信息,让 cargo doc 能够合并来自不同输出目录的跨 crate 信息(如搜索索引、源码文件索引等),并并行运行 rustdoc

json-target-spec

-Z json-target-spec 命令行标志允许使用自定义 target spec JSON 文件作为构建目标。

cargo +nightly build --target my-target.json -Z json-target-spec

通常需要与 build-std 配合使用。

hint-msrv

-Z hint-msrv 命令行标志让 Cargo 把 package.rust-version 传给 rustc,从而影响 rustc 发出哪些 lint。

你可以在全局 ~/.cargo/config.toml 中设置该选项,nightly 版 Cargo 会自动启用它,而 stable 版 Cargo 则会静默忽略这个不稳定选项:

[unstable]
hint-msrv = true

min-publish-age

-Zmin-publish-age 特性允许用户为依赖版本指定一个最短发布时长。设置后,Cargo 不会使用发布时间距当前不足该时长的 registry crate 版本,同时提供覆盖机制,以应对紧急安全修复等特殊情况。

例如,在 <repo>/.cargo/config.toml 中:

[registry]
global-min-publish-age = "14 days"

新增的配置项

Cargo 的配置格式将新增以下内容:

[resolver]
incompatible-publish-age = "deny" # 指定 resolver 对此类情况的处理方式

[registries.<name>]
min-publish-age = "..."  # 针对该 registry 覆盖 `registry.global-min-publish-age`

[registry]
min-publish-age = "..."  # 针对 crates.io 覆盖 `registry.global-min-publish-age`
global-min-publish-age = "0"  # 该 registry 来源的包所允许的最短发布时长

resolver.incompatible-publish-age

  • 类型:字符串
  • 默认值:"deny"
  • 环境变量:CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE

在解析依赖版本时,指定对 pubtime(如存在)不满足 registry.min-publish-age 要求的版本的处理方式。可选值包括:

  • allow:将不满足发布时长要求的版本与其他版本同等对待
  • deny:忽略不满足要求的版本,除非它们已存在于 lock file 中

registries.<name>.min-publish-age

  • 类型:字符串
  • 默认值:无
  • 环境变量:CARGO_REGISTRIES_<name>_MIN_PUBLISH_AGE

指定该 registry 来源的包,其版本自 pubtime 起需经过的最短时长,用于配合 resolver.incompatible-publish-age 进行判断。未设置时将使用 registry.global-min-publish-age

如果该 registry 不支持此功能,则该配置会被忽略。

支持以下取值:

  • 一个整数后跟“seconds”、“minutes”、“hours”、“days”、“weeks”或“months”
  • "0" 允许所有包

registry.min-publish-age

  • 类型:String
  • 默认值:无
  • 环境变量:CARGO_REGISTRY_MIN_PUBLISH_AGE

指定自某个版本的 pubtime 以来,来自 crates.io 的包可以被 resolver.incompatible-publish-age 考虑的最小时间间隔。若未设置,则将使用 registry.global-min-publish-age

支持以下值:

  • 一个整数后跟“seconds”、“minutes”、“hours”、“days”、“weeks”或“months”
  • "0" 允许所有包

通常使用 "0""N days""N weeks"

registry.global-min-publish-age

  • 类型:String
  • 默认值:"0"
  • 环境变量:CARGO_REGISTRY_GLOBAL_MIN_PUBLISH_AGE

指定自某个版本的 pubtime 以来,包可以被 resolver.incompatible-publish-age 考虑的全局最小时间间隔。如果未通过 registries.<name>.min-publish-age 为特定注册表设置 min-publish-age,Cargo 将使用此全局最小发布时间。

支持以下值:

  • 一个整数后跟“seconds”、“minutes”、“hours”、“days”、“weeks”或“months”
  • "0" 允许所有包

添加到 Resolver

以下内容将作为“Yanked versions”的兄弟章节,添加到解析器章节中:

“Pubtime 不兼容的版本”

发布时间比配置的 min-publish-age 更新的版本被视为 pubtime 不兼容。当 resolver.incompatible-publish-age 设置为 deny 时,解析器将忽略这些版本,除非它们已存在于 Cargo.lock 文件中。将配置设置为 allow 会禁用此检查;若与 cargo update --precise 结合使用,Cargo 将拉取特定版本及其传递依赖。

已稳定并移除的特性

Compile progress

compile-progress 特性已在 1.30 版本中稳定,进度条现在默认开启。关于如何控制该特性,请参阅 term.progress

Edition

Cargo.toml 中指定 edition 的功能已在 1.31 版本中稳定。详情请参阅edition 字段

rename-dependency

Cargo.toml 中重命名依赖的功能已在 1.31 版本中稳定。详情请参阅重命名依赖

Alternate Registries

对备用 registry 的支持已在 1.34 版本中稳定。详情请参阅Registries 章节

Offline Mode

offline 特性已在 1.36 版本中稳定。关于离线模式的用法,请参阅 --offline 标志

publish-lockfile

publish-lockfile 特性已在 1.37 版本中移除。现在,如果包中包含二进制目标,发布时总会包含 Cargo.lock 文件;cargo install 需要加上 --locked 标志才会使用 Cargo.lock 文件。详情请参阅 cargo packagecargo install

default-run

default-run 特性已在 1.37 版本中稳定。关于如何指定默认运行的目标,请参阅 default-run 字段

cache-messages

编译器消息缓存功能已在 1.40 版本中稳定。编译器警告现在默认会被缓存,并在重新运行 Cargo 时自动重放。

install-upgrade

install-upgrade 特性已在 1.41 版本中稳定。cargo install 现在会自动升级看起来已过时的软件包。详见 cargo install 文档。

Profile Overrides

Profile overrides 已在 1.41 版本中稳定。有关使用 override 的更多信息,请参阅 Profile Overrides

Config Profiles

在 Cargo 配置文件和环境变量中指定 profile 的功能已在 1.43 版本中稳定。有关在配置文件中指定 profile 的更多信息,请参阅配置中的 [profile]

crate-versions

-Z crate-versions 标志已在 1.47 版本中稳定。crate 版本现在会自动显示在 cargo doc 生成的文档侧边栏中。

Features

-Z features 标志已在 1.51 版本中稳定。有关使用新 feature 解析器的更多信息,请参阅 feature resolver version 2

package-features

-Z package-features 标志已在 1.51 版本中稳定。有关使用 features 命令行选项的更多信息,请参阅 resolver version 2 命令行标志

Resolver

Cargo.toml 中的 resolver 特性已在 1.51 版本中稳定。有关指定 resolver 的更多信息,请参阅 resolver versions

在 build script 中指定额外链接器参数的 extra-link-arg 特性已在 1.56 版本中稳定。有关指定额外链接器参数的更多信息,请参阅 build script 文档

configurable-env

configurable-env 功能用于在 Cargo 配置中指定环境变量,已在 1.56 版本中稳定化。关于配置环境变量的更多信息,请参阅配置文档

rust-version

Cargo.toml 中的 rust-version 字段已在 1.56 版本中稳定化。关于使用 rust-version 字段和 --ignore-rust-version 选项的更多信息,请参阅rust-version 字段

patch-in-config

-Z patch-in-config 标志以及 Cargo 配置文件中对 [patch] 段的支持已在 1.56 版本中稳定化。更多信息请参阅patch 字段

edition 2021

2021 edition 已在 1.56 版本中稳定化。关于设置 edition 的更多信息,请参阅edition 字段。关于迁移现有项目,请参阅cargo fix --editionEdition Guide

自定义命名 profile

自定义命名 profile 已在 1.57 版本中稳定化。更多信息请参阅profile 章节

Profile 的 strip 选项

Profile 的 strip 选项已在 1.59 版本中稳定化。更多信息请参阅profile 章节

未来不兼容报告

生成未来不兼容报告的支持已在 1.59 版本中稳定化。更多信息请参阅未来不兼容报告章节

命名空间特性

命名空间特性已在 1.60 版本中稳定化。更多信息请参阅特性章节

弱依赖特性

弱依赖特性已在 1.60 版本中稳定化。更多信息请参阅特性章节

timings

-Ztimings 选项已在 1.60 版本中稳定为 --timings。 timings 输出格式选项 (例如 --timings=html 以及机器可读的 --timings=json 输出) 已在 1.94.0-nightly 中移除。

config-cli

--config 命令行选项已在 1.63 版本中稳定。 详见 config 文档

multitarget

-Z multitarget 选项已在 1.64 版本中稳定。 关于如何设置默认的 target 平台三元组, 请参阅 build.target

crate-type

cargo rustc--crate-type 标志已在 1.64 版本中稳定。 详见 cargo rustc 文档

Workspace Inheritance

Workspace Inheritance 已在 1.64 版本中稳定。 详见 workspace.packageworkspace.dependenciesinheriting-a-dependency-from-a-workspace

terminal-width

-Z terminal-width 选项已在 1.68 版本中稳定。 只要 Cargo 能够自动检测终端宽度,就会在从终端运行时把宽度传给编译器。

sparse-registry

Sparse registry 支持已在 1.68 版本中稳定。 详见 Registry Protocols

cargo logout

cargo logout 命令已在 1.70 版本中稳定。

doctest-in-workspace

cargo test-Z doctest-in-workspace 选项已在 1.72 版本中稳定并默认启用。 关于编译和运行测试时的工作目录,详见 cargo test 文档

keep-going

--keep-going 选项已在 1.74 版本中稳定。详情可参考 cargo build 中的 --keep-going 标志

[lints]

[lints](通过 -Zlints 启用)已在 1.74 版本中稳定。

credential-process

-Z credential-process 特性已在 1.74 版本中稳定。

详情请参阅 Registry Authentication 文档。

registry-auth

-Z registry-auth 特性已在 1.74 版本中稳定,但需要额外配置 credential-provider。

详情请参阅 Registry Authentication 文档。

check-cfg

-Z check-cfg 特性已在 1.80 版本中稳定,并成为默认行为。

关于如何指定自定义 cfg,请参阅 build script 文档

Edition 2024

2024 edition 已在 1.85 版本中稳定。关于如何设置 edition,请参阅 edition 字段。关于如何迁移现有项目,请参阅 cargo fix --editionThe Edition Guide

自动垃圾回收

自动删除旧文件的支持已在 Rust 1.88 中稳定。更多信息请参阅 配置章节

doctest-xcompile

从 Rust 1.89 开始,doctest 交叉编译已被无条件启用。cargo test 运行 doctest 时现在会遵循 --target 标志。

package-workspace

多 package 发布功能已在 Rust 1.90.0 中稳定。

build-dir

build.build-dir 的支持已在 1.91 版本中稳定。关于如何更改 build-dir,请参阅 配置文档

Build-plan

build 命令的 --build-plan 参数已在 1.93.0-nightly 中移除。移除原因见 https://github.com/rust-lang/cargo/issues/7614

config-include

通过 include 配置项包含额外配置文件的功能已在 1.93.0 中稳定化。详见 include 配置文档

pubtime

pubtime 索引字段已在 Rust 1.94.0 中稳定化。

lockfile-path

resolver.lockfile-path 配置字段的支持已在 Rust 1.97.0 中稳定化。

warnings

build.warnings 配置字段已在 Rust 1.97 中稳定化。

评论 (0)