配置文件

配置文件提供了一种修改编译器设置的方式,这会影响优化和调试符号等内容。

Cargo 有 4 个内置配置文件:devreleasetestbench。如果在命令行上未指定配置文件,则会根据正在运行的命令自动选择配置文件。除了内置配置文件外,还可以指定自定义用户定义的配置文件。

配置文件设置可以在 Cargo.toml 中使用 [profile] 表进行更改。在每个命名配置文件中,可以通过如下所示的键/值对更改各个设置

[profile.dev]
opt-level = 1               # Use slightly better optimizations.
overflow-checks = false     # Disable integer overflow checks.

Cargo 只会查找位于工作空间根目录的 Cargo.toml 清单中的配置文件设置。依赖项中定义的配置文件设置将被忽略。

此外,配置文件可以通过 配置 定义进行覆盖。在配置文件或环境变量中指定配置文件将覆盖 Cargo.toml 中的设置。

配置文件设置

以下是可以在配置文件中控制的设置列表。

opt-level

opt-level 设置控制 -C opt-level 标志,该标志控制优化级别。更高的优化级别可能会生成更快的运行时代码,但代价是更长的编译时间。更高的级别还可能更改和重新排列编译后的代码,这可能会使其更难与调试器一起使用。

有效选项为

  • 0: 无优化
  • 1: 基本优化
  • 2: 一些优化
  • 3: 所有优化
  • "s": 优化以减小二进制大小
  • "z": 优化以减小二进制大小,但也关闭循环向量化。

建议尝试不同的级别以找到适合您项目的平衡点。可能会出现令人惊讶的结果,例如级别 32 慢,或者 `"s"` 和 `"z"` 级别不一定更小。随着 rustc 新版本更改优化行为,您可能还需要随着时间推移重新评估您的设置。

另请参阅 配置文件引导优化 以了解更高级的优化技术。

debug

debug 设置控制 -C debuginfo 标志,该标志控制编译后的二进制文件中包含的调试信息量。

有效选项为

  • 0false 或 `"none"`: 完全没有调试信息,release 的默认值
  • "line-directives-only": 仅行信息指令。对于 nvptx* 目标,这会启用 性能分析。对于其他用例,line-tables-only 是更好、更兼容的选择。
  • "line-tables-only": 仅行表。生成回溯所需的最少调试信息,包含文件名/行号信息,但不包含其他任何内容,即没有变量或函数参数信息。
  • 1 或 `"limited"`: 不包含类型或变量级别信息的调试信息。生成比 line-tables-only 更详细的模块级信息。
  • 2true 或 `"full"`: 完整的调试信息,dev 的默认值

有关每个选项作用的更多信息,请参阅 rustc 关于 debuginfo 的文档。

您可能还需要根据您的需求配置 split-debuginfo 选项。

**MSRV:** nonelimitedfullline-directives-onlyline-tables-only 需要 1.71 版本。

split-debuginfo

split-debuginfo 设置控制 -C split-debuginfo 标志,该标志控制生成的调试信息是放置在可执行文件本身中还是其附近。

此选项是一个字符串,可接受的值与 编译器接受的值 相同。对于启用了调试信息的配置文件,此选项在 macOS 上的默认值为 unpacked。否则,此选项的默认值 在 rustc 文档中有说明 并且是平台特定的。某些选项仅在 nightly 通道 上可用。一旦进行更多测试并且 DWARF 支持稳定后,Cargo 的默认值将来可能会改变。

请注意,Cargo 和 rustc 对于此选项有不同的默认值。此选项的存在是为了允许 Cargo 试验不同的标志组合,从而提供更好的调试和开发者体验。

strip

strip 选项控制 -C strip 标志,该标志指示 rustc 从二进制文件中剥离符号或调试信息。可以像这样启用它

[package]
# ...

[profile.release]
strip = "debuginfo"

strip 可能的字符串值为 `"none"`、`"debuginfo"` 和 `"symbols"`。默认值为 `"none"`。

您也可以使用布尔值 truefalse 配置此选项。strip = true 等效于 strip = "symbols"strip = false 等效于 strip = "none" 并完全禁用 strip

debug-assertions

debug-assertions 设置控制 -C debug-assertions 标志,该标志开启或关闭 cfg(debug_assertions) 条件编译。调试断言旨在包含仅在调试/开发构建中可用的运行时验证。这些在发布构建中可能过于昂贵或不受欢迎。调试断言启用标准库中的 debug_assert!

有效选项为

  • true: 启用
  • false: 禁用

overflow-checks

overflow-checks 设置控制 -C overflow-checks 标志,该标志控制 运行时整数溢出 的行为。当启用溢出检查时,溢出时会发生 panic。

有效选项为

  • true: 启用
  • false: 禁用

lto

lto 设置控制 rustc-C lto-C linker-plugin-lto-C embed-bitcode 选项,这些选项控制 LLVM 的 链接时优化。LTO 可以利用全程序分析生成更好的优化代码,但代价是更长的链接时间。

有效选项为

  • false: 执行“本地细粒度 LTO”,仅在本地 crate 的 代码生成单元 之间执行“细粒度”LTO。如果代码生成单元为 1 或 opt-level 为 0,则不执行 LTO。
  • true 或 `"fat"`: 执行“胖”LTO,尝试在依赖图中的所有 crate 之间执行优化。
  • "thin": 执行 “细粒度”LTO。这类似于“胖”,但运行时间大大减少,同时仍能获得与“胖”类似的性能提升。
  • "off": 禁用 LTO。

如果您对跨语言 LTO 感兴趣,请参阅 linker-plugin-lto 章。Cargo 尚不支持原生实现,但可以通过 RUSTFLAGS 执行。

panic

panic 设置控制 -C panic 标志,该标志控制使用哪种 panic 策略。

有效选项为

  • "unwind": 发生 panic 时展开栈。
  • "abort": 发生 panic 时终止进程。

当设置为 `"unwind"` 时,实际值取决于目标平台的默认值。例如,NVPTX 平台不支持展开,因此始终使用 `"abort"`。

测试、基准测试、构建脚本和 proc 宏会忽略 panic 设置。rustc 测试工具目前需要 unwind 行为。参见 panic-abort-tests 不稳定标志,该标志启用 abort 行为。

此外,当使用 abort 策略并构建测试时,所有依赖项也将被强制使用 unwind 策略构建。

incremental

incremental 设置控制 -C incremental 标志,该标志控制是否启用增量编译。增量编译会使 rustc 将额外信息保存到磁盘,这些信息在重新编译 crate 时会被重用,从而缩短重新编译时间。额外信息存储在 target 目录中。

有效选项为

  • true: 启用
  • false: 禁用

增量编译仅用于工作空间成员和“路径”依赖项。

增量值可以通过 CARGO_INCREMENTAL 环境变量build.incremental 配置变量进行全局覆盖。

codegen-units

codegen-units 设置控制 -C codegen-units 标志,该标志控制 crate 将被分割成多少个“代码生成单元”。更多的代码生成单元允许更多 crate 部分并行处理,可能会缩短编译时间,但可能会生成较慢的代码。

此选项接受一个大于 0 的整数。

对于 增量 构建,默认值为 256;对于非增量构建,默认值为 16。

rpath

rpath 设置控制 -C rpath 标志,该标志控制是否启用 rpath

默认配置文件

dev

dev 配置文件用于正常开发和调试。它是 cargo build 等构建命令的默认值,也用于 cargo install --debug

dev 配置文件的默认设置为

[profile.dev]
opt-level = 0
debug = true
split-debuginfo = '...'  # Platform-specific.
strip = "none"
debug-assertions = true
overflow-checks = true
lto = false
panic = 'unwind'
incremental = true
codegen-units = 256
rpath = false

release

release 配置文件用于发布和生产中使用的优化过的产物。当使用 --release 标志时使用此配置文件,并且是 cargo install 的默认值。

release 配置文件的默认设置为

[profile.release]
opt-level = 3
debug = false
split-debuginfo = '...'  # Platform-specific.
strip = "none"
debug-assertions = false
overflow-checks = false
lto = false
panic = 'unwind'
incremental = false
codegen-units = 16
rpath = false

test

test 配置文件是 cargo test 使用的默认配置文件。test 配置文件继承 dev 配置文件的设置。

bench

bench 配置文件是 cargo bench 使用的默认配置文件。bench 配置文件继承 release 配置文件的设置。

构建依赖项

为了快速编译,所有配置文件默认都不优化构建依赖项(构建脚本、proc 宏及其依赖项),并且在构建依赖项未用作运行时依赖项时避免计算调试信息。构建覆盖的默认设置为

[profile.dev.build-override]
opt-level = 0
codegen-units = 256
debug = false # when possible

[profile.release.build-override]
opt-level = 0
codegen-units = 256

但是,如果在运行构建依赖项时发生错误,开启完整的调试信息将在需要时改进回溯和调试能力

debug = true

构建依赖项否则会继承正在使用的活动配置文件的设置,如 配置文件选择 中所述。

自定义配置文件

除了内置配置文件外,还可以定义额外的自定义配置文件。这对于设置多个工作流程和构建模式可能很有用。定义自定义配置文件时,必须指定 inherits 键来指定当某个设置未指定时,该自定义配置文件从哪个配置文件继承设置。

例如,假设您想比较正常的 release 构建与带有 LTO 优化的 release 构建,您可以在 Cargo.toml 中指定如下内容

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

然后可以使用 --profile 标志来选择此自定义配置文件

cargo build --profile release-lto

每个配置文件的输出将放置在 target 目录 中与配置文件同名的目录中。如上面的示例所示,输出将进入 target/release-lto 目录。

配置文件选择

使用的配置文件取决于命令、--release--profile 等命令行标志,以及包(在 覆盖 的情况下)。如果未指定配置文件,则默认配置文件为

您可以使用 --profile=NAME 选项切换到不同的配置文件,该选项将使用给定的配置文件。--release 标志等效于 --profile=release

所选配置文件适用于所有 Cargo 目标,包括 二进制文件示例测试基准测试

特定包的配置文件可以通过 覆盖 指定,如下所述。

覆盖

可以为特定包和构建时 crate 覆盖配置文件设置。要覆盖特定包的设置,请使用 package 表更改指定包的设置

# The `foo` package will use the -Copt-level=3 flag.
[profile.dev.package.foo]
opt-level = 3

包名实际上是一个 包 ID 规范,因此您可以使用诸如 [profile.dev.package."foo:2.1.0"] 之类的语法来指定包的单个版本。

要覆盖所有依赖项(但不包括任何工作空间成员)的设置,请使用 "*" 包名

# Set the default for dependencies.
[profile.dev.package."*"]
opt-level = 2

要覆盖构建脚本、proc 宏及其依赖项的设置,请使用 build-override

# Set the settings for build scripts and proc-macros.
[profile.dev.build-override]
opt-level = 3

注意:当一个依赖项既是普通依赖项又是构建依赖项时,如果未指定 --target,Cargo 会尝试只构建一次。使用 build-override 时,该依赖项可能需要构建两次,一次作为普通依赖项,一次使用被覆盖的构建设置。这可能会增加初始构建时间。

使用哪个值的优先级按以下顺序进行(第一个匹配项获胜)

  1. [profile.dev.package.name] — 指定的包。
  2. [profile.dev.package."*"] — 对于任何非工作空间成员。
  3. [profile.dev.build-override] — 仅用于构建脚本、proc 宏及其依赖项。
  4. [profile.dev]Cargo.toml 中的设置。
  5. Cargo 内置的默认值。

覆盖不能指定 panicltorpath 设置。

覆盖与泛型

泛型代码被实例化(生成具体代码)的位置会影响该泛型代码使用的优化设置。在使用配置文件覆盖来更改特定 crate 的优化级别时,这可能会导致微妙的交互。如果您尝试提高定义泛型函数的依赖项的优化级别,当在您的本地 crate 中使用这些泛型函数时,它们可能不会被优化。这是因为代码可能在其被实例化的 crate 中生成,因此可能使用该 crate 的优化设置。

例如,nalgebra 是一个大量使用泛型参数定义向量和矩阵的库。如果您的本地代码定义了具体的 nalgebra 类型,例如 Vector4<f64>,并使用它们的方法,相应的 nalgebra 代码将在您的 crate 中被实例化和构建。因此,如果您尝试使用配置文件覆盖来提高 nalgebra 的优化级别,可能无法提高性能。

使问题更加复杂的是,rustc 有一些优化会尝试在 crate 之间共享单态化(monomorphized)的泛型。如果 opt-level 是 2 或 3,则一个 crate 将不会使用其他 crate 的单态化泛型,也不会导出本地定义的单态化项以与其他 crate 共享。在试验优化依赖项以用于开发时,可以考虑尝试 opt-level 1,它会在应用一些优化的同时仍允许共享单态化项。