From 64246fdcc66aca5d931c7c097f8230f709ee2ee3 Mon Sep 17 00:00:00 2001 From: sunface Date: Thu, 17 Feb 2022 21:56:53 +0800 Subject: [PATCH] =?UTF-8?q?add=20cargo=E4=BD=BF=E7=94=A8=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- contents/SUMMARY.md | 36 +++++----- contents/cargo/build-js.md | 1 - contents/cargo/cache.md | 7 -- contents/cargo/cargo-toml-lock.md | 1 - contents/cargo/commands.md | 1 - contents/cargo/dependency.md | 6 -- contents/cargo/feature.md | 23 ------ contents/cargo/getting-started.md | 71 +++++++++++++++++++ contents/cargo/guide/dependencies.md | 60 ++++++++++++++++ contents/cargo/guide/download-package.md | 17 +++++ contents/cargo/guide/intro.md | 2 + contents/cargo/guide/package-layout.md | 47 ++++++++++++ contents/cargo/guide/why-exist.md | 32 +++++++++ contents/cargo/intro.md | 8 ++- contents/cargo/layout.md | 6 -- contents/cargo/manifest.md | 1 - contents/cargo/profile.md | 4 -- contents/cargo/reference/intro.md | 1 + .../cargo/reference/manifest/cargo-target.md | 1 + contents/cargo/reference/manifest/intro.md | 1 + .../cargo/reference/specify-deps/intro.md | 1 + .../reference/specify-deps/overriding.md | 1 + contents/cargo/version.md | 4 -- contents/cargo/workspace.md | 1 - 24 files changed, 259 insertions(+), 74 deletions(-) delete mode 100644 contents/cargo/build-js.md delete mode 100644 contents/cargo/cache.md delete mode 100644 contents/cargo/cargo-toml-lock.md delete mode 100644 contents/cargo/commands.md delete mode 100644 contents/cargo/dependency.md delete mode 100644 contents/cargo/feature.md create mode 100644 contents/cargo/getting-started.md create mode 100644 contents/cargo/guide/dependencies.md create mode 100644 contents/cargo/guide/download-package.md create mode 100644 contents/cargo/guide/intro.md create mode 100644 contents/cargo/guide/package-layout.md create mode 100644 contents/cargo/guide/why-exist.md delete mode 100644 contents/cargo/layout.md delete mode 100644 contents/cargo/manifest.md delete mode 100644 contents/cargo/profile.md create mode 100644 contents/cargo/reference/intro.md create mode 100644 contents/cargo/reference/manifest/cargo-target.md create mode 100644 contents/cargo/reference/manifest/intro.md create mode 100644 contents/cargo/reference/specify-deps/intro.md create mode 100644 contents/cargo/reference/specify-deps/overriding.md delete mode 100644 contents/cargo/version.md delete mode 100644 contents/cargo/workspace.md diff --git a/contents/SUMMARY.md b/contents/SUMMARY.md index 85d834fe..b312d86e 100644 --- a/contents/SUMMARY.md +++ b/contents/SUMMARY.md @@ -123,6 +123,19 @@ - [类似迭代器的Stream](tokio/stream.md)) - [优雅的关闭](tokio/graceful-shutdown.md) - [异步跟同步共存](tokio/bridging-with-sync.md) + +- [Cargo使用指南](cargo/intro.md) + - [上手使用](cargo/getting-started.md) + - [使用手册 doing](cargo/guide/intro.md) + - [为何会有Cargo](cargo/guide/why-exist.md) + - [下载并构建Package](cargo/guide/download-package.md) + - [添加依赖](cargo/guide/dependencies.md) + - [Package目录结构](cargo/guide/package-layout.md) + - [进阶参考 todo](cargo/reference/intro.md) + - [指定依赖项 todo](cargo/reference/specify-deps/intro.md) + - [依赖覆盖 todo](cargo/reference/specify-deps/overriding.md) + - [Cargo.toml格式讲解 todo](cargo/reference/manifest/intro.md) + - [修改默认的文件目录 todo](cargo/reference/manifest/cargo-target.md) - [易混淆概念解析](confonding/intro.md) - [切片和切片引用](confonding/slice.md) @@ -130,7 +143,7 @@ - [原生指针、引用和智能指针 todo](confonding/pointer.md) - [作用域、生命周期和 NLL todo](confonding/lifetime.md) - [move、Copy和Clone todo](confonding/move-copy.md) - + - [对抗编译检查 doing](fight-with-compiler/intro.md) - [幽灵数据(todo)](fight-with-compiler/phantom-data.md) - [生命周期](fight-with-compiler/lifetime/intro.md) @@ -158,26 +171,13 @@ - [Rust最佳实践 doing](practice/intro.md) - [日常开发三方库精选](practice/third-party-libs.md) - - [代码开发实践 todo](practice/best-pratice.md) - [命名规范](practice/naming.md) - - [日志 todo](practice/logs.md) + - [代码开发实践 todo](practice/best-pratice.md) + - [日志记录 todo](practice/logs.md) - [可观测性监控 todo](practice/observability.md) -- [如何实现一个链表 todo]() - -- [Cargo使用指南 todo](cargo/intro.md) - - [常用命令 todo](cargo/commands.md) - - [项目结构 todo](cargo/layout.md) - - [Cargo.toml和Cargo.lock todo](cargo/cargo-toml-lock.md) - - [依赖管理 todo](cargo/dependency.md) - - [构建缓存 todo](cargo/cache.md) - - [版本管理 todo](cargo/version.md) - - [工作空间 todo](cargo/workspace.md) - - [条件编译、条件依赖 todo](cargo/feature.md) - - [配置参数 todo](cargo/manifest.md) - - [自定义构建脚本 todo](cargo/build-js.md) - - [Cargo profile todo](cargo/profile.md) - + + - [Rust性能剖析 todo](profiling/intro.md) - [深入内存 todo](profiling/memory/intro.md) - [指针和引用 todo](profiling/memory/pointer-ref.md) diff --git a/contents/cargo/build-js.md b/contents/cargo/build-js.md deleted file mode 100644 index f24e5a30..00000000 --- a/contents/cargo/build-js.md +++ /dev/null @@ -1 +0,0 @@ -# 自定义构建脚本 diff --git a/contents/cargo/cache.md b/contents/cargo/cache.md deleted file mode 100644 index cc9d6053..00000000 --- a/contents/cargo/cache.md +++ /dev/null @@ -1,7 +0,0 @@ -# 构建缓存 - - -## cargo 下载卡住 -删除 ~/.cargo/.package-cache - -https://zhuanlan.zhihu.com/p/74875840 \ No newline at end of file diff --git a/contents/cargo/cargo-toml-lock.md b/contents/cargo/cargo-toml-lock.md deleted file mode 100644 index 77e1c3a0..00000000 --- a/contents/cargo/cargo-toml-lock.md +++ /dev/null @@ -1 +0,0 @@ -# Cargo.toml和Cargo.lock diff --git a/contents/cargo/commands.md b/contents/cargo/commands.md deleted file mode 100644 index aa1e2035..00000000 --- a/contents/cargo/commands.md +++ /dev/null @@ -1 +0,0 @@ -# 常用命令 diff --git a/contents/cargo/dependency.md b/contents/cargo/dependency.md deleted file mode 100644 index c823279c..00000000 --- a/contents/cargo/dependency.md +++ /dev/null @@ -1,6 +0,0 @@ -# 依赖管理 - - -## 依赖升级 - -Minor note about your second point: You can use cargo update to update versions of transitive dependencies in your Cargo.lock when applicable; the very nice cargo-edit crate provides a cargo upgrade command which does the same for your Cargo.toml. If you use VSCode, I can also recommend the "crates" extension which shows available updates inline in your Cargo.toml. \ No newline at end of file diff --git a/contents/cargo/feature.md b/contents/cargo/feature.md deleted file mode 100644 index 53ff2cc9..00000000 --- a/contents/cargo/feature.md +++ /dev/null @@ -1,23 +0,0 @@ -# 条件编译、条件依赖 - - -## 通过featre来实现不同的derive -比如有一个类型,我们希望在不同包引用它的时候,派生引用不同的特征,可以这么做: - -在`Cargo.toml`中定义新的`feature`: -```toml -[features] -sqlx = [] -``` - -在类型定义处: -```rust -#[cfg_attr(feature = "sqlx", derive(sqlx::Type)] -#[derive(Debug, PartialEq, Deserialize, Serialize, strum_macros::EnumString)] -pub enum Role {Owner,Admin,User,} -``` - -在希望派生`sqlx`的包: -```toml -your_shared_crate = { version = "0.0.1", features = ["sqlx"] } -``` \ No newline at end of file diff --git a/contents/cargo/getting-started.md b/contents/cargo/getting-started.md new file mode 100644 index 00000000..975c6fdb --- /dev/null +++ b/contents/cargo/getting-started.md @@ -0,0 +1,71 @@ +# 上手使用 +Cargo 会在安装 Rust 的时候一并进行安装,无需我们手动的操作执行,安装 Rust 参见[这里](https://course.rs/first-try/installation.html)。 + +在开始之前,先来明确一个名词: `Package`,由于 `Crate` 被翻译成包,因此 `Package` 再被翻译成包就很不合适。为此我们决定不对 `Package` 进行翻译,但是大家可以将其理解为软件包、项目或工程。 + +安装完成后,接下来使用 `Cargo` 来创建一个新的[二进制 Package](https://course.rs/basic/crate-module/crate.html),二进制意味着该 `Package` 可以作为一个服务运行或被编译成可执行文件运行。 + +```rust +$ cargo new hello_world +``` + +这里我们使用 `cargo new` 创建一个新的 Package ,事实上该命令等价于 `cargo new hello_world --bin`,`bin` 是 `binary` 的简写,代表着二进制程序,由于 `--bin` 是默认参数,因此可以对其进行省略。 + +创建成功后,先来看看 `Package` 的目录结构长啥样: +```shell +$ cd hello_world +$ tree . +. +├── Cargo.toml +└── src + └── main.rs + +1 directory, 2 files +``` + +这里有一个很显眼的文件 `Cargo.toml`,一看就知道它是 `Cargo` 使用的配置文件,这个关系类似于: `package.json` 是 `npm` 的配置文件。 +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2021" + +[dependencies] +``` + +以上就是 `Cargo.toml` 的全部内容,它被称之为清单( manifest ),包含了 `Cargo` 编译程序所需的所有元数据。 + +下面是 `src/main.rs` 的内容 : +```rust +fn main() { + println!("Hello, world!"); +} +``` + +可以看出 `Cargo` 还为我们自动生成了一个 `hello world` 程序,或者说[二进制包](https://course.rs/basic/crate-module/crate.html),对程序进行编译构建: +```shell +$ cargo build + Compiling hello_world v0.1.0 (file:///path/to/package/hello_world) +``` + +然后再运行编译出的二进制可执行文件: +```shell +$ ./target/debug/hello_world +Hello, world! +``` + +注意到路径中的 `debug` 了吗?它说明我们刚才的编译是 `Debug` 模式,该模式主要用于测试目的,如果想要进行生产编译,我们需要使用 `Release` 模式 `cargo build --release`,然后通过 `./target/release/hello_world` 运行。 + +除了上面的编译 + 运行方式外,在日常开发中,我们还可以使用一个简单的命令直接运行: +```shell +$ cargo run + Fresh hello_world v0.1.0 (file:///path/to/package/hello_world) + Running `target/hello_world` +Hello, world! +``` + +`cargo run` 会帮我们自动完成编译、运行的过程,当然,该命令也支持 `Release` 模式: `cargo run --release`。 + +> 如果你的程序在跑性能测试 benchmark,一定要使用 `Relase` 模式,因为该模式下,程序会做大量性能优化 + +在快速了解 `Cargo` 的使用方式后,下面,我们将正式进入 Cargo 的学习之旅。 \ No newline at end of file diff --git a/contents/cargo/guide/dependencies.md b/contents/cargo/guide/dependencies.md new file mode 100644 index 00000000..1a129035 --- /dev/null +++ b/contents/cargo/guide/dependencies.md @@ -0,0 +1,60 @@ +# 添加依赖 +[`crates.io`](https://crates.io) 是 Rust 社区维护的中心化 `package` 注册服务,用户可以在其中寻找和下载所需的 `package`。对于 `cargo` 来说,默认就是从这里下载依赖。 + +下面我们来添加一个 `time` 依赖包,若你的 `Cargo.toml` 文件中没有 `[dependencies]` 部分,就手动添加一个,然后添加目标包名和版本号: +```toml +[dependencies] +time = "0.1.12" +``` + +可以看到我们指定了 `time` 包的版本号 "0.1.12",关于版本号,实际上还有其它的指定方式,具体参见[指定依赖项](https://course.rs/cargo/reference/specify-deps/intro.html)章节。 + +如果想继续添加 `regexp` 包,只需在 `time` 包后面添加即可 : +```toml +[package] +name = "hello_world" +version = "0.1.0" +edition = "2021" + +[dependencies] +time = "0.1.12" +regex = "0.1.41" +``` + +此时,再通过运行 `cargo build` 来重新构建,首先 `Cargo` 会获取新的依赖以及依赖的依赖, 接着对它们进行编译并更新 `Cargo.lock`: +```shell +$ cargo build + Updating crates.io index + Downloading memchr v0.1.5 + Downloading libc v0.1.10 + Downloading regex-syntax v0.2.1 + Downloading memchr v0.1.5 + Downloading aho-corasick v0.3.0 + Downloading regex v0.1.41 + Compiling memchr v0.1.5 + Compiling libc v0.1.10 + Compiling regex-syntax v0.2.1 + Compiling memchr v0.1.5 + Compiling aho-corasick v0.3.0 + Compiling regex v0.1.41 + Compiling hello_world v0.1.0 (file:///path/to/package/hello_world) +``` + +在 `Cargo.lock` 中包含了我们项目使用的所有依赖的准确版本信息。这个非常重要,未来就算 `regexp` 的作者升级了该包,我们依然会下载 `Cargo.lock` 中的版本,而不是最新的版本,只有这样,才能保证项目依赖包不会莫名其妙的因为更新升级导致无法编译。 当然,你还可以使用 `cargo update` 来手动更新包的版本。 + +此时,就可以在 `src/main.rs` 中使用新引入的 `regexp` 包: +```rust +use regex::Regex; + +fn main() { + let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").unwrap(); + println!("Did our date match? {}", re.is_match("2014-01-01")); +} +``` + +运行后输出: +```shell +$ cargo run + Running `target/hello_world` +Did our date match? true +``` diff --git a/contents/cargo/guide/download-package.md b/contents/cargo/guide/download-package.md new file mode 100644 index 00000000..dd95cac1 --- /dev/null +++ b/contents/cargo/guide/download-package.md @@ -0,0 +1,17 @@ +# 下载并构建Package +如果看中 `Github` 上的某个开源 Rust 项目,那下载并构建它将是非常简单的。 + +```shell +$ git clone https://github.com/rust-lang/regex.git +$ cd regex +``` + +如上所示,直接从 `github` 上克隆下来想要的项目,然后使用 `cargo build` 进行构建即可: +```shell +$ cargo build + Compiling regex v1.5.0 (file:///path/to/package/regex) +``` + +该命令将下载相关的依赖库,等下载成功后,再对 `package` 和下载的依赖进行一同的编译构建。 + +这就是包管理工具的强大之处,`cargo build` 搞定一切,而背后隐藏的复杂配置、参数你都无需关心。 \ No newline at end of file diff --git a/contents/cargo/guide/intro.md b/contents/cargo/guide/intro.md new file mode 100644 index 00000000..a80bbd70 --- /dev/null +++ b/contents/cargo/guide/intro.md @@ -0,0 +1,2 @@ +# 使用手册 +在本章中,我们将学习 `Cargo` 的详细使用方式,例如 `Package` 的创建与管理、依赖拉取、`Package` 结构描述等。 \ No newline at end of file diff --git a/contents/cargo/guide/package-layout.md b/contents/cargo/guide/package-layout.md new file mode 100644 index 00000000..38f44c2a --- /dev/null +++ b/contents/cargo/guide/package-layout.md @@ -0,0 +1,47 @@ +# 标准的Package目录结构 +一个典型的 `Package` 目录结构如下: +```shell +. +├── Cargo.lock +├── Cargo.toml +├── src/ +│ ├── lib.rs +│ ├── main.rs +│ └── bin/ +│ ├── named-executable.rs +│ ├── another-executable.rs +│ └── multi-file-executable/ +│ ├── main.rs +│ └── some_module.rs +├── benches/ +│ ├── large-input.rs +│ └── multi-file-bench/ +│ ├── main.rs +│ └── bench_module.rs +├── examples/ +│ ├── simple.rs +│ └── multi-file-example/ +│ ├── main.rs +│ └── ex_module.rs +└── tests/ + ├── some-integration-tests.rs + └── multi-file-test/ + ├── main.rs + └── test_module.rs +``` + +这也是 `Cargo` 推荐的目录结构,解释如下: + +- `Cargo.toml` 和 `Cargo.lock` 保存在 `package` 根目录下 +- 源代码放在 `src` 目录下 +- 默认的 `lib` 包根是 `src/lib.rs` +- 默认的二进制包根是 `src/main.rs` + - 其它二进制包根放在 `src/bin/` 目录下 +- 基准测试 benchmark 放在 `benches` 目录下 +- 示例代码放在 `examples` 目录下 +- 集成测试代码放在 `tests` 目录下 + + +关于 Rust 中的包和模块,[之前的章节](https://course.rs/basic/crate-module/intro.html)有更详细的解释。 + +这里的一些目录配置还能通过配置文件来修改,详情参见本章的后续章节[修改默认的文件目录](https://course.rs/cargo/reference/manifest/cargo-target.html) \ No newline at end of file diff --git a/contents/cargo/guide/why-exist.md b/contents/cargo/guide/why-exist.md new file mode 100644 index 00000000..fcb2315a --- /dev/null +++ b/contents/cargo/guide/why-exist.md @@ -0,0 +1,32 @@ +# 为何会有Cargo +根据之前学习的知识,Rust 有两种类型的包: `lib` 包和二进制包,前者是俗称的依赖包,用于被其它包所引入,而后者是一个应用服务,可以编译成二进制可执行文件进行运行。 + +包是通过 Rust 编译器 `rustc` 进行编译的: +```rust +$ rustc hello.rs +$ ./hello +Hello, world! +``` + +上面我们直接使用 `rustc` 对二进制包 `hello.rs` 进行编译,生成二进制可执行文件 `hello`,并对其进行运行。 + +上面的方式虽然简单,但是有几个问题: + +- 必须要指定文件名编译,当 package 复杂后,这种编译方式也随之更加复杂 +- 如果要指定编译参数,情况将更加复杂 + +最关键的是,外部依赖库的引入也将是一个大问题。大部分实际的项目都有不少依赖包,而这些依赖包又间接的依赖了新的依赖包,在这种复杂情况下,如何管理依赖包及其版本也成为一个相当棘手的问题。 + +正是因为这些原因,与其使用 `rustc` ,我们可以使用一个强大的包管理工具来解决问题:欢迎 `Cargo` 闪亮登场。 + +## Cargo +`Cargo` 解决了之前描述的所有问题,同时它保证了每次重复的构建都不会改变上一次构建的结果,这背后是通过完善且强大的依赖包版本管理来实现的。 + +总之,`Cargo` 为了实现目标,做了四件事: + +- 引入两个元数据文件,包含 `package` 的方方面面信息: `Cargo.toml` 和 `Cargo.lock` +- 获取和构建 `package` 的依赖,例如 `Cargo.toml` 中的依赖包版本描述,以及从 `crates.io` 下载包 +- 调用 `rustc` (或其它编译器) 并使用的正确的参数来构建 `package`,例如 `cargo build` +- 引入一些惯例,让 `package` 的使用更加简单 + +毫不夸张的说,得益于 `Cargo` 的标准化,只要你使用它构建过一个项目,那构建其它使用 `Cargo` 的项目,也将不存在任何困难。 \ No newline at end of file diff --git a/contents/cargo/intro.md b/contents/cargo/intro.md index 3b21ee2f..4eb2af5a 100644 --- a/contents/cargo/intro.md +++ b/contents/cargo/intro.md @@ -1,2 +1,8 @@ -# cargo +# Cargo 使用指南 +Rust 语言的名气之所以这么大,保守估计 `Cargo` 的贡献就占了三分之一。 +`Cargo` 是包管理工具,可以用于依赖包的下载、编译、更新、分发等,与 `Cargo` 一样有名的还有 [`crates.io`](https://crates.io),它是社区提供的包注册中心:用户可以将自己的包发布到该注册中心,然后其它用户通过注册中心引入该包。 + +> 本章内容是基于 [Cargo Book](https://doc.rust-lang.org/stable/cargo/index.html) 翻译,并做了一些内容优化和目录组织上的调整 + + \ No newline at end of file diff --git a/contents/cargo/layout.md b/contents/cargo/layout.md deleted file mode 100644 index 820653bc..00000000 --- a/contents/cargo/layout.md +++ /dev/null @@ -1,6 +0,0 @@ -# 项目结构 - - -## main函数的正确位置 - -目前发现部分人会搞不懂main函数应该放在哪个文件中,结果导致编译器报错:找不到main函数 \ No newline at end of file diff --git a/contents/cargo/manifest.md b/contents/cargo/manifest.md deleted file mode 100644 index dd3071df..00000000 --- a/contents/cargo/manifest.md +++ /dev/null @@ -1 +0,0 @@ -# manifest \ No newline at end of file diff --git a/contents/cargo/profile.md b/contents/cargo/profile.md deleted file mode 100644 index 7f6d100d..00000000 --- a/contents/cargo/profile.md +++ /dev/null @@ -1,4 +0,0 @@ -# Cargo profile - - -## custom profiles (rust 1.57.0) diff --git a/contents/cargo/reference/intro.md b/contents/cargo/reference/intro.md new file mode 100644 index 00000000..289ddf23 --- /dev/null +++ b/contents/cargo/reference/intro.md @@ -0,0 +1 @@ +# 进阶参考 diff --git a/contents/cargo/reference/manifest/cargo-target.md b/contents/cargo/reference/manifest/cargo-target.md new file mode 100644 index 00000000..99f71c63 --- /dev/null +++ b/contents/cargo/reference/manifest/cargo-target.md @@ -0,0 +1 @@ +# 修改默认的文件目录 diff --git a/contents/cargo/reference/manifest/intro.md b/contents/cargo/reference/manifest/intro.md new file mode 100644 index 00000000..e4629663 --- /dev/null +++ b/contents/cargo/reference/manifest/intro.md @@ -0,0 +1 @@ +# Cargo.toml格式讲解 diff --git a/contents/cargo/reference/specify-deps/intro.md b/contents/cargo/reference/specify-deps/intro.md new file mode 100644 index 00000000..7afabaf5 --- /dev/null +++ b/contents/cargo/reference/specify-deps/intro.md @@ -0,0 +1 @@ +# 指定依赖项 diff --git a/contents/cargo/reference/specify-deps/overriding.md b/contents/cargo/reference/specify-deps/overriding.md new file mode 100644 index 00000000..05831572 --- /dev/null +++ b/contents/cargo/reference/specify-deps/overriding.md @@ -0,0 +1 @@ +# 依赖覆盖 diff --git a/contents/cargo/version.md b/contents/cargo/version.md deleted file mode 100644 index 12311ff5..00000000 --- a/contents/cargo/version.md +++ /dev/null @@ -1,4 +0,0 @@ -# 版本管理 - - -Rust允许同一个包的多个API不兼容的版本共存,因此会导致问题:https://www.reddit.com/r/rust/comments/rlil11/simple_crud_web_api_with_actix_getting_error/ \ No newline at end of file diff --git a/contents/cargo/workspace.md b/contents/cargo/workspace.md deleted file mode 100644 index b0c4db71..00000000 --- a/contents/cargo/workspace.md +++ /dev/null @@ -1 +0,0 @@ -# 工作空间