以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「ENG八戒」https://mp.weixin.qq.com/s/PP9b5cSNd-7IqgNovcrB0A
优化输出
前面已经对 cargo package 工程编译输出了好多遍,发现编译结果打印的信息都包含了这个
unoptimized + debuginfo
这个信息表示 cargo 默认的编译构建未做任何的优化,这样方便于调试程序执行逻辑,和最终输出的文件仍然包含大量的调试信息,估计文件大小不容乐观。可见 cargo 编译构建默认是 dev 模式,或者叫它 debug 模式。
$ ll -h target/debug/hello_rust
-rwxrwxrwx 2 user user 4.5M Nov 15 01:58 target/debug/hello_rust
默认配置下 cargo 编译构建的二进制可执行文件 hello_rust 大小高达 4.5M。这对于开发调试过程中,是没有任何问题的。但是,一旦工程开发完毕,输出的二进制可执行文件或者库文件需要发布出去时,文件大小就显得非常刺眼了,况且执行性能也是非常受目标用户关注的。
Cargo 提供了 --release 的构建选项帮助去除调试信息和优化性能,也就是所谓的 release 模式了。
为了体现 release 模式对编译后输出文件的显著影响,先来修改一下代码,加入一些其他内容
$ cat src/main.rs
use rand::Rng;
fn main() {
println!("Hello, world!");
let mut rng = rand::thread_rng();
let random = rng.gen_range(1..101);
println!("random num is {}", random);
}
这段代码添加了打印一个随机数,所以也需要给工程添加依赖项 rand
$ cargo add rand
$ cat Cargo.toml
[package]
name = "hello_rust"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8.5"
再分别在 debug 和 release 模式下编译输出可执行文件
$ cargo clean
$ cargo build
Compiling libc v0.2.150
Compiling cfg-if v1.0.0
Compiling ppv-lite86 v0.2.17
Compiling getrandom v0.2.11
Compiling rand_core v0.6.4
Compiling rand_chacha v0.3.1
Compiling rand v0.8.5
Compiling hello_rust v0.1.0 (~/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 5.89s
$ ll -h target/debug/hello_rust
-rwxrwxrwx 2 user user 5.8M Nov 15 02:14 target/debug/hello_rust
$ cargo clean
$ cargo build --release
Compiling libc v0.2.150
Compiling cfg-if v1.0.0
Compiling ppv-lite86 v0.2.17
Compiling getrandom v0.2.11
Compiling rand_core v0.6.4
Compiling rand_chacha v0.3.1
Compiling rand v0.8.5
Compiling hello_rust v0.1.0 (~/hello_rust)
Finished release [optimized] target(s) in 4.42s
$ ll -h target/release/hello_rust
-rwxrwxrwx 2 user user 4.5M Nov 15 02:15 target/release/hello_rust
在 debug 模式下,输出文件 5.8M,而 release 模式输出的文件减小到了 4.5M,效果是明显的。
在 release 模式下既然会对代码做性能优化,那么编译耗时也相对应该有所增长,可以使用 time 指令对比一下
$ cargo clean
$ time cargo build
Compiling libc v0.2.150
Compiling cfg-if v1.0.0
Compiling ppv-lite86 v0.2.17
Compiling getrandom v0.2.11
Compiling rand_core v0.6.4
Compiling rand_chacha v0.3.1
Compiling rand v0.8.5
Compiling hello_rust v0.1.0 (~/hello_rust)
Finished dev [unoptimized + debuginfo] target(s) in 4.19s
real 0m4.273s
user 0m3.313s
sys 0m2.266s
$ cargo clean
$ time cargo build --release
Compiling libc v0.2.150
Compiling cfg-if v1.0.0
Compiling ppv-lite86 v0.2.17
Compiling getrandom v0.2.11
Compiling rand_core v0.6.4
Compiling rand_chacha v0.3.1
Compiling rand v0.8.5
Compiling hello_rust v0.1.0 (~/hello_rust)
Finished release [optimized] target(s) in 4.22s
real 0m4.299s
user 0m4.234s
sys 0m2.078s
从时长来看,release 模式略微比 debug 模式耗时,但是不明显,可能是因为上面示例程序比较简单的缘故,毕竟 release 模式下编译构建需要做的事情更复杂。
生成库或者可执行文件
上面的例子里,编译输出都是可执行文件,可执行文件可以独立执行,但也可调用库文件。软件工程的编译输出基本可以划分为两类,一个就是可执行文件,另一个就是库文件,一般在创建软件工程时可以指定输出类型。
Cargo 在创建 package 工程时默认指定生成可执行文件,如果是要输出库文件,需要添加 --lib 选项。下面来对比一下两种工程模板
$ cargo new hello_rust
Created binary (application) `hello_rust` package
$ tree hello_rust/
hello_rust/
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
$ cargo new lib_rust --lib
Created library `lib_rust` package
$ tree lib_rust/
lib_rust/
├── Cargo.toml
└── src
└── lib.rs
1 directory, 2 files
hello_rust 是可执行文件类型 package 工程,lib_rust 是库文件类型 package 工程。自动生成的源码文件有所不同,前者是 main.rs,后者是 lib.rs。
对比一下自动生成的配置文件 Cargo.toml
$ diff hello_rust/Cargo.toml lib_rust/Cargo.toml
2c2
< name = "hello_rust"
---
> name = "lib_rust"
发现两种工程的配置文件内容除了工程名不一致,其它都是一样的,可推测 cargo 是通过 src 路径下的文件名来识别工程类型,src/main.rs 默认表明是可执行应用类型,src/lib.rs 默认表明是库类型。