总结:rustc 将在 x86_64-unknown-linux-gnu
平台上的 nightly 版本默认使用 rust-lld
,以显著减少链接时间。
背景介绍
链接时间通常是编译时间的重要组成部分。当 rustc 需要构建二进制文件或共享库时,它通常会调用系统上安装的默认链接器来完成此操作(这可以在命令行上或通过编译代码的目标进行更改)。
链接器承担着重要的工作,需要考虑稳定性、向后兼容性等等。由于这些及其他原因,在最流行的操作系统上,它们通常是较旧的程序,设计于计算机只有单核的时代。因此,它们在现代机器上往往速度较慢。例如,在 Linux 上以调试模式构建 ripgrep 13 时,大约一半的时间实际上花费在链接器上。
然而,存在不同的链接器,通常改善链接时间的建议是使用这些更新、更快的链接器之一,例如 LLVM 的 lld
或 Rui Ueyama 的 mold
。
Rust 的一些 wasm 和 aarch64 目标已经默认使用 lld
。使用 rustup 时,rustc 会附带一个版本的 lld
用于此目的。当 CI 构建用于编译器的 LLVM 时,它也会构建并打包该链接器。为了避免与用户机器上已安装的任何 lld
冲突,它被称为 rust-lld
。
由于链接时间的改进非常显著,因此在最流行的目标中将其设为默认值会很有益处。这已经被讨论了很长时间,例如在问题 #39915 和 #71515 中,并且 rustc 已经提供了 nightly 标志来使用 rust-lld
。
到目前为止,我们相信已经在 CI、crater 和我们的基准测试基础设施上完成了所有可能的内部测试。我们现在希望扩大测试范围并收集实际使用反馈和用例。因此,我们将为 x86_64-unknown-linux-gnu
平台的 nightly 构建启用 rust-lld
作为默认使用的链接器。
优势
虽然这也使得编译器未来可以使用更多的链接器特性,但最直接的好处是链接时间的极大改善。
以下是上述 ripgrep 示例的更多详细信息:链接时间缩短了 7 倍,使端到端编译时间减少了 40%。
大多数二进制文件应该会看到一些改进,但对于更大的二进制文件或涉及调试信息的情况,改进尤其显著。这些情况通常在链接器中遇到瓶颈。
这是我们基准测试完整结果的链接。
如果测试进展顺利,我们就可以为 x86_64-unknown-linux-gnu
用户默认稳定使用这个更快的链接器,之后可能会考虑其他目标。
可能的缺点
根据我们之前的测试,我们并不期望在实践中发生问题。对于绝大多数情况,它都是即插即用的替代品,但 lld
与 GNU ld 并非 bug-for-bug 兼容。
无论如何,如果发生任何问题,可以禁用使用 rust-lld
:使用 -Z linker-features=-lld
标志可以回退到使用系统的默认链接器。
某些依赖于这些差异的 crate 可能需要额外的链接参数。例如,我们在 crater 运行中看到不到 20 个 crate 由于 封装符号 的默认设置不同而导致链接失败:这些可能需要 -Clink-arg=-Wl,-z,nostart-stop-gc
来匹配传统的 GNU ld 行为。
部分性能上的显著提升来自于并行处理,这在资源受限的环境中可能不理想。
总结
从明天的 rustup nightly (nightly-2024-05-18
) 开始,rustc 将在 x86_64-unknown-linux-gnu
nightly 版本上使用 rust-lld
,以大幅提高链接速度。如果您遇到问题,请通过在 GitHub 上开启一个议题告知我们。
如果发生这种情况,您可以使用 -Z linker-features=-lld
标志回退到默认链接器。可以通过将其添加到常用的 RUSTFLAGS
环境变量中,或者添加到项目的 .cargo/config.toml
配置文件中,如下所示:
[]
= ["-Zlinker-features=-lld"]