其他
Rust 项目编译过慢时定位瓶颈并加速构建
适用于 Rust/Cargo 项目编译时间过长,需要定位瓶颈并通过缓存、代码生成后端、并行化、LTO 与链接器配置加速构建的场景。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
Rust 项目编译过慢时定位瓶颈并加速构特定
解决思路
- 用 `cargo build --timings` 生成构建计时报告。
- 打开 `build/cargo-timings/cargo-timing.html` 查看 crate 编译时间线、并行度与瓶颈。
- 对 release 构建使用 `cargo build --release --timings`。
- 在计时报告中重点查找:长串行链(没有并行)。
- 在计时报告中重点查找:单个 crate 编译超过 10s(可作为优化候选)。
- 在计时报告中重点查找:proc-macro crate 阻塞下游所有编译。
- 安装 `cargo-llvm-lines`:`cargo install cargo-llvm-lines`。
- 运行 `cargo llvm-lines --release | head -20` 查看生成最多 LLVM IR 的函数(模板膨胀)。
- 安装 sccache:`cargo install sccache` 或 `brew install sccache`。
- 配置 Rust 构建使用 sccache:`export RUSTC_WRAPPER=sccache`。
- 在项目或全局 `.cargo/config.toml` 中添加 `[build] rustc-wrapper = "sccache"`。
- 用 `sccache --show-stats` 查看缓存统计。
- 为 CI 团队配置 S3 后端:`export SCCACHE_BUCKET=my-rust-cache`、`export SCCACHE_REGION=us-east-1`、`export AWS_ACCESS_KEY_ID=xxx`、`export AWS_SECRET_ACCESS_KEY=yyy`,然后 `sccache --start-server`。
- 在 GitHub Actions 中使用 sccache:`- uses: mozilla-actions/sccache-action@v0.0.4`。
- 安装 nightly(Cranelift 目前需要 nightly):`rustup toolchain install nightly`。
- 添加 Cranelift 组件:`rustup component add rustc-codegen-cranelift-preview --toolchain nightly`。
- 在 `.cargo/config.toml` 中启用 unstable codegen backend:`[unstable] codegen-backend = true`。
- 在 dev profile 使用 Cranelift:`[profile.dev] codegen-backend = "cranelift"`。
- 单次构建使用 Cranelift:`CARGO_PROFILE_DEV_CODEGEN_BACKEND=cranelift RUSTFLAGS="-Zunstable-options" cargo +nightly build`。
- 权衡:dev 构建用 Cranelift 可快 20–40%。
- 权衡:LLVM 编译出的代码运行时性能更快(Cranelift 跳过许多优化)。
- 权衡:release 构建始终使用 LLVM。
- 将单个大 crate 拆分为更小 crate 以启用 Cargo 并行编译;单个巨型 crate 是串行编译。
- 使用 workspace 成员示例:`core`、`networking`、`ui`、`server`、`cli`,其中 networking 与 ui 无相互依赖可并行,server 依赖 core+networking,cli 依赖 core+ui。
- 用 `cargo tree | head -30` 可视化依赖图。
- 用 `cargo tree --graph | dot -Tsvg > deps.svg` 生成可视化依赖图。
- 用 `cargo build -j$(nproc) --timings` 检查有多少 crate 可并行编译并最大化并行度。
- 有效拆分 workspace 的规则:先打破循环依赖。
- 有效拆分 workspace 的规则:把 proc-macro 拆到独立 crate(它们会阻塞一切)。
- 有效拆分 workspace 的规则:把频繁变更的代码隔离(减少失效范围)。
- release profile 使用 thin LTO:`[profile.release] lto = "thin"`。
- release profile 设置 `codegen-units = 1` 以获得最佳优化(但禁用并行)。
- 定义 release-fast profile:`[profile.release-fast] inherits = "release"` 和 `lto = "fat"`。
- dev profile 禁用 LTO:`[profile.dev] lto = "off"`(编译速度)。
- dev profile 设置 `codegen-units = 16` 最大化并行 codegen。
- LTO 对比:`lto = false` 链接快、运行时基线,用于 dev builds。
- LTO 对比:`lto = "thin"` 链接中等、运行时 +5–15%,用于大多数 release builds。
- LTO 对比:`lto = "fat"` 链接慢、运行时 +15–30%,用于最大性能。
- LTO 对比:`codegen-units = 1` 链接最慢、优化最好,与 LTO 一起用于 release。
- 安装 mold:`sudo apt-get install mold`。
- 在 `.cargo/config.toml` 配置 Linux x86_64 使用 mold:`[target.x86_64-unknown-linux-gnu] linker = "clang"` 和 `rustflags = ["-C", "link-arg=-fuse-ld=mold"]`。
- 使用 cargo-zigbuild 作为链接器:`cargo install cargo-zigbuild`。
- 使用 cargo-zigbuild 构建:`cargo zigbuild --release`。
- 配置 lld(比 GNU ld 快,且到处可用):`[target.x86_64-unknown-linux-gnu] rustflags = ["-C", "link-arg=-fuse-ld=lld"]`。
- macOS 使用 zld 或默认 lld:`[target.x86_64-apple-darwin] rustflags = ["-C", "link-arg=-fuse-ld=/usr/local/bin/zld"]`。
- 链接器速度对比:GNU ld 为基线。
- 链接器速度对比:lld 约快 2 倍。
- 链接器速度对比:mold 约快 5–10 倍。
- 链接器速度对比:gold 约快 1.5 倍。
- 减少调试信息级别:`[profile.dev] debug = 1`;`0=off, 1=line tables, 2=full(default)`。
- `debug=1` 可节省 20–40% debug 构建时间。
- 拆分调试信息以减少链接器输入:`[profile.dev] split-debuginfo = "unpacked"`;macOS 等价于 `gsplit-dwarf`。
- 禁用增量编译:`CARGO_INCREMENTAL=0 cargo build`(有时完整重建更快)。
- 减少 proc-macro 编译时间:固定重型 proc-macro 依赖版本。
- 重型 proc-macros:`serde`、`tokio`、`axum`,保持版本稳定。
适用边界 · 注意事项
- 非 Rust/Cargo 项目不适用;Cranelift 目前需要 nightly,无法使用 nightly 时不能采用该配置。
- 需要完整可调试信息时不要降低 debug 级别或拆分 debug info;需要最大运行时性能且无法接受长链接时间时不要使用 fat LTO 或 codegen-units=1。
- 项目很小、编译时间不是瓶颈,或团队无法维护额外工具/CI 缓存时,引入 sccache、mold、拆分 workspace 等可能得不偿失。