编译设置
Profile "编译设置" 提供了一种修改编译器设置的方法,从而影响代码优化和调试符号等。
Cargo 内置的编译设置有4种: dev
、 release
、 test
和 bench
。
如果命令行中并未指定具体的编译设置,Cargo会根据当前运行的命令来自动选择。
除了内置,用户也可以自定义。
编译设置可以在 Cargo.toml
文件 [profile]
表中进行修改。
具体某个名称的编译设置中,单独的设置条目可以用键值对来修改:
[profile.dev]
opt-level = 1 # 使用较好的优化级别。
overflow-checks = false # 关闭整数溢出检查。
Cargo只会扫描工作空间根目录下 Cargo.toml
配置清单中的编译设置。
在依赖中定义的编译设置会被忽略。
此外,可以通过 config 的定义来覆盖编译设置。
在config文件或环境变量中指定编译设置将会覆盖 Cargo.toml
中的。
编译设置条目
下面是可以在编译设置中进行控制的设置条目列表。
opt-level
opt-level
设置控制 -C opt-level
flag 优化级别。高优化级别通过更长的编译时间换来生成后更快的运行时代码。
更高的优化级别同时也可能改变或者重新布局编译过的代码,从而更难调试。
有效选项:
0
: 无优化1
: 基础优化2
: 适量优化3
: 优化全开"s"
: 优化二进制大小"z"
: 优化二进制大小,同时关闭循环向量化
建议你的项目尝试用不同的优化级别,从而找到合理的平衡。也许你有时会惊讶级别 3
会比级别 2
慢,或者 "s"
和 "z"
级别未能压缩二进制的大小。
在开发的过程中,由于 rustc
版本更新可能改变了优化行为,也许你也需要重新评估设置。
另请参阅Profile Guided Optimization了解更多的高级优化技巧。
debug
debug
设置控制 [ -C debuginfo
flag] 编译后的二进制调试的信息量。
有效选项:
0
或false
: 无调试信息1
: 只包含行号表2
或true
: 包含完整的调试信息
也许根据需要,同时配置 split-debuginfo
选项。
split-debuginfo
split-debuginfo
设置控制 -C split-debuginfo
flag 调试信息,如果产生的话,是放在可执行文件本身,还是放在其旁边。
这个选项是字符串,可接受的值与编译器接受的相同。
在macOS上,这个选项的默认值是 unpacked
,用于已启用调试信息的编译设置。
否则,这个选项的默认值是 rustc文档,并且是特定平台的。
有些选项只在 每日构建通道 中可用。
一旦进行了更多的测试,并且对DWARF的支持稳定下来,Cargo的默认值可能会在未来发生变化。
strip
strip
选项控制 [ -C strip
flag] 从而告知 rustc 从二进制文件中去除符号或调试信息。可以像这样启用:
[package]
# ...
[profile.release]
strip = "debuginfo"
可能的 strip
字符串值包括 "none"
、 "debuginfo"
和 "symbols"
。默认值是 "none"
。
你还可以使用布尔值 true
或 false
配置此选项。
strip = true
等同于 strip = "symbols"
。
strip = false
等同于 strip = "none"
并完全禁用 strip
。
debug-assertions
debug-assertions
设置控制 [ -C debug-assertions
flag] ,从而可以打开或关闭 cfg(debug_assertions)
conditional compilation "条件编译"。
调试断言旨在包含仅在调试或开发版本可用的运行时验证。这些对于发布版本来说可能消耗过高或者并不需要。调试断言会开启标准库中的 debug_assert!
macro 。
有效选项:
true
: 开启false
: 禁用
overflow-checks
overflow-checks
设置控制[ -C overflow-checks
flag] ,控制 runtime integer overflow 的行为。当启用溢出检查时,溢出将导致系统发生严重错误,从而panic恐慌。
有效选项:
true
: 开启false
: 禁用
lto
lto
设置控制 -C lto
flag,控制LLVM link time optimizations "链接时优化"。
LTO可以使用全过程分析,以更长的链接时间换取生成更好的优化后的代码。
有效选项:
false
: 执行 "thin local LTO",仅在本地的所有crate上执行 "thin" LTOcodegen units。如果codegen单位为1或opt-level是0,则不会进行LTO优化。true
或"fat"
:执行 "fat" LTO,尝试对依赖图中的所有crate执行优化。"thin"
:执行 "thin" LTO。这与 "fat" 类似,但运行时间缩短,同时仍能获得类似于 "fat" 的性能提升。"off"
: 禁用 LTO。
另请参阅[ -C linker-plugin-lto
] rustc
跨语言LTO标志。
panic
panic
设置控制 [ -C panic
flag] ,控制使用哪种恐慌策略。
有效选项:
"unwind"
:panic时进行栈解旋。"abort"
:panic时终止进程。
当设置为 "unwind"
时,实际值取决于目标平台的默认值。例如,NVPTX平台不支持栈解旋,所以它总是使用 "abort"
。
测试、性能测试、构建脚本、过程宏会忽略 panic
设置。
rust
测试工具目前需要 unwind
行为。 见 panic-abort-tests
未稳定的标志启用 abort
行为。
此外,当使用 abort
策略和构建测试时,所有依赖也将强制使用 unwind
策略来构建。
incremental
incremental
设置控制[ -C incremental
flag],控制是否启用增量编译。
增量编译会使 rustc
将额外的信息保存到磁盘,这些额外信息在重新编译crate时可重复使用,从而缩短重新编译时间。附加信息存储在 target
目录中。
有效选项:
true
: 开启false
: 禁用
增量编译仅用于工作空间成员和 "path" 依赖。
增量值可以用 CARGO_INCREMENTAL
environment variable 或者 [ build.incremental
] config 变量来进行全局覆盖。
codegen-units
codegen-units
设置控制[ -C codegen-units
flag],控制着crate分割到多少个"代码生成单元"。
更多的代码生成单元允许并行处理更多的crate,这可能会减少编译时间,但可能会生成较慢的代码。
此选项接受大于0的整数。
默认值为256 incremental构建 ,16用于非增量构建。
rpath
rpath
设置控制[ -C rpath
flag],控制是否启用 [ rpath
] 。
默认编译设置
dev
dev
编译设置用于日常的开发和调试。它是构建指令如[ cargo build
]的默认参数,并且用于 cargo install --debug
。
dev
编译设置的默认设置有:
[profile.dev]
opt-level = 0
debug = true
split-debuginfo = '...' # 平台指定。
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 = '...' # 平台指定。
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
编译配置中的设置。
构建依赖
默认情况下,所有的编译设置都不会优化构建依赖(构建脚本、过程宏、它们的依赖)。构建覆盖的默认设置为:
[profile.dev.build-override]
opt-level = 0
codegen-units = 256
[profile.release.build-override]
opt-level = 0
codegen-units = 256
构建依赖项以其他方式继承正在使用的编译设置条目,如Profile selection所描述。
自定义编译设置
除了内置编译设置,还可以自定义。在需要划分多个工作流和构建模式时,可能会用到自定义编译设置。
在自定义编译设置时,必须指定 inherits
键,以便在条目没有指定时,可以找到自定义继承了的哪个编译设置。
举例来说,假如你想将一个普通的发布构建与使用LTO优化的构建做比较,那么可以如下在 Cargo.toml
指定:
[profile.release-lto]
inherits = "release"
lto = true
--profile
标志可用来选择自定义编译设置:
cargo build --profile release-lto
每个编译设置的输出会放在target
directory下和编译设置同名的文件夹下。对于上面的例子来说,编译设置产生的输出会放置在路径为 target/release-lto
文件夹下。
编译设置选择
编译设置的使用依赖于指令、命令行标志如 --release
或 --profile
和包(比如overrides)。如果未指定那么默认的编译设置为:
Command | Default Profile |
---|---|
cargo run , cargo build ,cargo check , cargo rustc | dev profile |
cargo test | test profile |
cargo bench | bench profile |
cargo install | release profile |
可以使用 --profile=NAME
来切换到不同的编译设置。 --release
标志等价于 --profile=release
。
选择的编译设置作用于Cargo所有的生成目标,包括 library, binary, example, test, benchmark。
对于特定包的编译设置可以使用overrides来指定,描述如下。
覆盖
编译设置可对特定包和构建时的crate进行覆盖。如需对特定的包进行覆盖,使用 package
表来更改已命名的包的编译设置:
# `foo` 包会使用 -Copt-level=3 标志。
[profile.dev.package.foo]
opt-level = 3
包的名字实际为Package ID Spec,所以可以使用如 [profile.dev.package."foo:2.1.0"]
的语法定位到某个版本的包。
如需覆盖所有依赖的设置(但是并非任意工作空间的成员),使用 "*"
包名 :
# 为所有配置设定默认设置。
[profile.dev.package."*"]
opt-level = 2
如需覆盖构建脚本、过程宏和相关依赖的设置,使用 build-override
表:
# 为构建脚本和过程宏设置配置。
[profile.dev.build-override]
opt-level = 3
注意:当依赖既是普通依赖而且是构建依赖时, 如果
--target
未指定,Cargo 会试图只构建一次。 当使用build-override
时,依赖可能需要构建两次, 一次作为正常依赖项,一次使用覆盖的构建设置。这可能会增加初始构建的时间。
使用值的优先顺序如下(先匹配到的优先):
[profile.dev.package.name]
— 命名的包。[profile.dev.package."*"]
— 对于任何非工作空间成员。[profile.dev.build-override]
— 仅适用于构建脚本、过程宏及其依赖项。[profile.dev]
—Cargo.toml
中的设置。- Cargo中内置的默认值。
覆盖不能指定 panic
、 lto
、 rpath
设置。
覆盖和泛型
实例化泛型代码的位置会影响用于该泛型代码的优化配置。 当使用编译配置覆盖去更改特定crate的优化级别时,这可能会导致微妙的影响。 如果试图提高定义泛型函数依赖的优化级别,在本地crate中使用这些泛型函数时可能无法进行优化。 这是因为代码可能会在其实例化的crate中生成,因而可能会使用该crate的优化设置。
举例来说, nalgebra 是一个定义向量和矩阵的库,并且大量使用了泛型参数。
如果你的本地代码定义了具体的nalgebra类型,比如 Vector4<f64>
并使用他们的方法,相应的nalgebra代码将被实例化并构建在你的crate中。
因此,如果你试图使用覆盖编译配置来提高nalgebra的优化级别的话,可能并不会带来更快的性能。
更复杂的是, rustc
有一些优化尝试在crate之间共享单态化的泛型。如果优化级别是2或3,
那么crate将不会使用其他crate中单态化的泛型,也不会导出本地定义的与其他crate共享的单态化内容。