文档列表见:Rust 移动端跨平台复杂图形渲染项目开发系列总结(目录)
2019.4.24 更新:多条件(feature)编译
Cargo用于组织Rust项目,比直接用rustc编译多个源文件更方便。本文档介绍我们开发过程中用到的Cargo功能与小技巧,更多信息可参考 The Cargo Book。
使用依赖项目的指定git commit
rev
表示要用的git commit id,可简写成前7个字符,因为git commit id前7个字符可算出完整的41个SHA字符值。
[dependencies]
gfx-hal = { version = "0.1.0", git = "https://github.com/gfx-rs/gfx", rev = "bd7f058" }
# 或者写成多行
[dependencies.gfx-hal]
git = "https://github.com/gfx-rs/gfx"
version = "0.1.0"
rev = "bd7f058"
git仓库地址需要支持https访问,如果是http需要额外配置,比较麻烦。
引用本地Rust项目
[dependencies]
hello_utils = { path = "hello_utils", version = "0.1.0" }
path是相对于本项目Cargo.toml文件的被依赖项目的Cargo.toml的位置,填错将找不到文件,且编译报错。详细信息参考The Cargo Book/specifying-dependencies
workspace feature 条件编译的执行路径问题
当cargo workspace中存在多个project时,如果对某一project进行feature条件编译或单元测试,一定要在此项目的Cargo.toml或src路径中执行,否则Cargo会忽悠cargo test
或cargo build --features=your_feature
所指定的feature,这是个容易遇的坑。
default feature 条件编译
[features]
default = ["gfx-backend-metal"]
写在Cargo.toml的default = ["a", "b", "c"]
对cargo build
是默认启用的,即不用加上--features
条件。
多条件(feature)编译
语法:--features "条件1 条件2 条件3"
,每个feature(条件)中间留出空格,示例:
cargo build --features "metal gl" --bin quad
表示启用metal
、gl
两个条件编译去编译quad可执行程序。
cargo c 减少编译耗时
- 使用
cargo check
,命令可缩写为cargo c
。如果只是想验证语法、类型检查等,那么可以直接使用这个命令,它只会调用编译器前端。比cargo build
快2倍,比cargo build -—release
快6倍。 - 使用sccache,该工具是Mozilla出品的Rust兼容的编译缓存服务,一般可以获得2倍速度提升。使用
cargo install sccache
安装sccache,并且在.bashrc中添加环境变量export RUSTC_WRAPPER=sccache
- 避免LTO。 LTO是链接时优化的缩写。LTO将付出更高的编译时间代价。
- 控制crate依赖。
编译优化级别说明
opt level 3和z,哪个性能优化更高?答案:3。 z不管性能,z和s差不多,O2的优化,减少size。
另一种说法:在不同平台上会得到不同结果,-z为size优化,对于cpu code cache小的机器优势比较大,大概就是优化等级开高了代码尺寸变大会导致在某些cache小的机器上性能下降的很厉害。z在inline的优化肯定要少一些。优化这东西是个神坑,不要跳。建议在你的手机上进行profiling。
opt level 参数完整说明见 Properly document and explain opt-levels s and z
[profile.release] debug=true 的讨论
这样改会影响release的性能吗? 好像只是留下符号信息。编译出来大点吧。性能应该不会有啥影响。你可以试试 说起来release带符号 会不会导致行号不准啊
To get the best data from a profiler, you need both optimizations (usually enabled only in release builds) and debug symbols (usually enabled only in debug builds). To enable both, add this to your Cargo.toml: Programming Rust
尝试:
debug = false --release image-20190225103810132
debug = true --release image-20190225104833677
hal api基本没改善,可能是因为多数被inline或zero cost abstraction?
workspace 与其子 project 同时指定 [profile] 配置会引起冲突
package: /Users/michael/Documents/my_project/gles/Cargo.toml workspace: /Users/michael/Documents/my_project/Cargo.toml 同时指定
# The release profile, used for `cargo build --release`
[profile.release]
panic = "abort"
debug = true # `true` for better profiler readability with debug symbols, `false` for sdk client
lto = true
opt-level = 3
overflow-checks = false
warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
测试Rust代码中的Markdown代码段
/// Open the physical device with `count` queues from some active queue family. The family is
/// the first that both provides the capability `C`, supports at least `count` queues, and for
/// which `selector` returns true.
///
/// # Examples
///
/// ```no_run
/// # extern crate gfx_backend_empty as empty;
/// # extern crate gfx_hal as hal;
/// use hal::General;
/// # fn main() {
///
/// # let mut adapter: hal::Adapter<empty::Backend> = return;
/// let (device, queues) = adapter.open_with::<_, General>(1, |_| true).unwrap();
/// # }
/// ```
///
/// # Return
///
/// Returns the same errors as `open` and `InitializationFailed` if no suitable
/// queue family could be found.
pub fn open_with<F, C>(
&self,
count: usize,
selector: F,
) -> Result<(B::Device, QueueGroup<B, C>), DeviceCreationError>
where
F: Fn(&B::QueueFamily) -> bool,
C: Capability,
{
// ...
}
注释中的Examples
代码可以用rust-skeptic进行测试,具体做法可阅读rust-skeptic文档。