Cargo 与自定义链接器:mold 和 lld 能让链接阶段快多少的实测数据

📅 2026/7/18 23:41:49 👁️ 阅读次数 📝 编程学习
Cargo 与自定义链接器:mold 和 lld 能让链接阶段快多少的实测数据

Cargo 与自定义链接器:mold 和 lld 能让链接阶段快多少的实测数据

专栏: 技术 / Cargo / 编译优化


一、链接:编译管线中最被忽视的性能黑洞

cargo build最慢的不是编译,是链接。我是在一个 100+ crate 的中型项目里意识到这一点的:Rust 编译器完成所有 crate 的代码生成只花了 25 秒,而链接器又额外花了18 秒——占了近一半的总时间。

默认的 GNUld链接器是单线程的,在链接 Rust 大型二进制(动辄几十甚至上百 MB 的 debug 二进制)时,它是整个编译管线中最慢的一环。

flowchart LR subgraph Pipeline["Rust 编译管线时间分布(中型项目实测)"] P1["rustc 编译<br/>~25s"] --> P2{"链接器"} P2 -->|"GNU ld(默认)"| L1["~18s ⚠️"] P2 -->|"gold"| L2["~8s"] P2 -->|"lld"| L3["~4s ✅"] P2 -->|"mold"| L4["~1.5s 🚀"] end L1 --> Total1["总计 ~43s"] L2 --> Total2["总计 ~33s"] L3 --> Total3["总计 ~29s"] L4 --> Total4["总计 ~26.5s"] style L1 fill:#F44336,color:#fff style L2 fill:#FF9800,color:#fff style L3 fill:#4CAF50,color:#fff style L4 fill:#2196F3,color:#fff

mold 的作者 Rui Ueyama 说了一句大实话:"链接器的速度瓶颈 90% 是算法问题,不是硬件问题。"这就是为什么 mold 能把链接阶段从 18 秒砍到 1.5 秒。


二、mold:Rust 项目的最佳链接搭档

mold 是目前最快的链接器,它的核心设计哲学是"能用哈希表的地方绝不用排序"。在 Rust 项目中使用 mold 非常简单:

# 第一步:安装 mold 链接器(macOS/Linux 通用) # macOS brew install mold # Ubuntu/Debian sudo apt install mold # 第二步:配置 Cargo 使用 mold # 方法 1:在 .cargo/config.toml 中全局配置
# .cargo/config.toml — 全局配置 mold 作为 Rust 链接器 [target.x86_64-unknown-linux-gnu] # mold 作为首选链接器,速度最快 rustflags = ["-C", "link-arg=-fuse-ld=mold"] [target.x86_64-apple-darwin] # macOS 上 mold 目前需要配合 clang 前端使用 rustflags = ["-C", "link-arg=-fuse-ld=mold"] # 备选:lld 跨平台稳定方案 [target.x86_64-unknown-linux-gnu] # rustflags = ["-C", "link-arg=-fuse-ld=lld"]

做完配置后,用cargo clean && cargo build --release就能立即感受到差距。


三、实测对比:四种链接器的全维度 benchmark

我在三个不同规模的项目上做了系统测试,结果如下:

测试环境:AMD Ryzen 7 5800X(8 核 16 线程)、32GB DDR4、NVMe SSD、Ubuntu 22.04

项目规模链接器链接耗时二进制体积峰值内存
小型(15 crates, ~5 万行)GNU ld3.2s18MB450MB
小型gold1.5s17.8MB380MB
小型lld0.8s17.9MB320MB
小型mold0.3s18.1MB280MB
中型(120 crates, ~30 万行)GNU ld18.1s95MB2.1GB
中型gold8.3s94MB1.7GB
中型lld4.1s94.5MB1.2GB
中型mold1.5s95.5MB0.9GB
大型(400+ crates, ~100 万行)GNU ld76s310MB6.8GB
大型gold38s305MB5.2GB
大型lld16s308MB3.8GB
大型mold5.1s312MB2.6GB
xychart-beta title "链接耗时对比(秒)— 越低越好" x-axis ["小型项目", "中型项目", "大型项目"] y-axis "链接耗时(秒)" 0 --> 80 bar [3.2, 18.1, 76] bar [1.5, 8.3, 38] bar [0.8, 4.1, 16] bar [0.3, 1.5, 5.1]

几个值得注意的发现:

  1. mold 在大型项目上的优势最明显——比 GNU ld 快了约15 倍
  2. lld 是一个非常优秀的折中选择——速度快、跨平台、稳定,而且是 LLVM 官方项目。
  3. 所有链接器产出的二进制体积几乎一致(差异 < 2%),不存在"快链接=大体积"的 trade-off。
  4. mold 的内存效率也是最好的,在大项目上峰值内存只有 GNU ld 的 40%。

生产实战经验:mold 的两个真实坑

我在生产环境里遇到过 mold 1.x 早期版本的两个问题,都是靠用户报错才发现。

第一个坑是debug info 损坏。mold 1.2.0 及以下版本在链接具有大量泛型实例化的 Rust 代码时,.debug_info段会产生不正确的 DWARF 条目。表现形式是:程序 crash 后 backtrace 里的函数名全是??addr2line也无法解析地址。升级到 mold 1.3.0 后问题解决。

# 检查当前 mold 版本 mold --version # 如果输出 "mold 1.2.0" 或更早,建议升级到 2.x # 验证二进制的 debug info 是否正常 # 正常情况下应该能看到函数名,而不是全 ??? objdump -Wi ./target/release/my-app 2>/dev/null | grep "DW_TAG_compile_unit" | head -5

第二个坑是glibc 版本兼容性。mold 默认生成的二进制在.dynamic段里要求的GLIBC_版本比较高(2.32+),在 CentOS 7(glibc 2.17)上运行时会报symbol lookup error: version 'GLIBC_2.32' not found。解决办法是在和部署目标相同版本的系统里编译,或者用 Docker 多阶段构建:

# 在 CentOS 7 兼容的环境里编译 FROM centos:7 AS builder RUN yum install -y epel-release && yum install -y mold # ... 编译步骤 ...

这两个坑的共性是:mold 发展很快,版本之间差异大,生产环境用最新稳定版,但别用刚发布的版本。我现在固定用 mold 2.0.0,不追新。


四、实战:在 CI 中自动化使用自定义链接器

CI 流水线里的链接时间是实打实的成本。部署 mold 到 CI 只需要几行:

# .github/workflows/ci.yml — CI 中使用 mold 加速链接 name: CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 安装 mold 链接器 run: | # mold 安装极快,几秒完成 sudo apt-get update sudo apt-get install -y mold - name: 安装 Rust uses: dtolnay/rust-toolchain@stable - name: 编译 & 测试 run: | # 通过环境变量指定链接器(优先级高于 config.toml) RUSTFLAGS="-C link-arg=-fuse-ld=mold" cargo test --release RUSTFLAGS="-C link-arg=-fuse-ld=mold" cargo build --release - name: 验证链接方式 run: | # 确认二进制确实使用了 mold 链接 readelf -p .comment target/release/my-app | grep mold

这套配置的 ROI 简单计算:如果每个 CI run 中有 5 个不同的cargo build/cargo test命令,使用 mold 后:

  • 中型项目:从 90s → 25s,每次 CI 节省 65 秒
  • 每天 20 次 CI:节省约 22 分钟的等待时间

对于付费 CI 按分钟计费的团队,一个月下来能省不少钱。

CI 里安装 mold 的三种方式对比

mold不是所有 CI 环境的默认工具链组件,需要自己安装。我在 GitHub Actions 里试过三种安装方式,耗时差异很大:

安装方式耗时可靠性适用场景
sudo apt-get install mold10-30s(Ubuntu 22.04 默认源没有,需加 PPA)Ubuntu 22.04+
从源码编译 mold120-180s高,但太慢需要最新功能或特定平台
下载官方预编译二进制3-5sCI 推荐方式

我现在的做法是直接下载官方预编译二进制,整个安装步骤 5 秒内完成:

- name: 安装 mold 链接器(预编译二进制,5 秒完成) run: | # 直接下载官方预编译二进制,不需要 apt-get 或编译 curl -L https://github.com/rui314/mold/releases/download/v2.0.0/mold-2.0.0-x86_64-linux.tar.gz \ | tar xz -C /tmp/ echo "/tmp/mold-2.0.0-x86_64-linux/bin" >> $GITHUB_PATH

mold 不会加快cargo test里的编译速度,只会加快链接速度。如果你的项目是测试密集型的(每次 CI 跑几千个单元测试),链接时间优化对总体 CI 时间的贡献可能不到 10%。mold 的 ROI 最高的场景是那些cargo build --release产物很大、且频繁做全量编译的项目。

另一个实战技巧:把 mold 二进制本身也缓存起来。GitHub Actions 的actions/cache可以缓存/tmp/mold-2.0.0-x86_64-linux目录,这样第二次 CI run 连下载都不需要:

- name: 缓存 mold 二进制 uses: actions/cache@v4 with: path: /tmp/mold-2.0.0-x86_64-linux key: mold-2.0.0

五、总结

换个链接器是提升 Rust 编译体验最高性价比的优化——不需要改代码,不需要重构项目,一行配置就能见效。

核心建议:

场景推荐链接器理由
日常开发mold速度第一,体感提升巨大
CI/CD 流水线mold省钱省时间
macOS 项目lldmold 在 macOS 上支持不完善
跨平台交叉编译lldLLVM 生态,兼容性最好
需要最高稳定性lld出货量大,久经考验

一句话总结:如果今天你只能做一件事来加速 Rust 编译,把默认链接器换成 mold 是回报名最明确的选择。