🦀 Cargo 1.94 深度解析:构建提速、锁机制革新与未来规划

🦀 Cargo 1.94 深度解析:构建提速、锁机制革新与未来规划

Photos provided by Unsplash OR Pexels

引言

在 Rust 生态系统中,Cargo 作为构建系统和包管理器,其每一次迭代都牵动着万千开发者的日常工作。Rust 1.94 版本的开发周期中,Cargo 团队聚焦于提升构建效率、增强并发安全性和改善开发者体验。从重构构建目录布局到引入细粒度的目标目录锁机制,从结构化日志工具到 TOML 1.1 规范支持,这一系列更新不仅解决了长期存在的痛点,也为未来功能铺平道路。本文将带你深入了解这些变化的技术细节、设计权衡以及社区的协作方式。

解码 Cargo 1.94:新功能、优化与未来方向

过去六周,Rust Cargo 团队持续推进多项关键改进:构建目录布局优化、目标目录锁定机制、结构化日志工具、TOML 1.1 支持等。本文将深入解读这些更新的技术细节、设计决策背后的思考,以及社区协作的最新进展,为你呈现 Cargo 生态系统的发展脉络。

英文标题: Decoding Cargo 1.94: New Features, Optimizations, and Future Directions


Cargo 开发周期回顾:1.94 版本

本文总结了过去 6 周 Cargo 团队的开发进展,这段时间主要对应 Rust 1.94 版本的合并窗口。

本期插件推荐

Cargo 无法满足所有人的所有需求——这既源于其必须维护的兼容性保证,也体现了生态系统的多样性。插件在 Cargo 生态中扮演着重要角色,我们希望通过这个栏目展示社区的优秀作品。

本期推荐插件是 cargo-edit,它提供了编辑Cargo.toml文件的命令集。其中cargo addcargo rm已合并到 Cargo 主程序中。该插件还提供了cargo upgrade(用于更新版本要求,Cargo 主程序跟踪于#12425)和cargo set-version(用于修改package.version,暂无合并计划)。

感谢 kpreid 的推荐!

欢迎为下期文章提交插件建议

功能实现

构建目录布局

1.93 版本更新

ranger-ross 提交了#16502,更新了 Cargo 关于构建目录布局的内部文档。这份文档为审查这一变更提供了新的视角,促使了进一步的优化,如#16514#16515#16519

在一个不相关的变更中,epage 曾提议使CARGO_BIN_EXE_*变量在运行时(而不仅是编译时)可用(Zulip 讨论),但在发现实际不需要后放弃了这一想法。在分析首次 crater 运行结果后,他们决定推进这一改变以减轻对生态系统的影响并可能带来其他好处,提交了#16421

epage 还尝试在新的构建目录布局下运行 Cargo 的全部测试套件(#16375),这导致了#16348的提出。

新一轮crater 运行已启动,结果分析正在进行中。

目标目录锁定

1.93 版本更新

自上次更新以来,除了已有挑战外,另一个问题是在读取指纹以决定是否修改缓存条目时需要持有锁。锁的升级和降级存在死锁风险。

上次更新结束时提出了顶层构建操作拥有所有锁并独占获取的想法。这有助于解决指纹问题——我们在读取指纹前获取锁,确保其有效性。但这意味着两个相同的构建会争用锁。至少 rust-analyzer 的cargo checkcargo test(包装了cargo build)或cargo clippy不会相互争用——但某些容易被忽视的重要情况下它们会争用。对于cargo checkcargo clippycargo clippy仅为工作区成员获取唯一缓存条目,因此非工作区成员会争用锁。对于cargo checkcargo test,缓存条目是唯一的(至少目前如此,参见#3501),但过程宏和构建脚本除外。我们决定暂时搁置这些问题,先合并一个最小化设计以便后续迭代。

我们还推迟处理了动态 rlimit用户阻塞消息以及在构建线程被阻塞时复用其他构建单元而非闲置的问题。至此,我们成功合并了#16155。这些推迟事项的进展在#4282中跟踪。

结构化日志

1.93 版本更新

weihanglo 持续推进此项工作,包括:

  • 代码重构(#16485
  • 文档编写(#16476
  • cargo report timings添加缺失功能(#16414#16441
  • 添加cargo report rebuild命令(#16456#16408#16448),用于查看重建原因
  • 添加cargo report sessions命令(#16428),查找用于cargo report timingscargo report rebuild的 ID
  • cargo report *命令提供手册页(#16432#16430
  • 移除不稳定的--timings=FMT标志,因其与cargo report timings功能重复(#16420

在项目目标跟踪问题上,weihanglo 发布了进展总结,列出了稳定化的剩余步骤以及社区的参与方式。

TOML 1.1 支持

12 月 18 日,TOML v1.1 规范正式发布。此版本的主要变化是允许在内联表格中使用换行符。同一天,toml v0.9.10发布,支持解析 TOML 1.1 文件

Zulip上,我们讨论了 Cargo 的过渡策略。用户可能无意中使用 TOML v1.1 特性,从而提升解析其清单所需的 Cargo 版本。这也是我们鼓励在 CI 中验证rust-version的原因之一。不过影响有限,因为cargo package会重写发布的Cargo.toml,仅使用 TOML v0.5 或更早版本的功能。这一变化主要影响使用原始仓库的git 补丁的情况。

需要注意一个细节:toml目前不保留时间中秒或纳秒是省略还是为0,默认假设秒不会被省略,纳秒为0时总是省略。如果toml开始保留这些信息,且Cargo.toml的某个字段使用了时间(可能仅在[*.metadata]字段中),且用户使用了新语法格式化时间,那么cargo package生成的Cargo.toml将需要新版本 Cargo 才能解析。

Cargo 可以检测是否使用了 TOML v1.1 特性,并在package.rust-version字段过低时发出警告,但我们认为这并非阻塞性问题——这与当前使用任何其他字段可能提升 MSRV 的情况类似。

Cargo 对 TOML v1.1 的支持已于 12 月 28 日合并(#16415)。

cargo-cargofmt

长期以来,社区一直期望cargo fmt也能格式化Cargo.toml文件(rustfmt#4091)。这项工作的一大障碍是Cargo.toml官方风格指南与现有或预期的使用方式不一致。风格指南的提案曾在Zulip上讨论过,但最终停滞。

epage 创建了cargo-cargofmt作为风格指南思想和实现方法的试验田。这包括总结过往讨论以及比较现有格式化工具

iepathos 加入并扩展了格式化规则,包括调整单行和多行数组之间转换的复杂工作(cargo-cargofmt#37)。将内联表格格式化为多行的功能被推迟,因为这可能需要新的Style Edition来确保包的 MSRV 足够高以支持该特性。

查看cargo-cargofmt#25了解当前支持的功能,以及项目议题了解正在考虑的内容。

lockfile-path 配置

1.82 版本更新

此前,--lockfile-path ../Cargo.lock的不稳定支持已添加(#14326)。在#15510中,我们收到了通过环境变量支持该功能的请求。讨论后我们认为应将该功能从 CLI 标志转向配置字段,这样既能支持环境变量,也能通过--config支持 CLI。我们特别关注的是用户通过cargo <cmd> --help查找所需功能的易用性。标志越多,用户越可能找不到所需标志,导致所有标志的价值降低——用户会转而通过其他方式解决他们认为不支持的功能。这在--out-dir/--artifact-dir的讨论中已经提及(#6100)。考虑到此功能的适用范围,将其”隐藏”在配置中似乎是最佳选择。

weihanglo#16510中添加了resolver.lockfile-path配置。我们将在后续开发周期中移除--lockfile-path,给调用者留出过渡时间。

设计讨论

工作区和配置发现机制

如果不小心将Cargo.toml文件复制到主目录,且没有显式声明[workspace],它会导致所有包的构建失败。任何位于父目录中的损坏或仅限 nightly 的Cargo.toml.cargo/config.toml文件都会出现这种情况(例如#6646#6706)。对于Cargo.toml,Cargo 会检查当前清单是否属于某个工作区。

我们至少可以改进错误信息,这在#6706中跟踪。同时,劝阻新用户在主目录中意外创建包也会有所帮助(#16562)。

对于 nightly 清单的情况,Cargo 可以检查父级Cargo.toml是否有[workspace]表,并通过延迟 nightly 特性检查来跳过它。但 nightly 特性可能影响工作区发现。

对于清单,一种解决方法是向包中添加空的[workspace]。但如果在子目录中运行cargo new,它会自动被添加为成员。我们可以扩展package.workspace = "<path>",增加package.workspace = <bool>来选择性启用或禁用工作区的自动发现。对于这种情况,可以设置package.workspace = false来避免向上遍历目录树。Cargo 脚本默认禁用工作区自动发现,这可能是启用它的方式。这个想法在#16563中跟踪。

我们希望在更广泛层面改进工作区和配置发现行为,这在#7871中跟踪。

其他更新

  • osiewicz#16264中加速了cargo clean -pcargo clean --workspace的执行。
  • 1.93 版本更新ranger-ross 添加了对构建脚本使用cargo::metadata而不需要package.links清单键的不稳定支持(#16436)。

未进展的重点领域

以下是 Cargo 团队关注但本开发周期未有可报告进展的领域。

需要负责人的项目目标:

准备开发:

规划中:

如何参与贡献

如果您有改进 Cargo 的想法,建议先查看我们的待办列表,然后在Internals 论坛上探讨。

如果您希望推动某个本文未提及的具体问题,可以采取以下步骤:

  • 总结现有讨论(例如: 改进 Docker 层缓存支持Cargo.lock 策略变更MSRV 感知解析器
  • 记录其他生态系统的先例,以便我们借鉴已有工作并创建用户熟悉的方案
  • 记录 Cargo 中相关问题和解决方案,确保我们在正确的抽象层面解决问题
  • 基于以上信息,提出考虑周全且符合 Cargo 兼容性要求的解决方案(示例

我们可以在Zulip上为S-accepted 议题提供指导,也可以在贡献者办公时间实时交流。如果您想参与本文提到的大型项目但刚入门,解决一些简单问题将帮助您熟悉流程和期望,使后续工作更顺利。如果您想处理没有导师的议题,则需要更多自主完成工作的能力。

版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)