Hello Cargo

发布时间 2023-06-12 11:11:25作者: CloverYou

创建于2023-03-30 09:51

本笔记主要来自于 Rust 程序设计语言 中文版 [1.3],旨在记录个人学习过程中的重点和心得体会。在记录过程中,笔者会对文档中的某些内容进行摘抄或修改,并添加自己的注释或说明。如有不当之处,请指正。

Cargo 是 Rust 的构建系统和包管理器(有些类似MAVEN和YARN、PNPM + VITE/WEBPACK),大多数 rust 开发者都用它来管理 Rust 项目,因为他可以为你处理很多任务,比如构建代码、下载依赖库以及编译这些库。(代码所需要的库通常被叫做依赖)

一个最简单的 Rust 项目可能不包含任何依赖,所以如果使用 Cargo 来构建它,那么将只会使用到 Cargo 构建代码的那部分功能。我们在编写更复杂的 Rust 程序时,你将添加依赖想,如果使用 Cargo 启动项目,那么添加依赖项会变的得容易。

使用Cargo创建项目

我需要在我的项目文件夹创建我第一个 Cargo 项目,通过以下命令创建项目

# clover @ MacBook-Pro in ~/dev/rust/learn [10:13:17] 
$ cargo new hello_cargo  
     Created binary (application) `hello_cargo` package

值得注意的是,通过 Cargo 创建的项目不能以数字开头

执行创建命令后,它会在我指定的地方创建 hello_cargo ,同时它还在这个文件夹里创建了一些基础的默认结构,例如一个 Cargo.toml 文件和一个 src 文件夹以及位于 src 文件夹中的 src/main.rs 文件。

同时它也在项目中初始化了 git 仓库和一个 .gitignore 文件。

# clover @ MacBook-Pro in ~/dev/rust/learn [10:14:03] 
$ cd hello_cargo
# clover @ MacBook-Pro in ~/dev/rust/learn/hello_cargo on git:master x [10:16:41] 
$ tree -a
.
├── .git
      ...
├── .gitignore
├── Cargo.toml
└── src
    └── main.rs

10 directories, 8 files

如果需要在一个现有的 git 仓库执行 cargo new,那么它不会生成 git 相关的产物。可以使用 cargo new --vcs=git 来覆盖它的默认行为。

Git 是一个常用的版本控制系统(version control system, VCS)。可以通过 --vcs 参数使 cargo new 切换到其它版本控制系统,或者不使用 VCS。运行 cargo new --help 查看可用的选项。

下面这段内容时 Cargo 生成的 Cargo.toml 默认内容

此文件使用 TOML (Tom's Obvious, Minimal Language) 格式,这是 Cargo 配置文件的格式。

[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
  1. [package] 是一个表块(Section)标题,用来描述一个包(package)的详细信息。随着我们在这个表块添加更多信息,可能还需要添加一些其它表块。
  2. 下面的三行设置了 Cargo 编译程序所需的配置:项目名称、版本和使用的 Rust 大版本号(version区别于edition,version描述的是当前项目的版本,而edition是rust的核心版本,目前为止,Rust的核心版本有:2015、2018、2021 版等)
  3. 最后一行 [dependencies] 是罗列项目依赖的表块的开始。在 Rust 中,代码包被称为 crate

该篇引用来自附录[21.5 E]

我们见过 cargo newCargo.toml 中增加了一些有关 edition 的元数据。本附录将解释其意义!

Rust 语言和编译器有一个为期 6 周的发布循环。这意味着用户会稳定得到新功能的更新。其他编程语言发布大更新但不甚频繁;Rust 选择更为频繁的发布小更新。一段时间之后,所有这些小更新会日积月累。不过随着小更新逐次的发布,或许很难回过头来感叹:“哇,从 Rust 1.10 到 Rust 1.31,Rust 的变化真大!”

每两到三年,Rust 团队会生成一个新的 Rust 版本edition)。每一个版本会结合已经落地的功能,并提供一个清晰的带有完整更新文档和工具的功能包。新版本会作为常规的 6 周发布过程的一部分发布。

这为不同的人群提供了不同的功能:

  • 对于活跃的 Rust 用户,其将增量的修改与易于理解的功能包相结合。
  • 对于非用户,它表明发布了一些重大进展,这意味着 Rust 可能变得值得一试。
  • 对于 Rust 自身开发者,其提供了项目整体的集合点。

在本文档编写时,Rust 有两个版本:Rust 2015 和 Rust 2018。本书基于 Rust 2018 edition 编写。

Cargo.toml 中的 edition 字段表明代码应该使用哪个版本编译。如果该字段不存在,其默认为 2015 以提供后向兼容性。

每个项目都可以选择不同于默认的 2015 edition 的版本。这样,版本可能会包含不兼容的修改,比如新增关键字可能会与代码中的标识符冲突并导致错误。不过除非选择兼容这些修改,(旧)代码仍将能够编译,即便升级了 Rust 编译器的版本。

所有 Rust 编译器都支持任何之前存在的编译器版本,并可以链接任何支持版本的 crate。编译器修改只影响最初的解析代码的过程。因此,如果你使用 Rust 2015 而某个依赖使用 Rust 2018,你的项目仍旧能够编译并使用该依赖。反之,若项目使用 Rust 2018 而依赖使用 Rust 2015 亦可工作。

有一点需要明确:大部分功能在所有版本中都能使用。开发者使用任何 Rust 版本将能继续接收最新稳定版的改进。然而在一些情况,主要是增加了新关键字的时候,则可能出现了只能用于新版本的功能。只需切换版本即可利用新版本的功能。

请查看 Edition Guide 了解更多细节,这是一个完全介绍版本的书籍,包括如何通过 cargo fix 自动将代码迁移到新版本。

以下是 Cargo 生成 src/main.rs 的默认代码

fn main() {
    println!("Hello, world!");
}

它默认生成了一个通过 println! 输出 "Hello World" 的程序,和之前 hello_word 项目的区别是它将代码存放在 src 目录并且在同级生成了 Cargo.toml 配置文件。

和大多数 cli 一样,它希望我们将代码都放在 src 目录下,项目根目录只存放一些其它的资源文件或项目说明文件,例如:README、license 等其它与代码无关的文件,保持一个干净整洁的项目结构

对于没有使用 Cargo 创建的项目而现在希望使用 Cargo,只需要创建 src 目录并将代码移动到该目录,并创建一个 Cargo.toml 文件即可。

构建并运行 Cargo 项目

通过 Cargo 来编译项目

# clover @ MacBook-Pro in ~/dev/rust/learn/hello_cargo on git:master x [10:13:37] 
$ cargo build
   Compiling hello_cargo v0.1.0 (/Users/clover/dev/rust/learn/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 10.47s

cargo build 命令执行后会在 ./target/debug 目录下创建一个可执行文件 hello_cargo (这在 windows 中是hello_cargo.exe),对比之前 hello_world 项目,Cargo 的编译产物并不是存放在“当前”目录中。

如需运行,可以使用 cargo run 命令来操作,如果你 target/debug 目录中没有内容或者你的代码发生了改变,那么该命令会自动执行 build 操作,所以在我们开发的时候无需手动 build。

# clover @ MacBook-Pro in ~/dev/rust/learn/hello_cargo on git:master x [10:19:06] 
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.00s
     Running `target/debug/hello_cargo`
Hello, world!

当然,也可以手动执行可执行文件,但更推荐使用 cargo run 的方式去编译和运行,因为它非常方便

# clover @ MacBook-Pro in ~/dev/rust/learn/hello_cargo on git:master x [10:19:54] 
$ ./target/debug/hello_cargo 
Hello, world!

在首次执行 cargo build 时,会在项目根目录创建一个 Cargo.lock 文件,这个文件用于记录项目依赖的实际版本,目前项目依赖较少,所以里面的内容记录不多。通常我们并不需要去理会这个文件,交给 Cargo 去操作就好。

Cargo 还提供了一个 cargo check 命令,它用于检查代码是否可以正常编译。与 cargo build 不同的是,它并不会产生任何可执行文件,所以它通常比 cargo build 要快很多。在发的时候,我们都需要对代码持续检查以保证第一时间修改错误,所以,cargo check 对我们的开发效率提升会很大。在我们需要使用可执行文件的时候才执行 cargo build

# clover @ MacBook-Pro in ~/dev/rust/learn/hello_cargo on git:master x [10:22:18] 
$ cargo check
    Checking hello_cargo v0.1.0 (/Users/clover/dev/rust/learn/hello_cargo)
    Finished dev [unoptimized + debuginfo] target(s) in 0.65s

发布并构建

以下段落摘抄自[1.3]

"当项目最终准备好发布时,可以使用 cargo build --release 来优化编译项目。这会在 target/release 而不是 target/debug 下生成可执行文件。这些优化可以让 Rust 代码运行的更快,不过启用这些优化也需要消耗更长的编译时间。这也就是为什么会有两种不同的配置:一种是为了开发,你需要经常快速重新构建;另一种是为用户构建最终程序,它们不会经常重新构建,并且希望程序运行得越快越好。如果你要对代码运行时间进行基准测试,请确保运行 cargo build --release 并使用 target/release 下的可执行文件进行测试。"