check to ch14-05

pull/276/head
KaiserY 6 years ago
parent d11ba9796e
commit 19e97f6c36

@ -1,10 +1,10 @@
# 进一步认识 Cargo 和 Crates.io
> [ch14-00-more-about-cargo.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-00-more-about-cargo.md)
> [ch14-00-more-about-cargo.md](https://github.com/rust-lang/book/blob/master/src/ch14-00-more-about-cargo.md)
> <br>
> commit ff93f82ff63ade5a352d9ccc430945d4ec804cdf
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
目前为止我们只使用过 Cargo 构建、运行和测试代码的最基本功能,不过它还可以做到更多。这里我们将了解一些 Cargo 其他更为高级的功能,他们将展示如何:
目前为止我们只使用过 Cargo 构建、运行和测试代码这些最基本的功能,不过它还可以做到更多。本章会讨论 Cargo 其他一些更为高级的功能,我们将展示如何:
* 使用发布配置来自定义构建
* 将库发布到 [crates.io](https://crates.io)<!-- ignore -->
@ -12,4 +12,4 @@
* 从 [crates.io](https://crates.io)<!-- ignore --> 安装二进制文件
* 使用自定义的命令来扩展 Cargo
相比本章能够涉及的工作 Cargo 甚至还可以做到更多,关于其功能的全部解释,请查看 [文档](http://doc.rust-lang.org/cargo/)
相比本章能够涉及的工作 Cargo 甚至还可以做到更多,关于其功能的全部解释,请查看 [文档](http://doc.rust-lang.org/cargo/)

@ -1,14 +1,14 @@
## 采用发布配置自定义构建
> [ch14-01-release-profiles.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-01-release-profiles.md)
> [ch14-01-release-profiles.md](https://github.com/rust-lang/book/blob/master/src/ch14-01-release-profiles.md)
> <br>
> commit ff93f82ff63ade5a352d9ccc430945d4ec804cdf
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
在 Rust 中 **发布配置***release profiles*)是预定义的、可定制的带有不同选项的配置,他们允许程序员更多的控制代码编译的多种选项。每一个配置都彼此相互独立。
在 Rust 中 **发布配置***release profiles*)是预定义的、可定制的带有不同选项的配置,他们允许程序员更灵活地控制代码编译的多种选项。每一个配置都彼此相互独立。
Cargo 有两个主要的配置:运行 `cargo build` 时采用的 `dev` 配置和运行 `cargo build --release``release` 配置。`dev` 配置被定义为开发时的好的默认配置,`release` 配置则有着良好的发布构建的默认配置。
我们应该很熟悉这些配置名称因为他们出现在构建的输出中,这会展示构建所使用的配置
这些配置名称可能很眼熟,因为它们出现在构建的输出中
```text
$ cargo build
@ -19,7 +19,7 @@ $ cargo build --release
构建输出中的 `dev``release` 表明编译器在使用不同的配置。
Cargo 对每一个配置都有默认设置,当项目的 *Cargo.toml* 文件中没有任何 `[profile.*]` 部分的时候。通过增加任何希望定制的配置对应的 `[profile.*]` 部分,我们可以选择覆盖任意默认设置的子集。例如,如下是 `dev``release` 配置的 `opt-level` 设置的默认值:
当项目的 *Cargo.toml* 文件中没有任何 `[profile.*]` 部分的时候Cargo 会对每一个配置都采用默认设置。通过增加任何希望定制的配置对应的 `[profile.*]` 部分,我们可以选择覆盖任意默认设置的子集。例如,如下是 `dev``release` 配置的 `opt-level` 设置的默认值:
<span class="filename">文件名: Cargo.toml</span>

@ -1,24 +1,23 @@
## 将 crate 发布到 Crates.io
> [ch14-02-publishing-to-crates-io.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-02-publishing-to-crates-io.md)
> [ch14-02-publishing-to-crates-io.md](https://github.com/rust-lang/book/blob/master/src/ch14-02-publishing-to-crates-io.md)
> <br>
> commit ff93f82ff63ade5a352d9ccc430945d4ec804cdf
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
我们曾经在项目中使用 [crates.io](https://crates.io)<!-- ignore --> 上的包作为依赖,不过你也可以通过发布自己的包来向它人分享代码。[crates.io](https://crates.io)<!-- ignore --> 用来分发包的源代码,所以它主要托管开源代码。
Rust 和 Cargo 有一些帮助它人更方便找到和使用你发布的包的功能。我们将介绍一些这样的功能,接着讲到如何发布一个包。
### 编写有用的文档注释
准确的包文档有助于其他用户理解如何以及何时使用他们,所以花一些时间编写文档是值得的。第三章中我们讨论了如何使用 `//` 注释 Rust 代码。Rust 也有特定的用于文档的注释类型,通常被称为 **文档注释***documentation comments*),他们会生成 HTML 文档。这些 HTML 展示公有 API 文档注释的内容,他们意在让对库感兴趣的程序员理解如何 **使用** 这个 crate而不是它是如何被 **实现** 的。
准确的包文档有助于其他用户理解如何以及何时使用他们,所以花一些时间编写文档是值得的。第三章中我们讨论了如何使用两斜杠 `//` 注释 Rust 代码。Rust 也有特定的用于文档的注释类型,通常被称为 **文档注释***documentation comments*),他们会生成 HTML 文档。这些 HTML 展示公有 API 文档注释的内容,他们意在让对库感兴趣的程序员理解如何 **使用** 这个 crate而不是它是如何被 **实现** 的。
文档注释使用 `///` 而不是 `//` 并支持 Markdown 注解来格式化文本。文档注释就位于需要文档的项的之前。示例 14-1 展示了一个 `my_crate` crate 中 `add_one` 函数的文档注释:
文档注释使用三斜杠 `///` 而不是两斜杆并支持 Markdown 注解来格式化文本。文档注释就位于需要文档的项的之前。示例 14-1 展示了一个 `my_crate` crate 中 `add_one` 函数的文档注释:
<span class="filename">文件名: src/lib.rs</span>
```rust,ignore
/// Adds one to the number given.
/// 将给定的数字加一
///
/// # Examples
///
@ -34,7 +33,7 @@ pub fn add_one(x: i32) -> i32 {
<span class="caption">示例 14-1一个函数的文档注释</span>
这里,我们提供了一个 `add_one` 函数工作的描述,接着开始了一个标题为 “Examples” 的部分,和展示如何使用 `add_one` 函数的代码。可以运行 `cargo doc` 来生成这个文档注释的 HTML 文档。这个命令运行由 Rust 分发的工具 `rustdoc` 并将生成的 HTML 文档放入 *target/doc* 目录。
这里,我们提供了一个 `add_one` 函数工作的描述,接着开始了一个标题为 `Examples` 的部分,和展示如何使用 `add_one` 函数的代码。可以运行 `cargo doc` 来生成这个文档注释的 HTML 文档。这个命令运行由 Rust 分发的工具 `rustdoc` 并将生成的 HTML 文档放入 *target/doc* 目录。
为了方便起见,运行 `cargo doc --open` 会构建当前 crate 文档(同时还有所有 crate 依赖的文档)的 HTML 并在浏览器中打开。导航到 `add_one` 函数将会发现文档注释的文本是如何渲染的,如图 14-1 所示:
@ -78,10 +77,10 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```rust,ignore
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.
//! `my_crate` 是一个使得特定计算更方便的
//! 工具集合
/// Adds one to the number given.
/// 将给定的数字加一。
// --snip--
```
@ -99,30 +98,30 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
### 使用 `pub use` 导出合适的公有 API
第七章介绍了如何使用 `mod` 关键字来将代码组织进模块中,如何使用 `pub` 关键字将项变为公有,和如何使用 `use` 关键字将项引入作用域。然而对你开发来说很有道理的结果可能对用户来说就不太方便了。你可能希望将结构组织进有多个层次的层级中,不过想要使用被定义在很深层级中的类型的人可能很难发现这些类型是否存在。他们也可能会厌烦 `use my_crate::some_module::another_module::UsefulType;` 而不是 `use my_crate::UsefulType;` 来使用类型。
第七章介绍了如何使用 `mod` 关键字来将代码组织进模块中,如何使用 `pub` 关键字将项变为公有,和如何使用 `use` 关键字将项引入作用域。然而对你开发来说很有道理的结果可能对用户来说就不太方便了。你可能希望将结构组织进有多个层次的层级中,不过想要使用被定义在很深层级中的类型的人可能很难发现这些类型是否存在。他们也可能会厌烦使用 `use my_crate::some_module::another_module::UsefulType;` 而不是 `use my_crate::UsefulType;` 来使用类型。
公有 API 的结构是你发布 crate 时主要需要考虑的。crate 用户没有你那么熟悉其结构,并且如果模块层级过大他们可能会难以找到所需的部分。
好消息是,如果结果对于用户来说 **不是** 很方便,你也无需重新安排内部组织:你可以选择使用 `pub use` 重导出re-export项来使公有结构不同于私有结构。重导出获取位于一个位置的公有项并将其公开到另一个位置好像它就定义在这个新位置一样。
例如,假设我们创建了一个模块化充满艺术化气息的库 `art`。在这个库中是一个包含两个枚举 `PrimaryColor``SecondaryColor` 的模块 `kinds`,以及一个包含函数 `mix` 的模块 `utils`,如示例 14-3 所示:
例如,假设我们创建了一个模块化充满艺术化气息的库 `art`。在这个库中是一个包含两个枚举 `PrimaryColor``SecondaryColor` 的模块 `kinds`,以及一个包含函数 `mix` 的模块 `utils`,如示例 14-3 所示:
<span class="filename">文件名: src/lib.rs</span>
```rust,ignore
//! # Art
//!
//! A library for modeling artistic concepts.
//! 一个模块化的充满艺术化气息的库。
pub mod kinds {
/// The primary colors according to the RYB color model.
/// 采用 RGB 色彩模式的主要颜色。
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
/// 采用 RGB 色彩模式的次要颜色。
pub enum SecondaryColor {
Orange,
Green,
@ -133,8 +132,8 @@ pub mod kinds {
pub mod utils {
use kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
/// 等量的混合两个主要颜色
/// 来创建一个次要颜色。
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
}
@ -149,15 +148,13 @@ pub mod utils {
<span class="caption">图 14-3包含 `kinds``utils` 模块的库 `art` 的文档首页</span>
注意 `PrimaryColor``SecondaryColor` 类型没有在首页中列出,`mix` 函数也。必须点击 `kinds``utils` 才能看到他们。
注意 `PrimaryColor``SecondaryColor` 类型没有在首页中列出,`mix` 函数也没有。必须点击 `kinds``utils` 才能看到他们。
另一个依赖这个库的 crate 需要 `use` 语句来导入 `art` 中的项,这包含指定其当前定义的模块结构。示例 14-4 展示了一个使用 `art` crate 中 `PrimaryColor``mix` 项的 crate 的例子:
<span class="filename">文件名: src/main.rs</span>
```rust,ignore
extern crate art;
use art::kinds::PrimaryColor;
use art::utils::mix;
@ -179,7 +176,7 @@ fn main() {
```rust,ignore
//! # Art
//!
//! A library for modeling artistic concepts.
//! 一个模块化的充满艺术化气息的库。
pub use kinds::PrimaryColor;
pub use kinds::SecondaryColor;
@ -202,13 +199,11 @@ pub mod utils {
<span class="caption">图 14-10`art` 文档的首页,这里列出了重导出的项</span>
`art` crate 的用户仍然可以看见和选择使用示例 14-3 中的内部结构,或者可以使用示例 14-4 中更为方便的结构,如示例 14-6 所示:
`art` crate 的用户仍然可以看见和选择使用示例 14-4 中的内部结构,或者可以使用示例 14-5 中更为方便的结构,如示例 14-6 所示:
<span class="filename">文件名: src/main.rs</span>
```rust,ignore
extern crate art;
use art::PrimaryColor;
use art::mix;
@ -225,7 +220,7 @@ fn main() {
### 创建 Crates.io 账号
在你可以发布任何 crate 之前,需要在 [crates.io](https://crates.io)<!-- ignore --> 上注册账号并获取一个 API token。为此访问位于 [crates.io](https://crates.io)<!-- ignore --> 的首页并使用 GitHub 账号登陆————目前 GitHub 账号是必须的,不过将来该网站可能会支持其他创建账号的方法。一旦登陆之后,查看位于 [https://crates.io/me/](https://crates.io/me/)<!-- ignore --> 的账户设置页面并获取 API token。接着使用该 API token 运行 `cargo login` 命令,像这样:
在你可以发布任何 crate 之前,需要在 [crates.io](https://crates.io)<!-- ignore --> 上注册账号并获取一个 API token。为此访问位于 [crates.io](https://crates.io)<!-- ignore --> 的首页并使用 GitHub 账号登陆。(目前 GitHub 账号是必须的,不过将来该网站可能会支持其他创建账号的方法)一旦登陆之后,查看位于 [https://crates.io/me/](https://crates.io/me/)<!-- ignore --> 的账户设置页面并获取 API token。接着使用该 API token 运行 `cargo login` 命令,像这样:
```text
$ cargo login abcdefghijklmnopqrstuvwxyz012345
@ -259,7 +254,10 @@ error: api errors: missing or empty metadata fields: description, license.
这是因为我们缺少一些关键信息:关于该 crate 用途的描述和用户可能在何种条款下使用该 crate 的 license。为了修正这个错误需要在 *Cargo.toml* 中引入这些信息。
描述通常是一两句话,因为它会出现在 crate 的搜索结果中和 crate 页面里。对于 `license` 字段,你需要一个 **license 标识符值***license identifier value*。Linux 基金会位于 *http://spdx.org/licenses/* 的 Software Package Data Exchange (SPDX) 列出了可以使用的标识符。例如,为了指定 crate 使用 MIT License增加 `MIT` 标识符:
描述通常是一两句话,因为它会出现在 crate 的搜索结果中和 crate 页面里。对于 `license` 字段,你需要一个 **license 标识符值***license identifier value*)。[Linux 基金会 的 Software Package Data
Exchange (SPDX)][spdx] 列出了可以使用的标识符。例如,为了指定 crate 使用 MIT License增加 `MIT` 标识符:
[spdx]: http://spdx.org/licenses/
<span class="filename">文件名: Cargo.toml</span>
@ -271,7 +269,7 @@ license = "MIT"
如果你希望使用不存在于 SPDX 的 license则需要将 license 文本放入一个文件,将该文件包含进项目中,接着使用 `license-file` 来指定文件名而不是使用 `license` 字段。
关于项目所适用的 license 指导超出了本书的范畴。很多 Rust 社区成员选择与 Rust 自身相同的 license这是一个双许可的 `MIT OR Apache-2.0` ———— 这展示了也可以通过 `OR` 来分隔来为项目指定多个 license 标识符。
关于项目所适用的 license 指导超出了本书的范畴。很多 Rust 社区成员选择与 Rust 自身相同的 license这是一个双许可的 `MIT OR Apache-2.0`。这个实践展示了也可以通过 `OR` 分隔为项目指定多个 license 标识符。
那么,有了唯一的名称、版本号、由 `cargo new` 新建项目时增加的作者信息、描述和所选择的 license已经准备好发布的项目的 *Cargo.toml* 文件可能看起来像这样:

@ -1,12 +1,14 @@
## Cargo 工作空间
> [ch14-03-cargo-workspaces.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-03-cargo-workspaces.md)
> [ch14-03-cargo-workspaces.md](https://github.com/rust-lang/book/blob/master/src/ch14-03-cargo-workspaces.md)
> <br>
> commit a59537604248f2970e0831d5ead9f6fac2cdef84
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
第十二章中,我们构建一个包含二进制 crate 和库 crate 的包。你可能会发现,随着项目开发的深入,库 crate 持续增大,而你希望将其进一步拆分成多个库 crate。对于这种情况Cargo 提供了一个叫 **工作空间***workspaces*)的功能,它可以帮助我们管理多个相关的协同开发的包。
**工作空间** 是一系列共享同样的 *Cargo.lock* 和输出目录的包。让我们使用工作空间创建一个项目,这里采用常见的代码这样就可以关注工作空间的结构了。有多种组织工作空间的方式;我们将展示一个常用方法。我们的工作空间有一个二进制项目和两个库。二进制项目会提供作为命令行工具的主要功能,它会依赖另两个库。一个库会提供 `add_one` 方法而第二个会提供 `add_two` 方法。这三个 crate 将会是相同工作空间的一部分。让我们以新建工作空间目录开始:
### 创建工作空间
**工作空间** 是一系列共享同样的 *Cargo.lock* 和输出目录的包。让我们使用工作空间创建一个项目 —— 这里采用常见的代码以便可以关注工作空间的结构。有多种组织工作空间的方式;我们将展示一个常用方法。我们的工作空间有一个二进制项目和两个库。二进制项目会提供主要功能,并会依赖另两个库。一个库会提供 `add_one` 方法而第二个会提供 `add_two` 方法。这三个 crate 将会是相同工作空间的一部分。让我们以新建工作空间目录开始:
```text
$ mkdir add
@ -28,7 +30,7 @@ members = [
接下来,在 *add* 目录运行 `cargo new` 新建 `adder` 二进制 crate
```text
$ cargo new --bin adder
$ cargo new adder
Created binary (application) `adder` project
```
@ -64,7 +66,7 @@ members = [
接着新生成一个叫做 `add-one` 的库:
```text
$ cargo new add-one
$ cargo new add-one --lib
Created library `add-one` project
```
@ -111,7 +113,7 @@ add-one = { path = "../add-one" }
<span class="filename">文件名: adder/src/main.rs</span>
```rust,ignore
extern crate add_one;
use add_one;
fn main() {
let num = 10;
@ -154,7 +156,7 @@ Hello, world! 10 plus one is 11!
rand = "0.3.14"
```
现在就可以在 *add-one/src/lib.rs* 中增加 `extern crate rand;` 了,接着在 *add* 目录运行 `cargo build` 构建整个工作空间就会引入并编译 `rand` crate
现在就可以在 *add-one/src/lib.rs* 中增加 `use rand;` 了,接着在 *add* 目录运行 `cargo build` 构建整个工作空间就会引入并编译 `rand` crate
```text
$ cargo build
@ -167,7 +169,7 @@ $ cargo build
Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs
```
现在顶级的 *Cargo.lock* 包含了 `add-one``rand` 依赖的信息。然而,即使 `rand` 被用于工作空间的某处,也不能在其他 crate 中使用它,除非也在他们的 *Cargo.toml* 中加入 `rand`。例如,如果在顶级的 `adder` crate 的 *adder/src/main.rs* 中增加 `extern crate rand;`,会得到一个错误:
现在顶级的 *Cargo.lock* 包含了 `add-one``rand` 依赖的信息。然而,即使 `rand` 被用于工作空间的某处,也不能在其他 crate 中使用它,除非也在他们的 *Cargo.toml* 中加入 `rand`。例如,如果在顶级的 `adder` crate 的 *adder/src/main.rs* 中增加 `use rand;`,会得到一个错误:
```text
$ cargo build
@ -176,7 +178,7 @@ error: use of unstable library feature 'rand': use `rand` from crates.io (see
issue #27703)
--> adder/src/main.rs:1:1
|
1 | extern crate rand;
1 | use rand;
```
为了修复这个错误,修改顶级 `adder` crate 的 *Cargo.toml* 来表明 `rand` 也是这个 crate 的依赖。构建 `adder` crate 会将 `rand` 加入到 *Cargo.lock*`adder` 的依赖列表中,但是这并不会下载 `rand` 的额外拷贝。Cargo 确保了工作空间中任何使用 `rand` 的 crate 都采用相同的版本。在整个工作空间中使用相同版本的 `rand` 节省了空间,因为这样就无需多个拷贝并确保了工作空间中的 crate 将是相互兼容的。
@ -257,4 +259,4 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
现在尝试以类似 `add-one` crate 的方式向工作空间增加 `add-two` crate 来作为更多的练习!
随着项目增长,考虑使用工作空间:每一个更小的组件比一大块代码要容易理解。将 crate 保持在工作空间中更易于协调他们的改变,如果他们一起运行并经常需要同时被修改的话
随着项目增长,考虑使用工作空间:每一个更小的组件比一大块代码要容易理解。如果它们经常需要同时被修改的话,将 crate 保持在工作空间中更易于协调他们的改变。

@ -1,10 +1,10 @@
## 使用 `cargo install` 从 Crates.io 安装二进制文件
> [ch14-04-installing-binaries.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-04-installing-binaries.md)
> [ch14-04-installing-binaries.md](https://github.com/rust-lang/book/blob/master/src/ch14-04-installing-binaries.md)
> <br>
> commit ff93f82ff63ade5a352d9ccc430945d4ec804cdf
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
`cargo install` 命令用于在本地安装和使用二进制 crate。它并不打算替换系统中的包它意在作为一个方便 Rust 开发者们安装其他人已经在 [crates.io](https://crates.io)<!-- ignore --> 上共享的工具的手段。只有拥有二进制目标文件的包能够被安装。二进制目标文件是在 crate 有 *src/main.rs* 或者其他指定为二进制文件时所创建的可执行程序,这不同于自身不能执行但适合包含在其他程序中的库目标文件。通常 crate 的 *README* 文件中有该 crate 是库、二进制目标还是两者都是的信息。
`cargo install` 命令用于在本地安装和使用二进制 crate。它并不打算替换系统中的包它意在作为一个方便 Rust 开发者们安装其他人已经在 [crates.io](https://crates.io)<!-- ignore --> 上共享的工具的手段。只有拥有二进制目标文件的包能够被安装。**二进制目标** 文件是在 crate 有 *src/main.rs* 或者其他指定为二进制文件时所创建的可执行程序,这不同于自身不能执行但适合包含在其他程序中的库目标文件。通常 crate 的 *README* 文件中有该 crate 是库、二进制目标还是两者都是的信息。
所有来自 `cargo install` 的二进制文件都安装到 Rust 安装根目录的 *bin* 文件夹中。如果你使用 *rustup.rs* 安装的 Rust 且没有自定义任何配置,这将是 `$HOME/.cargo/bin`。确保将这个目录添加到 `$PATH` 环境变量中就能够运行通过 `cargo install` 安装的程序了。

@ -1,8 +1,8 @@
## Cargo 自定义扩展命令
> [ch14-05-extending-cargo.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch14-05-extending-cargo.md)
> [ch14-05-extending-cargo.md](https://github.com/rust-lang/book/blob/master/src/ch14-05-extending-cargo.md)
> <br>
> commit ff93f82ff63ade5a352d9ccc430945d4ec804cdf
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
Cargo 被设计为可以通过新的子命令而无须修改 Cargo 自身来进行扩展。如果 `$PATH` 中有类似 `cargo-something` 的二进制文件,就可以通过 `cargo something` 来像 Cargo 子命令一样运行它。像这样的自定义命令也可以运行 `cargo --list` 来展示出来。能够通过 `cargo install` 向 Cargo 安装扩展并可以如内建 Cargo 工具那样运行他们是 Cargo 设计上的一个非常方便的优点!

Loading…
Cancel
Save