首页 / Rust 入门教程 / cargo 进阶:发布配置

Rust 入门教程

cargo 进阶:发布配置

本教程共 78 篇 · 第 55 篇 · 更新于 2026-08-08 · 约 10 分钟阅读

RustRust 入门教程Cargoprofile发布配置opt-levelltorelease

本节目标:理解 Cargo 的 profile(发布配置)机制,知道 dev/release/test/bench 四种默认配置分别用在哪,并学会在 Cargo.toml 里调优编译选项、自定义 profile、给指定依赖单独覆盖配置。

你大概已经发现,cargo buildcargo build --release 编出来的程序跑起来速度差很多。背后的开关就是 profile,中文常叫”发布配置”。它决定编译器用多大力气优化代码、做不做溢出检查等。

1-1 四种默认 profile

Profile 是 Cargo 用来区分”为哪种环境构建”的一组配置。内置四种,一般不用手动指定,Cargo 按你敲的命令自动选:

  • devcargo buildcargo runcargo check 用这个,结果落在 target/debug
  • testcargo test 用这个,结果也在 target/debug
  • benchcargo bench 用这个。
  • releasecargo build --releasecargo run --releasecargo install 用这个,结果落在 target/release

dev 的目标是编译快,所以优化级别最低,换来的是编译飞速、改一行秒编。 release 的目标是运行快,优化拉满,代价是编译慢、吃 CPU。

Warning

初学者最常踩的坑:用 cargo run 跑性能测试。这跑的是 dev 配置,几乎没优化,测出来的数字毫无意义。要测性能必须用 cargo run --release

1-2 在 Cargo.toml 里改配置

每种 profile 都能单独调。写在 Cargo.toml[profile.名称] 段落下。比如给 dev 稍微提一点优化、关掉整数溢出检查:

[profile.dev]
opt-level = 1
overflow-checks = false

如果项目是工作空间(workspace),只有根 Cargo.toml 里的 [profile.*] 生效,成员包里的配置会被自动忽略。另外,通过 .cargo/config.toml 或环境变量设的 profile 会覆盖项目 Cargo.toml 里的。

1-3 常见可调选项

opt-level 控制优化强度,数值越大跑得越快、编得越慢:

  • 0:不优化
  • 1:基础优化
  • 2:更多优化
  • 3:全部优化
  • "s":优先缩小二进制体积
  • "z":极致缩小体积(会关掉一些向量化)

经验上 3 不一定比 2 快,有时反而更慢,且会让调试更难。别盲目上 3,对热点路径做基准测试再定。

overflow-checks 决定是否在运行时检查整数溢出。开启时溢出直接 panic,默认 dev 开、release 关。关掉它程序会快一点点,但溢出变成静默的回绕(wrapping),排错更痛苦。

lto 是链接时优化(Link Time Optimization)。开启后它对整个程序做跨包分析,能产出更优的代码,但会显著拉长链接时间;不开启(默认 false)则完全跳过:

  • false / "off"(默认):关闭 LTO,不做链接时优化
  • true / "fat":全量 LTO,对所有依赖做跨包分析,性能最好、链接最慢
  • "thin":thin LTO,折中方案——性能损失小、链接时间省很多

发布正式版本时常把 lto = true 打开,换运行性能。

panic 决定 panic 时怎么办:"unwind" 是展开调用栈,"abort" 是直接终止程序。注意测试和基准测试目前强制要求 "unwind",改不了。

debug 控制二进制里塞多少调试信息(0/false 无、1 行号、2 完整)。incremental 控制增量编译开关,能复用上次编译信息、加速日常改代码。codegen-units 控制把包拆成几个代码生成单元,单元越多并行编译越快,但运行性能可能略降。

1-4 自定义 profile

除了四种默认的,你还能定义自己的 profile。大团队常用它搭更灵活的发布流程。自定义时必须写 inherits,说明缺的配置从哪个默认 profile 继承:

[profile.release-lto]
inherits = "release"
lto = true

构建时用 --profile 指定:

cargo build --profile release-lto

自定义 profile 的产物放在同名目录,比如这里落在 target/release-lto

Tip

自定义 profile 适合”既要 release 的优化、又要某种特殊开关”的场景。新手先用好 devrelease 两种就足够,等真有需要再自定义。

1-5 给特定依赖单独覆盖

有时你想让某个依赖用更高的优化级别(比如一个计算密集的底层库),可以针对包名覆盖:

[profile.dev.package.foo]
opt-level = 3

package 后面是包名,也能带版本号:[profile.dev.package."foo:2.1.0"]。想给所有非工作空间的依赖统一设置:

[profile.dev.package."*"]
opt-level = 2

还能给构建脚本和过程宏单独设(build-override)。这类覆盖不能用 panicltorpath 这几个选项。

1-6 默认 profile 长什么样

了解默认值,改的时候心里才有底。dev 默认大致是:

[profile.dev]
opt-level = 0
debug = true
debug-assertions = true
overflow-checks = true
lto = false
panic = 'unwind'
incremental = true
codegen-units = 256

release 默认大致是:

[profile.release]
opt-level = 3
debug = false
debug-assertions = false
overflow-checks = false
lto = false
panic = 'unwind'
incremental = false
codegen-units = 16

test 继承自 devbench 继承自 release。这些默认值已经过官方调校,日常无需动;只有当你清楚自己要什么效果时,再去针对性修改。

Note

profile 是”编译期工程权衡”的集中体现:用编译时间换运行速度,或反过来。理解了它,你就明白为什么调试用 debug、上线用 release,而不是凭感觉。

1-7 常见组合与踩坑

把几个选项组合起来,能解决真实场景的痛点。比如发布正式版本,常这样配:

[profile.release]
opt-level = 3
lto = true
codegen-units = 1

lto = truecodegen-units = 1 能让优化器看到整个程序、产出最快的代码,代价是链接极慢——本地开发千万别开,只留给发版那一次。

相反,日常调试想快一点,可以稍微提优化:

[profile.dev]
opt-level = 1

只把 opt-level 从 0 提到 1,编译速度几乎无损,运行却能快一截,打断点调试也更接近真实表现。

Warning

别在 dev 里关掉 overflow-checks 图快。整数溢出在调试阶段恰恰是最该被抓出来的,关掉它,溢出变成静默回绕,bug 会藏得更深、更难复现。性能敏感的热循环另有办法优化,不该拿安全检查开刀。

还有个经验:bench profile 继承自 release,所以 cargo bench 跑的是满优化代码,测出来的性能数字才是可信的。如果你怀疑某次优化”变慢了”,用 cargo bench 对比前后,比肉眼猜靠谱得多。

Note

profile 的默认值已经过官方精心调校,绝大多数项目用默认 dev/release 就够了。只有当你明确知道”我要更快的链接”或”我要更小的体积”时,再去动对应选项,并且改完用基准测试验证收益,别凭感觉调。

1-8 查看当前生效的配置

有时你改了 profile 却不确定到底生不生效,可以借助 cargo 把最终配置打印出来核对。另外,CI 里编译慢,常把 target 目录缓存起来复用——但如果你改了 profile(比如开了 lto),旧缓存可能和新的编译选项不匹配,反而引出诡异问题。遇到”本地能编 CI 编不过”,先怀疑是不是缓存没清。

Tip

profile 是”用编译时间换运行性能”的旋钮,不是越多越好。先把默认 dev/release 用顺,真遇到性能或体积瓶颈,再针对性动一两个选项,并且改完用基准测试验证收益,别凭感觉调。

下一章我们学习如何把自己写的库发布到 crates.io,让全世界的 Rustacean 都能用。