在 nightly 上减少目标目录大小的实验

Lobsters Hottest 新闻

摘要

Cargo 团队正在 Rust nightly 频道上进行实验,通过默认设置为 -Zembed-metadata=no 来减少目标目录大小,旨在收集关于这一潜在改进的反馈。

<p><a href="https://lobste.rs/s/omsqyf/experiment_reducing_target_directory">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/08/18 20:22

# 测试在 nightly 版本中减小目标目录大小 | Inside Rust 博客 来源:https://blog.rust-lang.org/inside-rust/2026/08/18/reducing-target-dir-size-on-nightly/ 简要说明:Cargo 团队将推出一项实验,以评估一项拟议变更对用户的影响。Cargo 将在 *nightly* 频道默认启用 `\-Zembed\-metadata=no` 功能,这有助于在一定程度上减小目标目录的大小。本实验旨在收集关于该功能可行性的反馈。用户无需主动迁移到支持此功能,但可在此期间报告任何问题,并在需要时选择退出(opt\-out)(https://blog.rust-lang.org/inside-rust/2026/08/18/reducing-target-dir-size-on-nightly/#how-to-opt-out)。 ## 这是什么? Rust 编译产物占用大量磁盘空间,经常被用户列为最困扰的问题之一。在我们 2025 年的 Rust 现状调查中,这实际上是第二常见的报告问题 (https://blog.rust-lang.org/2026/03/02/2025-State-Of-Rust-Survey-results/#challenges-and-wishes-about-rust),仅次于编译速度。`target` 目录变得非常大的原因有多种,例如: - Cargo 默认会从头编译整个 crate 图,产生大量构建产物。 - 调试信息占用大量磁盘空间。 - 增量编译产物占用大量磁盘空间。 虽然你可以禁用调试信息或增量编译来减小 `target` 目录的大小,但这当然会以牺牲编译速度和程序可调试性为代价。然而,目前 `target` 目录中有一部分数据即使并非必需,却占据了过多的空间。这就是“crate 元数据”,它可能在多个文件中重复存储。我们将在本文中重点讨论这一点。 多年来,Cargo 一直使用流水线编译 (pipelined compilation) (https://blog.rust-lang.org/2019/09/26/Rust-1.38.0/#pipelined-compilation) 来加速 crate 图的构建。在编译库 crate 时,它会指示编译器尽快生成一个 `.rmeta` 文件(包含使用该库所需的所有 crate 元数据),甚至在最终可执行代码生成之前。这使得依赖 crate 可以更早地开始编译。然而,一旦库编译完成,最终生成的 `.rlib` 文件将同时包含可执行代码和 Rust 特定的元数据。这意味着编译完成后,每个库 crate 的元数据会在磁盘上存储两次:一次在 `.rmeta` 文件中,一次在 `.rlib` 文件中。这会导致 `target` 目录大小的显著增加。 为了减少构建产物中不必要的数据重复,去年我们引入了一个不稳定的编译器标志 (https://github.com/rust-lang/rust/pull/137535) `-Zembed-metadata`,以及一个同名的相应 Cargo 标志 (https://github.com/rust-lang/cargo/pull/15378)。当使用 `-Zembed-metadata=no` 时,编译器将停止将元数据放入 `.rlib` 文件中,从而减小其文件大小。 不久,当 Cargo 和所使用的 `rustc` 都处于 `nightly` 频道时,Cargo 将开始默认使用 `-Zembed-metadata=no`。请注意,这是一项实验,该功能目前尚未计划稳定。我们希望评估这一变更在实践中的表现,并收集 nightly 用户的反馈。因此,如果你遇到任何与此次变更相关的问题,请进行报告 (https://github.com/rust-lang/cargo/issues)! ## 它有多大帮助? 我们使用最近的 nightly 编译器 (`rustc 1.100.0-nightly (67854e511 2026-08-15)`),在 `x86_64-unknown-linux-gnu` 目标上,以多种配置编译了两个 crate(`serde` 和 `cargo` 自身): - `dev` 配置文件,分别启用/禁用增量编译,以及启用/禁用调试信息 - `release` 配置文件,禁用增量编译,禁用调试信息 我们可以在下表中看到结果。`Before` 列显示了使用之前默认设置 (`-Zembed-metadata=yes`) 时 `target` 目录的大小,而 `After` 列显示了使用 `-Zembed-metadata=no`(即将成为 nightly 频道的默认设置)后的目标磁盘大小。 | 配置文件 | 增量编译 | 调试信息 | Before [MiB] | After [MiB] | 减少比例 | | :--- | :--- | :--- | :--- | :--- | :--- | | `dev` | 是 | 是 | 179.70 | 171.29 | -4.7% | | `dev` | 是 | 否 | 96.84 | 88.44 | -8.7% | | `dev` | 否 | 是 | 81.12 | 72.68 | -10.4% | | `dev` | 否 | 否 | 31.06 | 22.62 | -27.2% | | `release` | 否 | 否 | 40.88 | 28.68 | -29.8% | 正如预期的那样,磁盘空间的节省在很大程度上取决于 crate 元数据本身占 `target` 目录的比例。如果没有增量产物且没有调试信息,例如使用 `release` 配置文件的默认配置时,节省是显著的,本例中接近 30%。另一方面,如果我们使用 `dev` 配置文件的默认设置(同时启用增量编译和生成调试信息),那么节省就更为有限(本例中约为 5%),因为调试信息和增量构建产物的大小远远超过了 crate 元数据的大小。 以下是编译 Cargo 自身的结果,略好于 serde。在最佳情况下,新的默认设置将 `target` 目录的大小减少了约 33%,在绝对量上接近 300 MiB! | 配置文件 | 增量编译 | 调试信息 | Before [MiB] | After [MiB] | 减少比例 | | :--- | :--- | :--- | :--- | :--- | :--- | | `dev` | 是 | 是 | 3151.16 | 2910.88 | -7.6% | | `dev` | 是 | 否 | 1476.00 | 1235.71 | -16.3% | | `dev` | 否 | 是 | 2065.75 | 1825.45 | -11.6% | | `dev` | 否 | 否 | 999.71 | 759.41 | -24.0% | | `release` | 否 | 是 | 807.05 | 537.15 | -33.4% | 这并不能完全解决 `target` 目录过大的问题,但至少能提供一些帮助。 ## 这会影响我吗? 在绝大多数情况下,使用 `-Zembed-metadata=no` 后,除了 `target` 目录变小外,你不应该注意到其他任何不同。然而,如果你由于某种原因手动链接 `.rlib` 文件,现在可能还需要使用 `--extern` 标志将对应的 `.rmeta` 文件传递给编译器,以便访问 crate 的元数据。如果你有类似这样的用例,请告知我们 (https://github.com/rust-lang/cargo/issues)! 如果操作不当,你可能会遇到类似以下的错误: ``` error: only metadata stub found for `rlib` dependency `foo` please provide path to the corresponding .rmeta file with full metadata ``` 请注意,即使使用 `-Zembed-metadata=no`,Cargo 目前也不会“提升” (uplift) (https://github.com/rust-lang/cargo/issues/17359) 对应的 `.rmeta` 文件。这意味着与 `.rlib` 文件不同,`.rmeta` 文件在叶库构建完成后不会作为最终的构建产物 (https://doc.rust-lang.org/cargo/reference/build-cache.html) 出现在 `target/` 目录中。如果你想定位它,必须在嵌套的构建目录中查找其位置,例如使用 Cargo 的 JSON 输出 (https://doc.rust-lang.org/cargo/reference/external-tools.html#json-messages)。 如果你使用的构建系统不是 Cargo,那么这个变更不会影响你。 ## 如何选择退出(opt out)? 如果你希望选择退出,你可以向 Cargo 传递 `-Zembed-metadata=yes` 命令行参数(注意这是作为 Cargo 标志传递的,而不是在 `RUSTFLAGS` 中作为编译器标志,因为 Cargo 必须知道该标志的值),或者设置环境变量 `CARGO_UNSTABLE_EMBED_METADATA=true`。你也可以使用 `.cargo/config.toml` 文件来选择退出: ```toml [unstable] embed-metadata = true ``` ## 未来的工作 通过在 `nightly` 频道默认启用此功能,我们希望了解它在实践中的表现,以及 Cargo 用户是否受到此变更的负面影响。在收集到关于该功能的反馈并了解到任何潜在问题后,Cargo 团队将决定如何继续推进:是直接稳定该功能、需要做出更改,还是存在需要我们重新考虑的重大问题。 因此,如果你遇到任何与这个新默认设置相关的问题,请在 Cargo 仓库中开启一个问题 (https://github.com/rust-lang/cargo/issues),以便我们了解这些问题。我们无法修复我们不知道的问题,谢谢! 如果你对该功能的进展感兴趣,可以关注其跟踪问题 (https://github.com/rust-lang/cargo/issues/15495)。

相似文章

Zig ELF 二进制文件代码高尔夫 (2025)

Lobsters Hottest

深入技术探讨如何缩小 Zig ELF 二进制文件的大小,从 2180K 缩减至 500 字节以下,通过去除调试信息、切换到 ReleaseSmall 以及使用 freestanding 目标。

提前发射元数据,可使 Rust 的构建/检查速度最高提升两倍

Hacker News Top

headstart 是一组对 rustc 和 cargo 的补丁,用于提前发射 crate 元数据(`.early-rmeta`),使依赖 crate 在其依赖项仍在对函数体进行类型检查时,就能开始针对接口元数据进行编译。在 13 个真实 Rust 项目中,干净的 `cargo check` 构建速度最高可提升 54%,`cargo build` 最高可提升 42%。

探索构建微型FUSE文件系统

Hacker News Top

本文将引导你使用Rust构建一个名为magicfs的最小FUSE文件系统,该系统使用metadata.json和blob文件作为后端存储,演示了名称查找、inode稳定性和内核缓存等核心文件系统概念。