You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
625 lines
23 KiB
625 lines
23 KiB
1 year ago
|
# 14 关于 Cargo 和 Crates.io 的更多内容
|
||
|
|
||
|
[Cargo](https://doc.rust-lang.org/cargo/) 的一些更高级的功能:
|
||
|
|
||
|
- 通过发布配置文件自定义您的构建过程
|
||
|
- 在 crates.io 上发布库
|
||
|
- 使用工作区组织大型项目
|
||
|
- 从 crates.io 安装二进制文件
|
||
|
- 使用自定义命令扩展 Cargo
|
||
|
|
||
|
## 自定义release配置文件
|
||
|
|
||
|
在 Rust 中,发布配置是预定义的可自定义配置文件,具有不同的配置,允许程序员更好地控制编译代码的各种选项。每个配置文件都是独立配置的。
|
||
|
|
||
|
Cargo 有两个主要的配置文件:当运行 `cargo build` 时使用的 **dev** 配置文件和当运行 `cargo build --release` 时使用的 **release** 配置文件。dev 配置文件为开发环境提供了良好的默认设置,而 release 配置文件则为发布构建提供了良好的默认设置。
|
||
|
|
||
|
![image-20230421113935081](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230421113935081.png)
|
||
|
|
||
|
|
||
|
|
||
|
`dev` 和 `release` 是编译器使用的不同配置文件。Cargo 为每个配置文件都有默认设置,当项目的 `Cargo.toml` 文件中没有明确添加任何 `[profile.*]` 部分时,这些设置会**自动应用**。通过为您想要自定义的任何配置文件添加 `[profile.*]` 部分,可以覆盖默认设置的任何子集。例如,下面是 `dev` 和 `release` 配置文件中 `opt-level` 设置的默认值:
|
||
|
|
||
|
```rust
|
||
|
[profile.dev]
|
||
|
opt-level = 0
|
||
|
|
||
|
[profile.release]
|
||
|
opt-level = 3
|
||
|
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
覆盖`dev`默认设置:
|
||
|
|
||
|
![image-20230421161039703](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230421161039703.png)
|
||
|
|
||
|
|
||
|
|
||
|
### opt-level
|
||
|
|
||
|
`opt-level` 是 Rust 编译器中一个重要的优化选项,用于控制生成的代码的优化级别。`opt-level` 的值可以是 0 到 3,分别代表不同的优化级别:
|
||
|
|
||
|
- `opt-level = 0`:不进行优化。生成的代码更容易调试,但运行速度会变慢。
|
||
|
- `opt-level = 1`:启用一些基本的优化,例如删除不可达代码。生成的代码仍然可以很好地调试,但运行速度比 `opt-level = 0` 更快。
|
||
|
- `opt-level = 2`:启用更多的优化,例如内联函数和循环展开。生成的代码比 `opt-level = 1` 更快,但可能更难以调试。
|
||
|
- `opt-level = 3`:启用所有优化。生成的代码运行速度最快,但可能更难以调试。
|
||
|
|
||
|
在 `dev` 配置文件中,`opt-level` 的默认值为 `0`,这意味着生成的代码更容易调试。而在 `release` 配置文件中,`opt-level` 的默认值为 `3`,这意味着生成的代码运行速度最快,但可能更难以调试。可以根据具体情况,自定义不同的 `opt-level` 值,以平衡生成的代码的调试性能和运行速度。[相关文档。](https://doc.rust-lang.org/cargo/reference/profiles.html)
|
||
|
|
||
|
|
||
|
|
||
|
## 发布Crate到Crate.io
|
||
|
|
||
|
### 提供有用的文档注释
|
||
|
|
||
|
文档注释使用三个斜杠,///,而不是两个,并支持Markdown符号来格式化文本。将文档注释放在他们要记录的项目的前面。它将生成HTML文档。
|
||
|
|
||
|
![image-20230423094431419](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423094431419.png)
|
||
|
|
||
|
|
||
|
|
||
|
生成 HTML 文档命令:
|
||
|
|
||
|
```rust
|
||
|
cargo doc // 从文档注释生成HTML文档。 生成位置:target/doc
|
||
|
cargo doc --open // 构建HTML,并在web浏览器中打开结果
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
HTML 界面:
|
||
|
|
||
|
![image-20230423101523963](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423101523963.png)
|
||
|
|
||
|
|
||
|
|
||
|
#### 常用文档注释
|
||
|
|
||
|
- Panics:这个部分描述了函数在何种情况下会 panic。如果一个函数可能导致程序 panic,那么调用该函数的用户需要确保不会出现这些情况。
|
||
|
- Errors:如果一个函数返回一个 Result 类型,那么这个部分描述了可能发生的错误以及导致这些错误的条件。这有助于用户编写处理不同错误类型的代码。
|
||
|
- Safety:如果一个函数是不安全的,那么这个部分需要解释为什么这个函数是不安全的,并列出用户需要遵守的不变量。
|
||
|
|
||
|
这些部分不是必需的,但可以提醒编写者在文档注释中包含哪些信息,以便用户更好地理解代码。
|
||
|
|
||
|
另外,本段落提到在文档注释中添加示例代码块(Examples)的好处是可以帮助用户理解如何使用库,并且这些示例代码块也可以作为测试运行。在运行 `cargo test` 命令时,Rust 会在生成的文档中查找示例代码块,并将其作为测试运行,以确保示例代码的正确性。
|
||
|
|
||
|
```rust
|
||
|
/// Increment an integer by one.
|
||
|
///
|
||
|
/// # Examples
|
||
|
///
|
||
|
/// ```
|
||
|
/// let x = 5;
|
||
|
/// let result = add_one(x);
|
||
|
///
|
||
|
/// assert_eq!(result, 6);
|
||
|
/// ```
|
||
|
///
|
||
|
/// # Panics
|
||
|
///
|
||
|
/// This function will panic if the input value is `std::i32::MAX`.
|
||
|
///
|
||
|
/// # Errors
|
||
|
///
|
||
|
/// This function does not return an error.
|
||
|
///
|
||
|
/// # Safety
|
||
|
///
|
||
|
/// This function is safe to call with any valid `i32` value.
|
||
|
///
|
||
|
/// However, calling this function with a value of `std::i32::MAX` will result in a panic.
|
||
|
pub fn add_one(x: i32) -> i32 {
|
||
|
if x == std::i32::MAX {
|
||
|
panic!("Attempted to add one to i32::MAX");
|
||
|
} else {
|
||
|
x + 1
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
添加后的页面:
|
||
|
|
||
|
![image-20230423103424252](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423103424252.png)
|
||
|
|
||
|
|
||
|
|
||
|
#### 使用文档注释进行测试
|
||
|
|
||
|
![image-20230423104049806](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423104049806.png)
|
||
|
|
||
|
|
||
|
|
||
|
#### 为包含注释的项(即 crate 或 module)添加文档
|
||
|
|
||
|
与 `///` 注释不同,`//!` 注释不是针对特定项的,而是针对包含注释的项的。因此,`//!` 注释通常用于在 **crate** 或 **module** 级别上添加文档。在 crate root 文件(通常是 `src/lib.rs` 文件)或 module 内部使用 `//!` 注释,可以为整个 crate 或 module 添加一段**描述其功能、设计理念和使用方法**等信息的文档。
|
||
|
|
||
|
当使用 `cargo doc` 命令生成 Rust crate 的 API 文档时,它将解析源代码中的文档注释,并将其转换为 HTML 文档。在生成的文档中,`//!` 注释将出现在 crate 或 module 的文档页面上,提供关于 crate 或 module 的描述、使用示例和其他相关信息。
|
||
|
|
||
|
```rust
|
||
|
//! # examples
|
||
|
//!
|
||
|
//! `Examples` is a collection of utilities to make performing certain
|
||
|
//! calculations more convenient.
|
||
|
|
||
|
/// Adds one to the number given.
|
||
|
///
|
||
|
/// # Examples
|
||
|
///
|
||
|
/// ```
|
||
|
/// let arg = 5;
|
||
|
/// let answer = my_crate::add_one(arg);
|
||
|
///
|
||
|
/// assert_eq!(6, answer);
|
||
|
/// ```
|
||
|
pub fn add_one(x: i32) -> i32 {
|
||
|
x + 1
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
对比图:
|
||
|
|
||
|
![image-20230423113656778](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423113656778.png)
|
||
|
|
||
|
|
||
|
|
||
|
### 使用 `pub use` 来重新导出公共项
|
||
|
|
||
|
当我们在开发一个 crate 时,我们可能会组织它的结构以方便我们自己使用,但是对于其他人来说,这可能并不方便。他们可能需要通过复杂的路径才能访问我们的类型、函数等。这时,我们可以使用 `pub use` 来重新导出项,以**创建一个公共 API**,使其他人更容易访问我们的类型、函数等。
|
||
|
|
||
|
```rust
|
||
|
//! # Art
|
||
|
//!
|
||
|
//! A library for modeling artistic concepts
|
||
|
|
||
|
pub mod kinds {
|
||
|
/// The primary colors according to the RYB color model.
|
||
|
pub enum PrimaryColor {
|
||
|
Red,
|
||
|
Yellow,
|
||
|
Blue,
|
||
|
}
|
||
|
|
||
|
/// The secondary colors according to the RYB color model.
|
||
|
pub enum SecondaryColor{
|
||
|
Orange,
|
||
|
Green,
|
||
|
Purple,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub mod utils {
|
||
|
use crate::kinds::*;
|
||
|
/// Combines two primary colors in equal amounts to create
|
||
|
/// a secondary color.
|
||
|
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor{
|
||
|
match (c1, c2) {
|
||
|
(PrimaryColor::Red, PrimaryColor::Yellow) |
|
||
|
(PrimaryColor::Yellow, PrimaryColor::Red) => SecondaryColor::Orange,
|
||
|
(PrimaryColor::Red, PrimaryColor::Blue) |
|
||
|
(PrimaryColor::Blue, PrimaryColor::Red) => SecondaryColor::Purple,
|
||
|
(PrimaryColor::Yellow, PrimaryColor::Blue) |
|
||
|
(PrimaryColor::Blue, PrimaryColor::Yellow) => SecondaryColor::Green,
|
||
|
(_, _) => SecondaryColor::Purple,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
文档页面图:
|
||
|
|
||
|
![image-20230423135736510](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423135736510.png)
|
||
|
|
||
|
|
||
|
|
||
|
目前PrimaryColor和SecondaryColor类型以及mix()没有在首页列出。下面是一个使用此crate的代码:
|
||
|
|
||
|
```rust
|
||
|
use art::kinds::PrimaryColor;
|
||
|
use art::utils::mix;
|
||
|
|
||
|
fn main() {
|
||
|
let red = PrimaryColor::Red;
|
||
|
let yellow = PrimaryColor::Yellow;
|
||
|
mix(red, yellow);
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
根据代码可见,使用PrimaryColor和mix必须知道他们所处的模块。为解决此问题可使用pub use 重新导出顶层的项目。
|
||
|
|
||
|
```rust
|
||
|
//! # Art
|
||
|
//!
|
||
|
//! A library for modeling artistic concepts
|
||
|
|
||
|
pub use self::kinds::PrimaryColor;
|
||
|
pub use self::kinds::SecondaryColor;
|
||
|
pub use self::utils::mix;
|
||
|
|
||
|
pub mod kinds {
|
||
|
/// The primary colors according to the RYB color model.
|
||
|
pub enum PrimaryColor {
|
||
|
Red,
|
||
|
Yellow,
|
||
|
Blue,
|
||
|
}
|
||
|
|
||
|
/// The secondary colors according to the RYB color model.
|
||
|
pub enum SecondaryColor{
|
||
|
Orange,
|
||
|
Green,
|
||
|
Purple,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub mod utils {
|
||
|
use crate::kinds::*;
|
||
|
/// Combines two primary colors in equal amounts to create
|
||
|
/// a secondary color.
|
||
|
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor{
|
||
|
match (c1, c2) {
|
||
|
(PrimaryColor::Red, PrimaryColor::Yellow) |
|
||
|
(PrimaryColor::Yellow, PrimaryColor::Red) => SecondaryColor::Orange,
|
||
|
(PrimaryColor::Red, PrimaryColor::Blue) |
|
||
|
(PrimaryColor::Blue, PrimaryColor::Red) => SecondaryColor::Purple,
|
||
|
(PrimaryColor::Yellow, PrimaryColor::Blue) |
|
||
|
(PrimaryColor::Blue, PrimaryColor::Yellow) => SecondaryColor::Green,
|
||
|
(_, _) => SecondaryColor::Purple,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
文档页面图:
|
||
|
|
||
|
![image-20230423151005642](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423151005642.png)
|
||
|
|
||
|
|
||
|
|
||
|
使用 Art crate代码:
|
||
|
|
||
|
```rust
|
||
|
use art::PrimaryColor;
|
||
|
use art::mix;
|
||
|
|
||
|
fn main() {
|
||
|
let blue = PrimaryColor::Blue;
|
||
|
let yellow = PrimaryColor::Yellow;
|
||
|
println!("{:#?}", mix(blue, yellow));
|
||
|
}
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
使用 `pub use` 可以将内部类型和函数重新导出到顶层,以提高代码的可读性和可用性。创建有用的公共 API 结构更多的是一种艺术而不是一门科学,需要进行多次迭代和测试以找到最佳的设计。
|
||
|
|
||
|
|
||
|
|
||
|
### 创建 crates.io 账号
|
||
|
|
||
|
在发布任何crate之前,您需要在[crate](https://crates.io/)上创建一个帐户,并获得一个API令牌。创建[链接](https://crates.io/settings/tokens)
|
||
|
|
||
|
![image-20230423154227662](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423154227662.png)
|
||
|
|
||
|
|
||
|
|
||
|
[cargo-login](https://doc.rust-lang.org/cargo/commands/cargo-login.html) 可以将 API token 保存在本地,方便后续上传 crate 时进行身份验证。如果没有登录,上传 crate 时将会提示你登录。使用 `cargo login` 命令登录成功后,API token 将保存在 `$HOME/.cargo/credentials` 文件中。在执行 `cargo publish` 命令时,会自动使用该文件中保存的 API token 进行身份验证,以便将 crate 发布到 crates.io。
|
||
|
|
||
|
![image-20230423160145017](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423160145017.png)
|
||
|
|
||
|
|
||
|
|
||
|
token位置:
|
||
|
|
||
|
![image-20230423160319545](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423160319545.png)
|
||
|
|
||
|
|
||
|
|
||
|
### 发布crate
|
||
|
|
||
|
发布一个 crate 之前需要在 Cargo.toml 文件中的 [package] 部分添加元数据,并且 crate 必须拥有唯一的名称。在发布到 crates.io 上时需要**检查该名称是否已经被使用**,如果已被占用就需要选择另一个名称进行发布。当在本地开发时,可以随意命名。
|
||
|
|
||
|
```rust
|
||
|
cargo publish // 发布crate
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
![image-20230423163737104](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423163737104.png)
|
||
|
|
||
|
发布是永久性的。版本永远不能被覆盖,代码也不能被删除。
|
||
|
|
||
|
|
||
|
|
||
|
### 发布crate新版本
|
||
|
|
||
|
当你对你的 crate 进行了更改并准备发布一个新版本时,你需要修改 Cargo.toml 文件中指定的**版本值**并重新发布。使用语义化版本控制规则来决定下一个适当的版本号,根据你所做的更改的种类。然后运行 `cargo publish` 命令来上传新版本。
|
||
|
|
||
|
![image-20230423165714253](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230423165714253.png)
|
||
|
|
||
|
|
||
|
|
||
|
### cargo yank 弃用 crate 版本
|
||
|
|
||
|
`cargo yank` 命令来弃用某个 crate 版本。弃用版本意味着防止未来的项目使用这个版本作为依赖,但所有现有项目仍然可以继续使用该版本。这在某些情况下很有用,比如某个 crate 版本存在 bug 或安全问题。使用 `cargo yank` 命令可以更新 Crates.io 的索引,并将指定版本标记为弃用状态。
|
||
|
|
||
|
要使用 `cargo yank` 命令弃用某个版本,你需要在之前已发布的 crate 目录下运行该命令,并指定要弃用的版本号。例如,如果要弃用名为 `zm-test` 版本号为 0.1.0 的 crate,需要在该 crate 目录下运行 `cargo yank --vers 0.1.0` 命令。如果需要重新启用已经弃用的版本,可以运行 `cargo yank --vers 0.1.0 --undo` 命令来撤销弃用状态。
|
||
|
|
||
|
需要注意的是,弃用版本不会删除任何代码,也不会防止已经使用该版本的项目出现问题,例如,如果一个版本中包含了误上传的密钥,那么即使使用 `cargo yank` 命令将该版本弃用,这些密钥仍然可能被泄露,因此需要立即重置这些密钥。
|
||
|
|
||
|
```rust
|
||
|
cargo yank --vers 0.1.0
|
||
|
Updating crates.io index
|
||
|
Yank zm-test@0.1.0
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
页面显示:
|
||
|
|
||
|
![image-20230424103251005](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424103251005.png)
|
||
|
|
||
|
|
||
|
|
||
|
```rust
|
||
|
cargo yank --vers 0.1.0 --undo
|
||
|
Updating crates.io index
|
||
|
Yank zm-test@0.1.0
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
页面显示:
|
||
|
|
||
|
![image-20230424103512067](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424103512067.png)
|
||
|
|
||
|
|
||
|
|
||
|
## Cargo 工作区
|
||
|
|
||
|
Cargo workspace,它是一个包含多个 Rust 包的集合。**这些包共享同一个 Cargo.lock 文件和输出目录**。在这个例子中,我们创建了一个包含一个二进制包和两个库包的 workspace。这个二进制包提供主要的功能,依赖于这两个库包。其中一个库包提供了 add_one 函数,另一个库包提供了 add_two 函数。所有这三个 crate(包)都是 workspace 的一部分。Cargo 通过使用单个顶层目录下的 target 目录来管理 workspace 中所有 crate 的编译输出。这样,当有 crate 依赖于另一个 crate 时,就可以避免不必要的重新编译。
|
||
|
|
||
|
|
||
|
|
||
|
首先新建一个工作区目录:
|
||
|
|
||
|
```rust
|
||
|
mkdir add
|
||
|
cd add
|
||
|
```
|
||
|
|
||
|
然后新建一个Cargo.toml文件配置整个工作区,只需有以下内容即可:
|
||
|
|
||
|
```rust
|
||
|
[workspace]
|
||
|
|
||
|
members = [
|
||
|
"adder",
|
||
|
]
|
||
|
```
|
||
|
|
||
|
在add目录中新建adder二进制crate。并使用cargo build构建工作区。现目录中文件如下所示:
|
||
|
|
||
|
```rust
|
||
|
├── Cargo.lock
|
||
|
├── Cargo.toml
|
||
|
├── adder
|
||
|
│ ├── Cargo.toml
|
||
|
│ └── src
|
||
|
│ └── main.rs
|
||
|
└── target
|
||
|
```
|
||
|
|
||
|
工作区在顶层有一个target目录,将编译后的文件放入其中;adder包没有自己的目标目录。即使我们从adder目录内部运行cargo build,编译后的构件仍将在add/target而不是add/adder/target中。Cargo在工作区中按照这种方式**结构化目标目**录,因为工作区中的包应该相互依赖。
|
||
|
|
||
|
|
||
|
|
||
|
### 在工作区创建第二个包
|
||
|
|
||
|
首先修改最外层的 Cargo.toml, 添加add_one(新包名称)路径。
|
||
|
|
||
|
```rust
|
||
|
[workspace]
|
||
|
|
||
|
members = [
|
||
|
"adder",
|
||
|
"add_one",
|
||
|
]
|
||
|
```
|
||
|
|
||
|
新建 add_one lib crate。并使用cargo build:
|
||
|
|
||
|
```rust
|
||
|
├── Cargo.lock
|
||
|
├── Cargo.toml
|
||
|
├── add_one
|
||
|
│ ├── Cargo.toml
|
||
|
│ └── src
|
||
|
│ └── lib.rs
|
||
|
├── adder
|
||
|
│ ├── Cargo.toml
|
||
|
│ └── src
|
||
|
│ └── main.rs
|
||
|
└── target
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
在 add_one/src/lib.rs 中添加 add_one()
|
||
|
|
||
|
![image-20230424151704617](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424151704617.png)
|
||
|
|
||
|
|
||
|
|
||
|
接下来让adder使用add_one包。首先修改adder/Cargo.toml文件。
|
||
|
|
||
|
![image-20230424161041199](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424161041199.png)
|
||
|
|
||
|
|
||
|
|
||
|
Cargo并不假设工作区中的crate将相互依赖,因此我们需要明确依赖关系。在adder中使用add_one包方法,
|
||
|
|
||
|
![image-20230424163442014](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424163442014.png)
|
||
|
|
||
|
|
||
|
|
||
|
#### **[cargo参数](https://doc.rust-lang.org/cargo/commands/cargo-run.html) -p 与 -bin**
|
||
|
|
||
|
`cargo run -p` 命令用于运行指定的包,而包通常包含一个或多个二进制文件。如果包只包含一个二进制文件,那么这个文件就是默认的二进制文件。`cargo run -p` 命令将运行指定包中的默认二进制文件。
|
||
|
|
||
|
如果包含多个二进制文件,可以通过 `cargo run -p` 命令的 `--bin` 选项来指定要运行的特定二进制文件。例如,`cargo run -p my_package --bin my_binary` 将运行 `my_package` 包中名为 `my_binary` 的二进制文件。
|
||
|
|
||
|
因此,`cargo run -p` 命令可以用于运行指定的包和该包中的默认或指定的二进制文件。
|
||
|
|
||
|
另一方面,`cargo run --bin` 命令用于运行指定包中的特定二进制文件。需要同时指定包名和要运行的二进制文件名。例如,`cargo run --bin my_binary --package my_package` 将运行名为 `my_package` 的包中名为 `my_binary` 的二进制文件。
|
||
|
|
||
|
因此,`cargo run --bin` 命令用于运行指定包中的特定二进制文件,而不管该包中是否包含其他二进制文件。
|
||
|
|
||
|
|
||
|
|
||
|
![image-20230424164918427](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424164918427.png)
|
||
|
|
||
|
|
||
|
|
||
|
#### 依赖工作区外的包
|
||
|
|
||
|
工作区有一个顶级的 `Cargo.lock` 文件,而不是在每个 crate 的目录下都有一个 `Cargo.lock` 文件,这确保了所有 crate 都使用**相同版本**的所有依赖项。在 `add_one` 和 `adder` crate 的 `Cargo.toml` 文件中添加 `rand` 包作为依赖项,然后运行 `cargo build` 来构建整个 workspace,这样所有 crate 就可以使用相同版本的 `rand` 包了。虽然 `rand` 包已经在 workspace 中使用了,但是如果想在 workspace 中的其他 crate 中使用它,就必须在这些 crate 的 `Cargo.toml` 文件中也添加 `rand` 作为依赖项。
|
||
|
|
||
|
|
||
|
|
||
|
先在 add_one/Cargo.toml 添加 rand依赖
|
||
|
|
||
|
![image-20230424163205318](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424163205318.png)
|
||
|
|
||
|
|
||
|
|
||
|
build后,工作区的 Cargo.lock 已经包含了 add_one 对rand的依赖的信息。
|
||
|
|
||
|
![image-20230424163124138](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424163124138.png)
|
||
|
|
||
|
|
||
|
|
||
|
但若在其他 crate 中直接使用rand,是不可以的:
|
||
|
|
||
|
![image-20230424165906881](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424165906881.png)
|
||
|
|
||
|
|
||
|
|
||
|
必须在 `Cargo.toml` 文件中也添加 `rand` 作为依赖项才可以使用:
|
||
|
|
||
|
![image-20230424170928013](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424170928013.png)
|
||
|
|
||
|
不会下载rand的其他副本。Cargo已经确保工作空间中使用rand包的每个包中的每个crate都使用相同的版本,从而节省了我们的空间,并确保工作空间中的crate彼此兼容。
|
||
|
|
||
|
|
||
|
|
||
|
#### 在工作区中添加测试
|
||
|
|
||
|
当在工作区最外层运行 cargo test 时,会测试工作区所有的crate。
|
||
|
|
||
|
![image-20230424172215377](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424172215377.png)
|
||
|
|
||
|
|
||
|
|
||
|
输出的第一部分显示通过了add_one crate中的it_works测试。下一节显示在adder crate中没有找到任何测试,最后一节显示在add_one crate中没有找到任何文档测试。
|
||
|
|
||
|
可通过 -p 指定要测试的crate:
|
||
|
|
||
|
![image-20230424172810426](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230424172810426.png)
|
||
|
|
||
|
|
||
|
|
||
|
#### 发布工作区crate
|
||
|
|
||
|
如果想将 workspace 中的 crate 发布到 crates.io 上,每个 crate 都需要**单独发布**,可以使用 `-p` 标志和要发布的 crate 的名称来发布特定的 crate。如果有多个 crate 需要发布,需要分别指定每个 crate 的名称并分别执行 `cargo publish -p <crate-name>` 命令。
|
||
|
|
||
|
|
||
|
|
||
|
## 使用cargo install安装可执行文件
|
||
|
|
||
|
[cargo install](https://doc.rust-lang.org/cargo/commands/cargo-install.html) 是用于本地安装和使用二进制 crate 的命令,不是用来替代系统包管理的。它适用于 Rust 开发者安装和使用别人在 crates.io 上分享的工具。注意,只有具有二进制目标的包才能被安装。二进制目标是指如果 crate 有 **src/main.rs** 文件或者指定了其他二进制文件,生成的**可执行程序**,而不是一个不能独立运行,但适合包含在其他程序中的库目标。
|
||
|
|
||
|
所有用 cargo install 安装的二进制程序都存储在安装根目录的 **bin** 文件夹中。如果你使用 rustup.rs 安装了 Rust 并且没有进行自定义配置,该目录将为 $HOME/.cargo/bin。确保该目录在 $PATH 中,以便能够运行使用 cargo install 安装的程序。
|
||
|
|
||
|
- `cargo install` 用于将某个 crate 的二进制文件安装到系统的二进制目录下,以便在命令行中直接调用该程序。通常用于安装 Rust 生态系统中提供的工具或第三方应用程序。
|
||
|
- `cargo run` 用于在开发阶段直接运行项目中的二进制文件,通常用于测试、调试和验证代码。
|
||
|
|
||
|
简而言之,`cargo run` 用于开发阶段直接运行代码,而 `cargo install` 则用于在生产环境中安装可执行文件。
|
||
|
|
||
|
|
||
|
|
||
|
install 远端crate(非本地程序,修改不了):
|
||
|
|
||
|
![image-20230425111309861](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230425111309861.png)
|
||
|
|
||
|
|
||
|
|
||
|
install 本地crate:
|
||
|
|
||
|
![image-20230425152141433](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230425152141433.png)
|
||
|
|
||
|
|
||
|
|
||
|
cargo install 操作 cargo install --force xx 用于覆盖crate:
|
||
|
|
||
|
![image-20230425153534566](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230425153534566.png)
|
||
|
|
||
|
|
||
|
|
||
|
## 自定义命令扩展Cargo
|
||
|
|
||
|
Cargo的设计使得你可以扩展它的子命令而不必修改Cargo本身。Cargo 可以通过添加自定义子命令进行扩展,只需在 $PATH 中添加名为 cargo-xxx 的二进制文件,即可通过 cargo xxx 命令运行。自定义命令还会在运行 cargo --list 时列出。通过 cargo install 安装扩展,并像内置 Cargo 工具一样运行。
|
||
|
|
||
|
|
||
|
|
||
|
![image-20230425161238033](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230425161238033.png)
|
||
|
|
||
|
|
||
|
|
||
|
cargo --list:
|
||
|
|
||
|
![image-20230425161337132](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230425161337132.png)
|
||
|
|
||
|
|
||
|
|
||
|
### 为自定义命令添加描述
|
||
|
|
||
|
目前还没有找到合适方法办法添加,测试了两种方法都失败了。第一种是修改Cargo.toml(失败)
|
||
|
|
||
|
```rust
|
||
|
[package]
|
||
|
name = "cargo-xxx"
|
||
|
version = "0.1.0"
|
||
|
|
||
|
[package.metadata.'cargo-xxx']
|
||
|
description = "My custom Cargo command"
|
||
|
```
|
||
|
|
||
|
|
||
|
|
||
|
第二种方式使用clap添加依赖(失败):
|
||
|
|
||
|
```rust
|
||
|
fn zm() -> App {
|
||
|
App::new("zm")
|
||
|
.about("描述")
|
||
|
.arg(Arg::with_name("file")
|
||
|
.help("The file to read")
|
||
|
.required(true)
|
||
|
.index(1))
|
||
|
|
||
|
}
|
||
|
```
|
||
|
|