Cargo 的开发周期:1.85

2025 年 1 月 17 日 · Ed Page 代表 Cargo 团队

Cargo 的开发周期:1.85

这是过去 6 周左右 Cargo 开发进展的总结,大约是 Rust 1.85 的合并窗口期。

本周期的插件

Cargo 不可能满足所有人的需求,仅仅是因为它必须维护兼容性保证。插件在 Cargo 生态系统中扮演着重要的角色,我们希望对此表示赞赏。

我们本周期的选择是 clippy-sarif。虽然不是插件,但它包装了 cargo clippy,将 lint 输出转换为 静态分析结果交换格式 (SARIF),GitHub 可以使用它在 PR 审查中发布关于 lints 的评论,使其比读取日志文件更容易访问。

感谢 epage 的建议!

请提交您对下一篇文章的建议。

实现

Rustflags 和缓存

来自 1.84 的更新

回顾一下,Cargo 在 RUSTFLAGS 更改时会丢弃缓存,而不是在缓存中创建单独的条目。问题在于 RUSTFLAGS 对 Cargo 是不透明的,不同的标志有不同的缓存需求。剩下的问题是 --remap-path-prefix,它用于使两个不同的构建看起来相同。该标志的参数对于每个构建都是唯一的,并且缓存键最终会出现在最终的二进制文件中,从而阻止 --remap-path-prefix 发挥其作用。

我们在 Cargo 团队会议上讨论了这个问题。一旦我们通过 trim-paths 内置了对 --remap-path-prefix 的支持,我们就可以直接引导人们使用它。然而,trim-paths 存在未解决的问题,并且尚不清楚它需要多长时间才能可用。我们也可以回到之前尝试的修复方案,并解析 RUSTFLAGS(参见 #6966),但我们对此感到不安,因为命令行解析是上下文相关的。我们最终采取了一种折衷方案,即应用粗略的启发式方法,如果某些东西看起来像 --remap-path-prefix,我们就不在缓存键中包含 RUSTFLAGS

这已在 #14830 中合并。

在任务栏中报告进度

此前,Gordon01 选择了研究 ConEmu 的 OSC 9;4,这是一个 ANSI 转义代码,他们定义用于通过 Windows 任务栏图标报告进度 (#14615)。对报告此内容的支持已扩展到 systemd 等应用程序 (systemd#34929),而对报告此内容的支持也已扩展到 Ptyxis 等终端。

在 FCP 启动后,团队简要讨论了是否需要将其添加到 .cargo/config.toml 中。我们之前为其他终端功能添加了配置控制,例如 unicode 和超链接。我们没有完全开启这些功能,因为并非所有终端都能优雅地降级处理它们的存在。特别是对于任务栏转义代码,Kitty 使用 OSC 9 创建了自己的功能,导致 OSC 9;4 的体验不佳 (kitty#8011)。这为用户提供了一种测试该功能的方法,以防他们的终端不在我们的允许列表中,或者在他们不喜欢结果时将其关闭。

然后,讨论转向 #14615,特别关注于配置字段的命名。目前,建议将该字段放在 term.progress 表中。由于这些是事实上的标准,因此该功能没有正式定义的名称。我们可以根据转义代码 (term.progress.osc9_4)、原始意图 (term.progress.taskbar)、进度报告方式(例如 term.progress.ansi)或无数选项之一来命名它。

理想情况下,配置字段应该是

  • 希望更改此行为的人容易发现
  • 查看配置或配置文档时含义明确
  • 与更广泛的社区保持一致

目前,我们尚未就名称达成共识。

cargo publish 脏检查性能

当运行 cargo packagecargo publish 时,Cargo 会将 git 提交哈希和仓库中的路径记录到 .crate 文件中的一个文件中。如果使用了 --allow-dirty,则会跳过此操作,但在 Cargo 1.81 中进行了更改,以帮助审核已发布的软件包 (#13960)。

landonxjames 报告说,此更改导致发布 aws-sdk-rust 仓库 时性能显着下降。Cargo 从使用 --allow-dirty 跳过其脏文件检查变为始终运行它。该检查尚未针对一次发布 400 多个软件包进行优化。例如,Cargo 检查仓库中的任何文件是否是脏的。weihanglo#14962 中将此检查的范围缩小到仅限软件包目录,但我们推迟了该更改,因为这引起了人们对脏检查缺陷的关注 (#14967),并且我们担心修复这些问题会与性能改进相冲突。

weihanglo 着手通过修复 #14962 中的几个问题来测试该理论,特别是对于 Cargo 复制到软件包根目录的文件(#14981, #14966)。他们尝试在 #14985 中进一步优化,但似乎不值得增加复杂性。

采用上述方法后,路径过滤不再是问题,因此我们在 #14997 中继续推进。

我们正在等待回复,以了解是否需要更多工作来优化此操作。

面向未来的 Index

在讨论 Cargo 的新功能时,Index 的更改就会出现。Index 是注册表中每个软件包版本的基本元数据(称为摘要)的集合,允许依赖项解析,而无需下载 .crate 文件并解析 Cargo.toml。对摘要的纯粹添加性更改是可以的,例如添加 package.rust-version。我们可以扩展现有字段或更改它们的解释,但对于旧版本的 Cargo 来说,体验并不理想。

早在 Cargo 1.60 发布时,旧版本 Cargo 的用户就开始看到如下错误

error: failed to select a version for the requirement `libgit2-sys = "^0.13.3"`
candidate versions found which didn't match: 0.13.2+1.4.2, 0.13.1+1.4.2, 0.13.0+1.4.1, ...
location searched: crates.io index
required by package `git2 v0.14.3`
    ... which satisfies dependency `git2 = "^0.14"` (locked to 0.14.3) of package `repor v0.1.0 (/home/epage/src/personal/repro)`

当您访问 crates.io 时,版本 0.13.3 存在。问题是 0.13.3 使用了新的 弱依赖功能语法 (dep?/feature),而旧版本 Cargo 不理解。此错误消息对于弱依赖功能和摘要架构的任何未来扩展来说,用户体验都很差。我们一直在 #10623 中跟踪此可用性问题。

epage 最近做了一些工作(#14897, #14921, #14923, #14927),以便 Cargo 可以从不受支持的摘要中提取尽可能多的信息,而不会通过缓存丢失此信息,并将其报告给用户。

以下输出显示了我们可能报告不受支持的摘要的三种不同方式,具体取决于我们拥有的上下文量

[UPDATING] `dummy-registry` index
[ERROR] failed to select a version for the requirement `foo = "^0.1.1"`
  version 0.1.3 requires cargo 1.2345
  version 0.1.4 requires a Cargo version that supports index version 1000000000
  version 0.1.5's index entry is invalid
location searched: `dummy-registry` index (which is replacing registry `crates-io`)
required by package `a v0.5.0 ([ROOT]/foo)`

我们现在也报告了被撤回的版本

[UPDATING] `dummy-registry` index
[ERROR] failed to select a version for the requirement `baz = "=0.0.2"`
  version 0.0.2 is yanked
location searched: `dummy-registry` index (which is replacing registry `crates-io`)
required by package `bar v0.0.1`
    ... which satisfies dependency `bar = "*"` of package `foo v0.0.1 ([ROOT]/foo)`

通过改进的错误报告,我们可以更自由地设计与 Index 相关的功能。

设计讨论

项目目标

已提出的 2025h1 Cargo 相关目标包括

cargo publish 的自动重试

ijackson#13530 中提出,当达到 crates.io 速率限制时,cargo 自动退避并重试。

我们主要有两个担忧:

这是否符合 crates.io 设置速率限制的意图?我们联系了他们,他们表示从技术角度来看可以接受。

这是我们想要的用户体验吗?重试时间相当长,用户可能会对 cargo publish 意外“挂起”几分钟感到不满,如果他们发布的是工作区,情况会更糟 (#1169)。如果用户决定使用 ctrl-c 取消工作区发布,他们可能会处于半发布状态。拥有一个 --idempotent 标志来跳过已发布的版本 (#13397) 可能会有所帮助。如果这是更大的发布过程的一部分,例如使用 cargo-release,那么故障恢复可能会很麻烦。在 cargo-release 的情况下,它会猜测操作是否会受到速率限制并阻止用户,要求他们覆盖它。我们没有研究取消基于 CI 的发布(例如使用 release-plz)会是什么样子。crates.io 可以提供一个 API 来查询速率限制,而不是让 cargo-release 猜测是否会达到速率限制,但是 crates.io 团队担心这可能会给他们进一步发展速率限制带来兼容性负担。

当 crates.io 回复他们的反馈时,他们确实提出了将 crate 版本速率限制从按用户范围调整为按 crate 范围的想法。这正在 crates.io#10396 中跟踪。

cargo publish 验证行为

在测试 cargo publish --workspace (#1169) 时,epage 意识到验证步骤正在运行 cargo build,而不是 cargo check。虽然这对于发布可能无关紧要,但在使用 --dry-run 标志迭代发布过程时,可能会产生巨大的影响。他们在 #14930 中建议更改此设置,但在经过一番来回讨论后,结果表明这可能更细致,讨论转移到 #14941

需要记住的是,cargo check 不能保证找到 cargo build 可能找到的每个编译器错误(参见 RFC #3477)。更具体地说,这些涵盖了后单态化错误,其中包括链接器错误。

我们在最近的 Cargo 团队会议上讨论了这个问题。已经有人要求验证支持是可配置的,以便它可以运行测试 (#14685)。如果 cargo 具有该功能,那么这只会成为默认值的问题。如果没有它,我们将把人们锁定在一个答案中,这对决策施加了更大的压力。但是,#14685 中有几个问题需要解决,如果我们以此为阻碍,可能会减慢此问题的解决速度。

我们需要回答的一个重要问题是,验证步骤的默认目的是什么

  • 软件包完整性检查(例如,是否包含所有需要的文件)
    • 如果您认为测试 .crate 文件很重要,那么运行测试是检查其完整性的唯一方法,因为它们可以依赖于数据文件,有关更多详细信息,请参见 #14685
    • 对于 -sys crates,可能会因为缺少文件而导致链接器错误
    • 仅检查一种功能组合或一种配置文件也可能掩盖缺少文件的问题
  • 最后的基线质量检查
    • 以防没有 CI
    • 以防在发布之前在本地进行了更改,特别是使用 --allow-dirty

如果它是最后的基线质量检查,那么鉴于 RFC #3477,运行 build 会增加额外的保证。然后问题就变成了,什么是正确的默认基线?

  • 快速的“大多数构建问题”检查
  • 当前:当前平台上 dev 配置文件的默认功能
  • 不同的功能组合?
  • 不同的平台组合?
  • 不同的配置文件组合?
  • Linting、测试、不安全代码检查或形式化证明

cargo checkcargo build 之间的差异是否相关取决于以下因素:

  • 我们对用户在发布前所做操作的一般假设 (cargo test? 运行所有 CI?)
  • 发布前遗漏上述步骤之一的可能性
  • 在该间隙中引入后单态化错误的可能性
  • 如果问题确实被忽略了,受影响用户的数量(更受欢迎的 crates 是否可能具有更严格的流程?)

rust-lang/rfcs#3477 最可怕的部分是,使用 cargo check 构建的 crate 不受 Rust 稳定性保证的约束,只有 cargo build 受约束。但是,只能检查而不能构建的 crate 几乎没有用处,也不太可能有人会依赖它。

我们决定在 Internals 上联系,以获得更多关于验证作用及其性能影响的反馈。

编纂构建脚本模式

受到我们对寻找 RUSTFLAGS 抽象的兴趣(#12739)的启发,epage 开始在 #14948 中跟踪 build.rs 的使用情况,以便我们可以探索 Rust 和 Cargo 中需要填补的空白是什么

如果没有任何其他方法,我们可以使用 metabuild 进行自定义声明式构建脚本。为了简化设计并与其他功能保持一致,epage 发布了一个反提案,该提案建立在 工件依赖项 之上。与当前设计相比,这避免了构建脚本二进制文件的重复构建和链接,并允许更精细地跟踪何时重新运行它们。这甚至可能允许构建脚本的运行以功能为条件。joshtriplett 建议整合将数据传递给构建脚本的方式,epage 对此表示赞同。尚不清楚的是,数据应该是低级别的(字面环境变量)还是抽象的(转换为环境变量的某些配置)。

其他

没有进展的重点领域

这些是 Cargo 团队成员感兴趣的领域,在本开发周期中没有可报告的进展。

准备开发

需要设计和/或实验

计划中

您如何提供帮助

如果您对改进 cargo 有任何想法,我们建议首先查看 我们的积压工作,然后在 Internals 上探索该想法。

如果此处未讨论您想要解决的特定问题,您可以采取一些步骤来帮助推动其进展,包括

  • 总结现有的对话(示例:更好地支持 docker 层缓存Cargo.lock 策略的更改MSRV 感知解析器
  • 记录来自其他生态系统的现有技术,以便我们可以借鉴他人所做的工作,并在有意义的地方制作一些用户熟悉的东西
  • 记录 Cargo 中相关的问题和解决方案,以便我们了解我们是否正在解决正确的抽象层
  • 在这些帖子基础上,提出一个考虑到上述信息和 cargo 兼容性要求的解决方案(示例

我们可以在 zulip 上为 S-accepted issues 提供指导,您可以在 贡献者办公时间 与我们实时交谈。如果您希望帮助完成此处提到的一些更大的项目并且刚刚开始,修复一些问题 将有助于您熟悉流程和期望,使事情进展更顺利。如果您想在 没有导师的情况下 解决问题,那么对您需要独自完成的工作的期望会更高。