Rust 1.52.1 已正式发布,及其新特性详述—重要,官方建议升级

2022-09-01 15:42:29 浏览数 (1)

2021 年 5 月 10 日,Felix Klock 和 Mark Rousskov 代表 Rust 编译器团队发布文章 Announcing Rust 1.52.1,官宣发布 Rust 1.52.1。

以下为官方公告原文——

Rust 团队新发布的 Rust 1.52.1,解决了一个增量编译中的 bug,这个 bug 在 1.52.0 中,会导致一个编译器错误。我们建议所有 Rust 用户(包括使用 1.52.0 及之前稳定版本的用户)升级到 1.52.1,或者也可以禁用增量编译。如下是升级指导。

如果你已通过 rustup 安装了 Rust 的早期版本,那么更新到 Rust 1.52.1 相当容易:

代码语言:javascript复制
rustup update stable

如果您还未安装过 Rust,可以从 Rust 官网页面获取 rustup

如果官方途径安装速度较慢,可以配置 Rust 工具链的国内源,请参阅《配置 Rust 工具链的国内源》。

概要说明

此次发布,是针对 1.52.0 版本上的问题构建的,这些问题因新添加的验测而起。此次验测工作检测到的 bug,存在于 Rust 1.24 之后的版本中(因为增量编译是自 Rust 1.24 启用)。并且可能触发增量构建中的错误编译,因此降级到以前的稳定版本,并非解决方案。

因此,建议所有用户升级到 1.52.1,或在本地环境中禁用增量(如果使用 1.52.0 及之前版本):有关如何禁用增量的详细信息,请参阅小节:Rust 程序员该做的事情。

增量编译,在缺省情况下是关闭的,因此很少有生产环境的构建会受到影响(仅对选择启用的用户有影响)。

增量编译中的错误,可能会导致错误的编译!从而在最终的工件中,生成不正确的代码,既是会生成格式错误的二进制文件。这意味着,理论上,任何行为都是可能的。在实践中,我们目前只发现了一个特定的已知错误,但由于增量错误是出了名的难以追踪:如果用户从二进制文件中看到意外的结果,他们通常会在进行轻度重构后重新构建。这时,通常会进行充分的重新编译,可以修复错误。

本篇文章的目的是:

  1. 解释错误的具体表征;
  2. 在高层次上,解释检查(check)的作用;
  3. 解释 Rust 1.52.0 中,检查的具体展现;
  4. 在你的项目上,如果出现不稳定(unstable)的编译器指纹,告诉你如何做;
  5. 关于此问题,描述 Rust 团队的解决计划。

错误的具体表征?

错误消息是类似于这样的展现,关键部分文本是:“found unstable fingerprints”。

代码语言:javascript复制
thread 'rustc' panicked at 'assertion failed: `(left == right)`
  left: `Some(Fingerprint(4565771098143344972, 7869445775526300234))`,
  right: `Some(Fingerprint(14934403843752251060, 623484215826468126))`: found unstable fingerprints for <massive text describing rustc internals elided>

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

这是内部一致性检查导致的错误,如诊断中所述,它会产生“内部编译器错误”,也称作 ICE。换句话说,它代表了 Rust 编译器内部的一个 bug。具体在本例中,既是 ICE 揭示了关于增量编译的一个 bug。在早于 1.52.0 的版本中,或许没有捕获到它,但可能会导致错误编译。

什么是编译器指纹(fingerprints),为什么我们要对其检查?

Rust 编译器支持“增量编译”,在 2016 年的博客文章中,对有描述。当增量式编译开启时,编译器会将输入源分割成多个片段,并追踪这些输入片段如何影响最终的构建产品。然后,当输入发生变化时,它会检测到这一点并重用以前构建的工件,努力让构建需要的响应输入,仅在源代码发生变化的部分上花费精力。

编译器指纹(fingerprints)是我们体系结构的一部分,用来检测输入变化。更具体地说,编译器指纹(fingerprints,以及建立上下文的一些其它状态)是一个 128 位的值,用于唯一标识编译器中使用的内部值。某些编译器内部结果,在运行时缓存(cached)在磁盘上。编译器指纹(fingerprints)用于验证新计算的结果,是否与缓存的结果相同(有关这方面的详细信息,请参阅《rustc 开发指南》的相关章节)。

编译器指纹(fingerprints)的稳定性检查,是维护编译器指纹(fingerprints)内部一致性的保障措施。有时,编译器被迫重新运行检查,并期望输出与以前会话的增量编译输出相同。新启用的验证,将检查该值是否确实如预期的那样,而不是假设是这样。但在某些情况下,由于编译器实现中的错误,实际情况并非如此。

历史回溯

我们将编译器指纹(fingerprints)检查作为 rustc 开发工具的最初时间,是在 2017 年。它是作为一个不稳定的(unstable)标志 -Z 提供的,只对 nightly 版和开发版的构建可用。

最近,在 3 月份,我们遇到了一个错误编译,导致我们在默认情况下打开了 verify-ich。Rust 编译器团队认为:最好是捕获编译器指纹(fingerprints)问题并中止编译,而不是允许潜在的错误编译(以及随后的错误行为),以防止错误潜入二进制文件中。

当我们第一次默认开启编译器指纹(fingerprints)检查时,nightly 和 beta 版工具链的用户,会不断提交问题(issues),并且在修复方面也取得了稳步进展。其中一些已经解决。

上周,我们已经开始编制改善用户体验的计划,这样检查发出的诊断就可以更好地告诉程序员应该做什么。不幸的是,这样做的前提是:新的验证本将在 1.53 中发布,而非 1.52。

但最近发布的版本 Rust 1.52.0(请参阅 Rust 1.52.0 已正式发布,及其新特性详述),启用了 verify-ich

今天的新版本 Rust 1.52.1,解决了因新添加的验证而导致的问题。此版本中,临时将 Rust 编译器中的默认值更改为禁用增量编译,除非用户有意选择启用。

为什么会出现此问题?

从本质上讲,对于某些 crate,特定的编辑-编译(edit-compile)周期序列,将导致 rustc 遇到“不稳定指纹(unstable fingerprints)”的内部编译错误(ICE)。如文章开头展示的例子所示。

我们再来看看另一个例子的编译错误:

代码语言:javascript复制
thread 'rustc' panicked at 'found unstable fingerprints for predicates_of(<massive text describing rustc internals elided>)', /rustc/.../compiler/rustc_query_system/src/query/plumbing.rs:593:5

它们具有相同原因,将存储在磁盘上的增量编译缓存与当前 rustc 调用期间计算的值进行比较时,出现了不一致情况。这意味着,它们都是由于使用增量编译造成的。

如下方法可以开启增量编译:

  1. 使用默认启用增量编译的 devtest 配置文件进行构建。
  2. 设置环境变量 CARGO_INCREMENTAL=1
  3. 设置 Cargo config 文件,启用 build.incremental
  4. 设置 Cargo.toml,启用 incremental

如果项目中没有调整默认值,那么当运行 cargo build --release 时,或在 release 配置文件中,所有 Rust 1.x 都将禁用增量编译。这些问题,不应该影响你的版本发布。

Rust 程序员该做的事情

如果你发生内部编译器错误,请你报告此 bug。我们仍然需要该方面的信息,想知道失败的案例。

但是,无论你是否提交 bug,你都可以通过以下方式解决问题:

  1. 升级到 1.52.1,将会为你禁用增量编译。或者
  2. 删除增量编译缓存(例如,运行 cargo clean),或者
  3. 通过在环境变量中设置 CARGO_INCREMENTAL=0,或在 config.toml 中指定 build.incrementalfalse,强制禁用增量编译。

我们推荐用户都将 1.52.0 升级为 to 1.52.1,这样做即可禁用增量编译。

我们不建议 Rust 1.52.0 的用户,为了应对这个问题而降级到 Rust 的早期版本。如上所述,至少有一个实例,由于增量编译导致了错误编译。在我们添加编译器指纹(fingerprints)检查之前,错误未被捕获。

Rust 1.52.1 的用户,如果希望自行处理增量验证的 ICE(译注:内部编译错误)问题,并希望选择返回版本 1.52.0。则可以在环境变量中,设置 RUSTC_FORCE_INCREMENTAL=1。如此,Rust 编译器将执行 Cargo 传递的选项 -Cincremental,尽管添加了验证,但仍将以前版本一样工作。请注意,Rust 1.52.1 中,如果此标志尚未单独启用(无论是通过 Cargo 还是其它方式),则不会启用增量。

如果你当前正在使用 1.52.0 之前的工具链,并且希望继续这样做,我们建议你禁用增量编译,以避免出现无提示的错误编译。

自从增量编译启用以来,在所有的 Rust 构建中,编译时间对许多用户来说,都是一个重大的改进,而且会随着时间的推移而逐步改进。我们承认,这里提出的解决办法和建议,多用户来说是痛苦的,我们将努力保证这只是暂时的解决方案。

Rust 团队如何解决此问题?

译注:计划方面,和上文多有重复,即是配置环境变量和设置指定文件的反复。所以未再详细翻译,所有翻译开源在 github.com/zzy/blog.rust-lang.org-zh-cn,欢迎你补充和完善。

短期计划

既是我们发布了此 1.52.1 版本。

长期计划

修复错误。

谢谢您的阅读,欢迎交流。

0 人点赞