掘金 后端 ( ) • 2024-04-22 15:07

cargo build 的结果会被放入项目根目录下的 target 文件夹中,当然,这个位置可以三种方式更改:设置 CARGO_TARGET_DIR 环境变量、build.target-dir 配置项以及 --target-dir 命令行参数。

cargo build编译

cargo run 首先对项目进行编译,然后再运行,因此它实际上等同于运行了两个指令,下面我们手动试一下编译和运行项目:

cargo build 
Finished dev [unoptimized + debuginfo] target(s) in 0.00s

运行编译后的文件:

$ ./target/debug/world_hello 
Hello, world!

行云流水,但谈不上一气呵成。 细心的读者可能已经发现,在调用的时候,路径 ./target/debug/world_hello 中有一个明晃晃的 debug 字段,没错我们运行的是 debug 模式,在这种模式下,代码的编译速度会非常快,可是福兮祸所伏,运行速度就慢了. 原因是,在 debug 模式下,Rust 编译器不会做任何的优化,只为了尽快的编译完成,让你的开发流程更加顺畅。

作为尊贵的读者,咱自然可以要求更多,比如你想要高性能的代码怎么办? 简单,添加 --release 来编译:

  • cargo run --release
  • cargo build --release

试着运行一下我们高性能的 release 程序:

$ ./target/release/world_hello 
Hello, world!

cargo check

当项目大了后,cargo run 和 cargo build 不可避免的会变慢,那么有没有更快的方式来验证代码的正确性呢?大杀器来了,接着!

cargo check 是我们在代码开发过程中最常用的命令,它的作用很简单:快速的检查一下代码能否编译通过。因此该命令速度会非常快,能节省大量的编译时间。

$ cargo check 
Checking world_hello v0.1.0 (/Users/sunfei/development/rust/world_hello) Finished dev [unoptimized + debuginfo] target(s) in 0.06s

Rust 虽然编译速度还行,但是还是不能与 Go 语言相提并论,因为 Rust 需要做很多复杂的编译优化和语言特性解析,甚至连如何优化编译速度都成了一门学问: 优化编译速度

target 目录结构

target 目录的结构取决于是否使用 --target 标志为特定的平台构建。

若 --target 标志没有指定,Cargo 会根据宿主机架构进行构建,构建结果会放入项目根目录下的 target 目录中,target 下每个子目录中包含了相应的 发布配置profile 的构建结果,例如 release、debug 是自带的profile,前者往往用于生产环境,因为会做大量的性能优化,而后者则用于开发环境,此时的编译效率和报错信息是最好的。

除此之外我们还可以定义自己想要的 profile ,例如用于测试环境的 profile: test,用于预发环境的 profile :pre-prod 等。

目录 描述 target/debug/ 包含了 dev profile 的构建输出(cargo build 或 cargo build --debug) target/release release profile 的构建输出,cargo build --release target/foo/ 自定义 foo profile 的构建输出,cargo build --profile=foo

出于历史原因

  • dev 和 test profile 的构建结果都存放在 debug 目录下
  • release 和 bench profile 则存放在 release 目录下
  • 用户定义的 profile 存在同名的目录下

使用--target

当使用 --target XXX 为特定的平台编译后,输出会放在 target/XXX/ 目录下:

目录 示例 target/<triple>/debug target/thumbv7em-none-eabihf/debug/ target/<triple>/release target/thumbv7em-none-eabihf/release/

注意:,当没有使用 --target 时,Cargo 会与构建脚本和过程宏一起共享你的依赖包,对于每个 rustc 命令调用而言,RUSTFLAGS 也将被共享。

而使用 --target 后,构建脚本、过程宏会针对宿主机的CPU架构进行各自构建,且不会共享 RUSTFLAGS。

target子目录说明

在 profile 文件夹中(例如 debug 或 release),包含编译后的最终成果:

target/debug/ : 包含编译后的输出,例如二进制可执行文件、库对象( library target )

target/debug/examples/: 包含示例对象( example target )

还有一些命令会在 target 下生成自己的独立目录:

target/doc/: 包含通过 cargo doc 生成的文档

target/package/: 包含 cargo package 或 cargo publish 生成的输出

Cargo 还会创建几个用于构建过程的其它类型目录,它们的目录结构只应该被 Cargo 自身使用,因此可能会在未来发生变化:

target/debug/deps: 依赖和其它输出成果

target/debug/incremental : rustc增量编译的输出,该缓存可以用于提升后续的编译速度

target/debug/build/: 构建脚本的输出

依赖信息文件

在每一个编译成果的旁边,都有一个依赖信息文件,文件后缀是 .d。该文件的语法类似于 Makefile,用于说明构建编译成果所需的所有依赖包。

该文件往往用于提供给外部的构建系统,这样它们就可以判断 Cargo 命令是否需要再次被执行。

文件中的路径默认是绝对路径,你可以通过 build.dep-info-basedir 配置项来修改为相对路径。

# 关于 `.d` 文件的一个示例 : target/debug/foo.d
/path/to/myproj/target/debug/foo: /path/to/myproj/src/lib.rs /path/to/myproj/src/main.rs

共享缓存

sccache 是一个三方工具,可以用于在不同的工作空间中共享已经构建好的依赖包。

为了设置 sccache,首先需要使用 cargo install sccache 进行安装,然后在调用 Cargo 之前将 RUSTC_WRAPPER 环境变量设置为 sccache

  • 如果用的 bash,可以将 export RUSTC_WRAPPER=sccache 添加到 .bashrc 中
  • 也可以使用 build.rustc-wrapper 配置项