Rust Book 勉強会 #7 第14章「More About Cargo and Crates.io」

## この資料について

この資料は「[Rust Book 勉強会 #7](https://rust-kansai.connpass.com/event/124415/)」用の発表資料です。

* 担当: Yuya Kato (Nayutaya Inc.)
* 範囲: 第14章「More About Cargo and Crates.io」
* 原文: [More about Cargo and Crates.io - The Rust Programming Language](https://doc.rust-lang.org/book/ch14-00-more-about-cargo.html#more-about-cargo-and-cratesio)
* 日本語版: [CargoとCrates.ioについてより詳しく](https://doc.rust-jp.rs/book/second-edition/ch14-00-more-about-cargo.html)

---

## 第14章のサマリ

第14章の各節では、以下のような内容が紹介されています。

1. 「プロファイル」を使ってビルドをカスタマイズする方法
2. crates.ioでパッケージを公開する方法
    * ドキュメンテーションコメントを追加する方法
3. 「ワークスペース」を使ってプロジェクトを整理する方法
4. crates.ioから実行可能ファイルをインストールする方法
5. `cargo`コマンドを拡張する方法

---

## 第14章で登場するコマンド

第14章では、以下のコマンド（とオプション）が登場します。（登場順）

* `cargo build`: ビルド
    * `cargo build --release`: リリースプロファイルを使ったビルド
* `cargo test`: テストの実行
    * `cargo test -p xxx`: 一部のテストの実行
* `cargo doc`: ドキュメントの生成
    * `cargo doc --open`: ドキュメントをブラウザで開く
* `cargo login xxx`: crates.ioへのログイン
* `cargo publish`: パッケージの公開
* `cargo yank`: パッケージの取り下げ
* `cargo new`: パッケージの作成
    * `cargo new xxx --lib`: ライブラリパッケージの作成
* `cargo run`: 実行
    * `cargo run -p xxx`: 指定したパッケージの実行
* `cargo install xxx`: パッケージのインストール
* `cargo --list`: コマンド一覧の表示

---

## 1. プロファイルによるビルドのカスタマイズ

---

### プロファイルとは？

Cargoでは「プロファイル」（profile）という機構によってさまざまなビルドオプションを制御することができます。

Cargoには、主なプロファイルとして以下の2つが存在します。

| プロファイル | コマンド | 説明 |
|:---|:---|:---|
| `dev` | `cargo build` | 開発/デバッグ用 |
| `release` | `cargo build --release` | リリース用 |

※補足: 他にも`test`、`bench`が存在します。

---

### プロファイル: 実行例

以下に実行例を示します。

```text
$ cargo build
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs

$ cargo build --release
    Finished release [optimized] target(s) in 0.0 secs
```

---

### プロファイルの上書き (1/2)

`Cargo.toml`に`[profile.*]`というセクションを追加することでデフォルト値を上書き（カスタマイズ）することができます。例えば`opt-level`は以下のデフォルト値を持ちます。

```Cargo.toml
[profile.dev]
opt-level = 0

[profile.release]
opt-level = 3
```

`opt-level`は`0`から`3`までの整数を指定でき、数字が大きいほどより高度な最適化を行うことを示します。
高度な最適化には時間を要するため、頻繁にビルドを行う開発時は最適化を行わないようになっています。その代わり、生成されるオブジェクトコードは低速です。
リリース時には最適化を行い、時間は掛かりますが高速なオブジェクトコードを出力します。

---

### プロファイルの上書き (2/2)

`dev`プロファイルの`opt-level`オプションを上書きする例を以下に示します。

```Cargo.toml
[profile.dev]
opt-level = 1
```

上記の`Cargo.toml`が指定された状態で`cargo build`を行うと、`opt-level`に`1`が設定された状態でビルドが行われます。

詳しいオプションやデフォルト値については「[Cargoのドキュメント](https://doc.rust-lang.org/book/ch14-01-release-profiles.html)」を参照してください。

---

## 2. クレートをcrates.ioで公開する

---

### クレートを公開する

ここまでに、crates.ioに存在するクレートをプロジェクトの依存関係に追加する方法を学んできました。本節では、クレートを自身で作成して、公開、共有する方法を学びましょう。

---

### クレートを公開するまでのステップ

新しいクレートを公開する手順は以下の通りです。

1. ドキュメンテーションコメントの追加
2. テストの追加
3. 公開APIを整理する
4. crates.ioのアカウントをセットアップする
5. メタデータを追加する
6. crates.ioに公開する

また、既に公開しているクレートを更新、取り下げする方法についても学びましょう。

---

## 2.1. ドキュメンテーションコメント

---

### ドキュメンテーションコメント

第3章では`//`（2連スラッシュ）を使ってRustコードにコメントを追加する方法を学びました。

Rustには`///`（3連スラッシュ）、`//!`（2連スラッシュ＋エクスクラメーションマーク）というコメントの表記もあり、これらは「ドキュメンテーションコメント」と呼ばれます。
これらのドキュメンテーションコメントからHTMLドキュメントが生成されます。

次ページに例を示します。

---

### ドキュメンテーションコメント: 具体例

要素に対するドキュメンテーションコメントは`///`で始まり、Markdown記法をサポートしています。ドキュメント対象の要素の直前に記述する必要があります。
以下は、`my_crate`クレートの`add_one`関数のドキュメンテーションコメントの例です。

```src/lib.rs
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let five = 5;
///
/// assert_eq!(6, my_crate::add_one(5));
/// ```
pub fn add_one(x: i32) -> i32 {
    x + 1
}
```

Listing 14-1: A documentation comment for a function

Markdown記法についての補足:

* `# `、`## `などで始まる行は見出しを示します。
* ```` ``` ````で括られた行はコードを示します。

---

### ドキュメントの生成例

`cargo doc`コマンドを実行すると、ドキュメンテーションコメントからドキュメントを生成し、`target/doc`に出力することができます。内部的には`rustdoc`が使用されています。
また、`cargo doc --open`を実行すると、Webブラウザでドキュメントを閲覧することができます。生成されたドキュメントの例を以下に示します。

![trpl14-01.png](https://qiita-image-store.s3.amazonaws.com/0/58479/1b2f710f-100a-d622-485e-344c27a618e6.png)

Figure 14-1: HTML documentation for the add_one function

---

### よく使われるセクション

前述の例に含まれた「Examples」の他に、以下のセクションがよく用いられます。

* Panics: 関数が`panic!`する可能性のあるシナリオを記述します。パニックさせたくない関数の使用者は、これらの状況にならないように気を付ける必要があります。
* Errors: 関数が`Result`を返すのであれば、どんなエラーがどんな条件で発生するのかを記述します。
* Safety: 関数が`unsafe`ならその理由を説明し、期待する不変条件などを記述します。（`unsafe`については第19章を参照）

---

## 2.2. テストとしてのドキュメンテーションコメント

---

### テストとしてのドキュメンテーションコメント

先ほどの例のように、ドキュメンテーションコメントに「使用例」としてコードブロックを追加すると、説明文として意味があるだけでなく、`cargo test`でテストすることができます。（いわゆる「doctest」）

「例付きのドキュメントに上回るものはありません。しかし、メンテナンスされていないがために動かなくなっている例よりも悪いものもありません。」
ドキュメンテーションコメントに実行可能な例を含めることで、例が動かなくなることを防ぐことができます。

以下に実行例を示します。

```text
   Doc-tests my_crate

running 1 test
test src/lib.rs - add_one (line 5) ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

---

### クレートやモジュールにコメントする

`///`ではなく`//!`を用いることで、コメントの直後の要素に対してではなく、そのコメントが含まれる要素（クレート、モジュール全体）に対してコメントを付加することができます。具体例を以下に示します。

```src/lib.rs
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.

/// Adds one to the number given.
// --snip--
```

Listing 14-2: Documentation for the my_crate crate as a whole

生成されたドキュメントの例を次ページに示します。

---

### ドキュメントの生成例

![trpl14-02.png](https://qiita-image-store.s3.amazonaws.com/0/58479/e2ac74c5-bcb9-f8c5-0756-e1b61ddcb662.png)

---

## 2.3. `pub use`で便利な公開APIをエクスポートする

---

### 内部構造と公開API

第7章では:

* `mod`キーワードを使用してコードをモジュール化（構造化）する方法
* `pub`キーワードで要素を公開する方法
* `use`キーワードで要素をスコープに導入する方法

を学びました。しかし、クレートの内部構造は、クレートを使う側にとって便利ではない可能性があります。

例えばクレート内部の型が階層化されている場合、使う側が`use my_crate::some_module::another_module::UsefulType;`とするのは煩わしく感じます。
ここは単に`use my_crate::UsefulType;`と書けると便利です。本節ではその方法について学びましょう。

---

### 内部構造の例

例として以下のコードを用います。`PrimaryColor`、`SecondaryColor`という2つの列挙型を含む`kinds`モジュールと、`kinds`モジュールと`mix`関数を含む`utils`モジュールです。

```src/lib.rs
//! # 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 kinds::*;

    /// Combines two primary colors in equal amounts to create
    /// a secondary color.
    pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
        // --snip--
    }
}
```

Listing 14-3: An art library with items organized into kinds and utils modules

この例から生成されたドキュメントの例を次ページに示します。

---

### 生成されたドキュメントの例

![trpl14-03.png](https://qiita-image-store.s3.amazonaws.com/0/58479/16710184-5ec5-6a1e-2a51-ec2cf428f26c.png)

Figure 14-3: Front page of the documentation for art that lists the kinds and utils modules

画面の通り、`PrimaryColor`型、`SecondaryColor`型、`mix`関数はトップページには現れず、参照するためには`kinds`、`utils`をクリックする必要があります。

---

### 利用するクレートの例

前述のクレートを利用するクレートの例を以下に示します。

```rs
use art::kinds::PrimaryColor;
use art::utils::mix;

fn main() {
    let red = PrimaryColor::Red;
    let yellow = PrimaryColor::Yellow;
    mix(red, yellow);
}
```

Listing 14-4: A crate using the art crate’s items with its internal structure exported

上記の通り、クレートの利用者は`PrimaryColor`型が`kinds`モジュールにあり、`mix`関数が`utils`モジュールにあることを特定する必要があります。`art`クレートの内部構造は、クレートの利用者からすれば意味のある情報を含んでいません。

---

### `pub use`による再エクスポート

`pub use`を用いることで、内部構造を除去して再エクスポートすることができます。例を以下に示します。

```rs
//! # Art
//!
//! A library for modeling artistic concepts.

pub use kinds::PrimaryColor;
pub use kinds::SecondaryColor;
pub use utils::mix;

pub mod kinds {
    // --snip--
}

pub mod utils {
    // --snip--
}
```

Listing 14-5: Adding pub use statements to re-export items

この例から生成されたドキュメントの例を次ページに示します。

---

### 生成されたドキュメントの例

![trpl14-04.png](https://qiita-image-store.s3.amazonaws.com/0/58479/7a36d24d-baa0-5002-13be-0b2648e303a6.png)

Figure 14-4: The front page of the documentation for art that lists the re-exports

画面の通り、再エクスポートされた要素が列挙され、見つけやすくなります。

---

### 再エクスポートされた要素を利用する

再エクスポートされている場合、以前のように内部構造を利用することも、以下のようにより便利な構造を利用することもできます。
またクレートの開発者から見れば、内部構造と公開APIを切り離すことができます。

```src/main.rs
use art::PrimaryColor;
use art::mix;

fn main() {
    // --snip--
}
```

Listing 14-6: A program using the re-exported items from the art crate


---

## 2.4. アカウントのセットアップ

---

### crates.ioのアカウントをセットアップする

クレートを公開するためにはcrates.ioのアカウントを作成する必要があります。また、crates.ioのアカウント作成にはGitHubアカウントが必要です。（いずれGitHubアカウントが無くてもログインできるようになる予定）

ログイン後、 https://crates.io/me にアクセスしてAPIキー（トークン）を取得してください。APIキーと共に`cargo login`コマンドを実行すれば準備完了です。

```text
$ cargo login abcdefghijklmnopqrstuvwxyz012345
```

上記のコマンドは、APIキーを`~/.cargo/credentials`に保存します。APIキーは秘密にするべきであり、他人と共有してはなりません。何らかの理由によりAPIキーが漏れた場合は https://crates.io/me から再生成することができます。

---

## 2.5. メタデータの追加

---

### メタデータを追加する (1/2)

クレートを公開する場合、いくつかのメタデータの追加が必要です。具体的には`Cargo.toml`の`[package]`セクションにデータを追加する必要があります。以下に例を示します。

```Cargo.toml
[package]
name = "guessing_game"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"

[dependencies]
```

各項目については次ページで説明します。

---

### メタデータを追加する (2/2)

* `name`: クレートの名称です。crates.io全体でユニークである必要があり、早い者勝ちです。
* `version`: バージョン番号です。セマンティックバージョンルールに基づいて付加するのが望ましいです。
* `description`: クレートの説明文です。
* `license`: クレートのライセンスです。`OR`で区切ることで、複数のライセンスの選択肢を示すことができます。Rustコミュニティでは`MIT OR Apache-2.0`が多く用いられます。

その他の項目については[Cargoのドキュメント](https://doc.rust-lang.org/stable/cargo/index.html#the-cargo-book)を参照してください。

---

## 2.6. 公開と更新、取り下げ

---

### crates.ioに公開する

アカウントを作成し、APIキーを登録し、メタデータを追加したので、クレートを公開する準備ができました。

実際に公開する前に注意点。公開は恒久的です。バージョンを上書きすることも、コードを削除することもできません。これはcrates.ioが、クレートに依存しているすべてのプロジェクトがいつでもビルドできるように永久アーカイブとして機能しているためです。

`cargo publish`コマンドを実行すると、クレートを公開することができます。実行例を以下に示します。

```text
$ cargo publish
 Updating registry `https://github.com/rust-lang/crates.io-index`
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
 Finished dev [unoptimized + debuginfo] target(s) in 0.19 secs
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
```

---

### 公開済みのクレートの新バージョンを公開する（アップデートする）

クレートのコードを更新し、新バージョンをリリースする準備ができたら、`Cargo.toml`ファイルの`version`を更新し、`cargo publish`コマンドを実行してください。

バージョン番号は、セマンティックバージョンルールに基づき、加えた変更の種類に応じて適切な値を決定します。

---

### 特定のバージョンを取り下げる

クレートの特定のバージョンを削除することはできませんが、「取り下げ」を行い、新たに依存関係として追加されることを防ぐことはできます。

バージョンを取り下げても、引きつづきダウンロードし、利用することはできます。`Cargo.lock`で指定されている限り、プロジェクトが壊れることはありません。

`cargo yank`コマンドで特定のバージョン取り下げを行うことができます。

```text
$ cargo yank --vers 1.0.1
```

また、`--undo`オプションで取り下げの取り消しを行うことができます。

```text
$ cargo yank --vers 1.0.1 --undo
```

繰り返しになりますが、コードを削除することはできません。できるのは、新たに依存クレートとして加えられることを防ぐことだけです。

---

## 3. Cargoのワークスペース

---

### Cargoのワークスペース

本節では、以下の内容について学びましょう。

* ワークスペースを生成する
* ワークスペース内にクレートを追加する
* ワークスペースに外部クレートを追加する
* ワークスペースにテストを追加する

第12章では、バイナリクレートとライブラリクレートを含むパッケージを構築しました。プロジェクトの開発が進むにつれてクレートが肥大化し、パッケージを分割したくなることでしょう。

そんな場面において便利なのが「ワークスペース」です。

---

### ワークスペースを生成する (1/3)

ワークスペースは、同じ`Cargo.lock`と出力ディレクトリを共有する一連のパッケージです。

例として、バイナリ1つとライブラリ2つを含むワークスペースを作ります。バイナリは主要な機能を提供しますが、ライブラリに依存しています。1つ目のライブラリは`add_one`関数を提供し、2つ目のライブラリは`add_two`関数を提供します。これら3つのクレートがワークスペースの一部となります。

まずはワークスペース用のディレクトリを作りましょう。

```text
$ mkdir add
$ cd add
```

---

### ワークスペースを生成する (2/3)

続いて、ワークスペース全体の設定を行う`Cargo.toml`を作成します。

```Cargo.toml
[workspace]

members = [
    "adder",
]
```

この`Cargo.toml`はとてもシンプルで、`[package]`セクションやメタデータを含みません。その代わり、ワークスペースのメンバを管理する`[workspace]`セクションを含みます。

---

### ワークスペースを生成する (3/3)

続いて、`add`ディレクトリ内で`adder`クレートを作成しましょう。

```text
$ cargo new adder
     Created binary (application) `adder` project
```

この時点で`cargo build`を事項すると、ワークスペースをビルドできます。現状の構成は以下の通りです。

```text
add
├── Cargo.lock
├── Cargo.toml
├── adder
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target
```

---

### ワークスペース内にクレートを追加する (1/5)

次に、`add-one`ライブラリクレートを追加しましょう。ワークスペースの`Cargo.toml`を以下のように変更します。

```Cargo.toml
[workspace]

members = [
    "adder",
    "add-one",
]
```

---

### ワークスペース内にクレートを追加する (2/5)

それから、ライブラリクレートを作成します。

```text
$ cargo new add-one --lib
     Created library `add-one` project
```

現状の構成は以下の通りです。

```text
add
├── Cargo.lock
├── Cargo.toml
├── add-one
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── adder
│   ├── Cargo.toml
│   └── src
│       └── main.rs
└── target
```

---

### ワークスペース内にクレートを追加する (3/5)

次に、`add_one`関数を追加しましょう。

```add-one/src/lib.rs
pub fn add_one(x: i32) -> i32 {
    x + 1
}
```

この関数を利用するため、`adder`バイナリクレートに依存関係を追加しましょう。

```adder/Cargo.toml
[dependencies]

add-one = { path = "../add-one" }
```

---

### ワークスペース内にクレートを追加する (4/5)

次に、`adder`バイナリクレートに、実際に`add_one`を呼ぶ処理を追加します。

```adder/src/main.rs
use add_one;

fn main() {
    let num = 10;
    println!("Hello, world! {} plus one is {}!", num, add_one::add_one(num));
}
```

Listing 14-7: Using the add-one library crate from the adder crate

---

### ワークスペース内にクレートを追加する (5/5)

呼び出し処理を追加したので、ビルド、実行してみましょう。

```text
$ cargo build
   Compiling add-one v0.1.0 (file:///projects/add/add-one)
   Compiling adder v0.1.0 (file:///projects/add/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 0.68 secs
```

```text
$ cargo run -p adder
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/adder`
Hello, world! 10 plus one is 11!
```

無事に`add-one`クレートに依存した処理が実行されました。

---

### 外部クレートをワークスペースに追加する (1/3)

ワークスペース内のそれぞれのクレートには`Cargo.lock`が存在せず、ワークスペースの最上位ディレクトリにただ1つの`Cargo.lock`が存在します。
これにより、すべてのクレートが同一バージョンのクレートを使用します。

`rand`クレートを`adder/Cargo.toml`（バイナリクレート）と`add-one/Cargo.toml`（ライブラリクレート）に追加すると、Cargoはバージョンの解決を行い、トップディレクトリの`Cargo.lock`に記録します。

---

### 外部クレートをワークスペースに追加する (2/3)

`add-one`クレートに`rand`クレートを追加してみましょう。

```add-one/Cargo.toml
[dependencies]

rand = "0.3.14"
```

続いて`add-one/src/lib.rs`に`extern crate rand;`を追加し、`add`ディレクトリ（ワークスペース）で`cargo build`を実行すると`rand`の取得が行われます。

```text
$ cargo build
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading rand v0.3.14
   --snip--
   Compiling rand v0.3.14
   Compiling add-one v0.1.0 (file:///projects/add/add-one)
   Compiling adder v0.1.0 (file:///projects/add/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 10.18 secs
```

---

### 外部クレートをワークスペースに追加する (3/3)

トップディレクトリの`Cargo.lock`に`rand`に対する依存が記録されている状態になりましたが、ワークスペース内のそれぞれのクレートの`Cargo.toml`に`rand`を追加しない限り、それぞれのクレートで利用することはできません。

例えば、`adder/src/main.rs`に`extern crate rand;`を追加すると、以下のエラーが出力されます。

```text
$ cargo build
   Compiling adder v0.1.0 (file:///projects/add/adder)
error: use of unstable library feature 'rand': use `rand` from crates.io (see
issue #27703)
 --> adder/src/main.rs:1:1
  |
1 | extern use rand;
```

---

### ワークスペースにテストを追加する (1/3)

さらなる改善として`add-one`クレートに`add_one::add_one`関数のテストを追加しましょう。

```add-one/src/lib.rs
pub fn add_one(x: i32) -> i32 {
    x + 1
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        assert_eq!(3, add_one(2));
    }
}
```

---

### ワークスペースにテストを追加する (2/3)

トップディレクトリで`cargo test`を実行すると、すべてのクレートのテストが実行されます。

```text
$ cargo test
   Compiling add-one v0.1.0 (file:///projects/add/add-one)
   Compiling adder v0.1.0 (file:///projects/add/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 0.27 secs
     Running target/debug/deps/add_one-f0253159197f7841

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/adder-f88af9d2cc175a5e

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests add-one

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

---

### ワークスペースにテストを追加する (3/3)

一部のテストのみ実行したい場合、`cargo test -p xxx`を使うことができます。

```text
$ cargo test -p add-one
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running target/debug/deps/add_one-b3235fea9a156f74

running 1 test
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

   Doc-tests add-one

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

---

### ワークスペースに含まれるクレートの公開

ワークスペースのそれぞれのクレートは、個別にcrates.ioに公開する必要があります。
つまり、それぞれのクレートのディレクトリで`cargo publish`コマンドを実行する必要があります。残念ながら`--all`のようなオプションはありません。

---

### ワークスペース: 練習問題とヒント

練習問題: `add-one`クレートと同様に、`add-two`クレートをワークスペースに追加してください。

ヒント: プロジェクトが肥大化してきたら、ワークスペースの使用を考えましょう。一つの大きな固まりより、小さく、個別のコンポーネントの方が理解が容易です。また、複数人での共同作業も容易になります。

---

## 4. crates.ioからバイナリをインストールする

---

### `cargo install`: バイナリのインストール

`cargo install`コマンドを使うことで、バイナリクレート（実行可能ファイル）をローカルにインストールし、使用することができます。
ただこれは、OSが持つようなパッケージ管理システムを置き換えることを意図したものではありません。

`cargo install`コマンドでは、バイナリターゲットを持つパッケージのみをインストールできることに注意してください。単独では実行できない、ライブラリターゲットをインストールすることはできません。

`cargo install`コマンドでインストールされるバイナリは、`rustup`を使用し、かつ独自の設定を行っていなければ`$HOME/.cargo/bin`に格納されます。このディレクトリが`$PATH`に含まれている必要があります。

---

### 具体例: `ripgrep`のインストール

第12章で触れた`ripgrep`をインストールしてみましょう。

```text
$ cargo install ripgrep
Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading ripgrep v0.3.2
 --snip--
   Compiling ripgrep v0.3.2
    Finished release [optimized + debuginfo] target(s) in 97.91 secs
  Installing ~/.cargo/bin/rg
```

メッセージにある通り、`~/.cargo/bin/rg`にインストールされました。`rg --help`を実行して、ツールが動作することを確認しましょう。

---

## 5. `cargo`コマンドを拡張する方法

---

### 独自のサブコマンドで`cargo`を拡張する

Cargoは、それ自体を変更することなく、新しいサブコマンドで拡張できるように設計されています。

`$PATH`に存在するバイナリが`cargo-something`という名前なら、`cargo something`を実行することで、サブコマンドであるかのように実行することができます。

このような独自コマンドは、`cargo --list`コマンドでも列挙されます。

`cargo install`コマンドを使って拡張をインストールし、組み込みのCargoサブコマンドと同様に実行できることは、Cargoの設計上の優れた点です。

---

## 6. まとめ

---

### まとめ

* Cargoとcrates.ioを使ってコードを共有することは、Rustのエコシステムの有用な一部です。
* Rustの標準ライブラリは小さく安定的ですが、クレートは共有も使用も容易で、言語とは異なるタイムラインで進化します。
* 積極的にcrates.ioでコードを共有し、みんなの役に立ちましょう！