Rust:Cargoとは?プロジェクト管理からビルドまで全部おまかせの最強ツール完全ガイド

Rust

Rustでプログラミングを始めようと思ったとき、「どうやってプロジェクトを作るの?」「ライブラリはどう管理するの?」「ビルドはどうするの?」と疑問だらけになったことはありませんか?

「他の言語みたいに、いろんなツールを覚えないといけないの?」「複雑な設定ファイルを書かないとダメ?」と不安に思った方も多いはずです。

実は、Cargoは、Rustの公式パッケージマネージャー兼ビルドシステムで、プロジェクトの作成・依存関係の管理・ビルド・テスト・ドキュメント生成まで、すべてを一つのツールで完結できる超便利なツールなんです。まるで、料理に必要な材料の調達から調理、盛り付けまで全部やってくれる万能アシスタントのようなものですね。

この記事では、Cargoの基本から実践的な使い方まで、Rust初心者の方にも分かりやすく丁寧に解説していきます。

具体的なコマンドや設定例をたくさん見ながら、Rustプロジェクトの管理をマスターしていきましょう!


スポンサーリンク
  1. Cargoとは?その基本を知ろう
    1. 基本的な説明
    2. 何ができるの?
    3. 他の言語との比較
    4. 日常の例で理解しよう
  2. インストール方法
    1. Rustと一緒にインストール
    2. インストールの確認
    3. PATHの設定
  3. 新しいプロジェクトを作成する
    1. 実行可能プロジェクトの作成
    2. ライブラリプロジェクトの作成
    3. 初期コードを見てみよう
  4. 基本的なコマンド
    1. cargo build(ビルド)
    2. cargo run(ビルド+実行)
    3. cargo build –release(最適化ビルド)
    4. cargo check(構文チェック)
    5. cargo test(テスト実行)
    6. cargo doc(ドキュメント生成)
    7. cargo clean(クリーンアップ)
  5. プロジェクト構造を理解する
    1. Cargo.tomlファイル
    2. srcディレクトリ
    3. targetディレクトリ
  6. 依存関係の管理
    1. 外部クレートの追加
    2. バージョンの指定方法
    3. 依存関係のダウンロード
    4. Cargo.lockファイル
    5. 依存関係の更新
  7. 実践例:簡単なプロジェクトを作ろう
    1. 例1:乱数ゲーム
    2. 例2:Webスクレイピング
    3. 例3:コマンドラインツール
  8. テストの実行
    1. ユニットテストの書き方
    2. 統合テスト
    3. テストのフィルタリング
    4. テストオプション
  9. ドキュメントの生成
    1. ドキュメントコメントの書き方
    2. ドキュメント生成
    3. 依存関係のドキュメントも含める
  10. ワークスペース
    1. ワークスペースとは
    2. ワークスペースの作成
    3. ワークスペースでのビルド
  11. 設定とカスタマイズ
    1. ビルドプロファイル
    2. フィーチャーフラグ
    3. カスタムコマンド
  12. よく使うサブコマンドまとめ
  13. トラブルシューティング
    1. 問題1:ビルドが遅い
    2. 問題2:依存関係の競合
    3. 問題3:古いバージョンが使われる
    4. 問題4:ディスク容量不足
  14. よくある質問
    1. Q1: cargo buildとcargo runの違いは?
    2. Q2: releaseビルドはどれくらい速い?
    3. Q3: Cargo.lockはGitにコミットすべき?
    4. Q4: crates.ioにない非公開ライブラリを使いたい
    5. Q5: ビルドのキャッシュはどこに?
  15. まとめ

Cargoとは?その基本を知ろう

基本的な説明

Cargo(カーゴ)は、Rustの公式パッケージマネージャー兼ビルドシステムです。

2014年にRust 1.0と同時にリリースされ、Rustエコシステムの中核を担っています。

名前の由来:
「Cargo」は英語で「貨物」の意味。プロジェクトに必要なものを運んでくる、というイメージなんです。

何ができるの?

主な機能:

プロジェクト管理:
新しいプロジェクトを簡単に作成できます。

依存関係の管理:
外部ライブラリ(クレート)を自動でダウンロード・管理します。

ビルドシステム:
ソースコードをコンパイルして実行ファイルを作ります。

テストの実行:
ユニットテストや統合テストを簡単に実行できます。

ドキュメント生成:
コードから自動でドキュメントを生成します。

パッケージの公開:
作ったライブラリをcrates.ioに公開できます。

一つのツールで、すべてが完結するんですね!

他の言語との比較

Node.js: npm(パッケージ管理)+ webpack(ビルド)

Python: pip(パッケージ管理)+ setuptools(ビルド)

Java: Maven/Gradle(すべて統合)

Rust: Cargo(すべて統合)

Cargoは、JavaのMavenやGradleのように、最初から統合されているんです。

日常の例で理解しよう

レストランの支配人:

プロジェクト作成 = 店舗の開店準備
必要な設備や道具を揃える

依存関係管理 = 食材の仕入れ
必要な材料を適切な業者から調達

ビルド = 料理の調理
材料を組み合わせて料理を完成させる

テスト = 味見
料理が正しくできているか確認

ドキュメント = メニュー作成
どんな料理があるか説明書を作る

Cargoは、このすべてを一人でこなす有能な支配人なんです。


インストール方法

Rustと一緒にインストール

Cargoは、Rustをインストールすると自動的に入ります。

公式インストーラー(rustup)を使用:

Linux/macOS:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Windows:
https://rustup.rs/ からインストーラーをダウンロードして実行します。

インストールの確認

Rustのバージョン確認:

rustc --version

Cargoのバージョン確認:

cargo --version

出力例:

cargo 1.75.0 (1d8b05cdd 2024-01-10)

バージョンが表示されれば、インストール成功です!

PATHの設定

インストールが完了すると、自動的にPATHに追加されます。

確認方法:

which cargo
# Linux/macOS: /home/ユーザー名/.cargo/bin/cargo
# Windows: C:\Users\ユーザー名\.cargo\bin\cargo.exe

もしPATHが通っていない場合は、以下を~/.bashrc~/.zshrcに追加します:

export PATH="$HOME/.cargo/bin:$PATH"

新しいプロジェクトを作成する

実行可能プロジェクトの作成

コマンド:

cargo new hello_world

何が起きる?

  1. hello_worldディレクトリが作成される
  2. 必要なファイルが自動生成される
  3. Gitリポジトリが初期化される(自動)

作成されるファイル構造:

hello_world/
├── Cargo.toml       # プロジェクト設定ファイル
├── .git/            # Gitリポジトリ
├── .gitignore       # Git除外設定
└── src/
    └── main.rs      # メインのソースコード

ライブラリプロジェクトの作成

コマンド:

cargo new my_library --lib

違い:
--libオプションを付けると、実行ファイルではなくライブラリプロジェクトになります。

ファイル構造:

my_library/
├── Cargo.toml
├── .git/
├── .gitignore
└── src/
    └── lib.rs       # ライブラリのメインファイル(main.rsではない)

初期コードを見てみよう

Cargo.toml(設定ファイル):

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

[dependencies]

シンプルな設定ファイルですね。

src/main.rs(ソースコード):

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

最初から動くコードが用意されています。


基本的なコマンド

cargo build(ビルド)

プロジェクトをコンパイルします。

cd hello_world
cargo build

何が起きる?

  1. 依存関係をダウンロード(初回のみ)
  2. ソースコードをコンパイル
  3. target/debug/に実行ファイルを生成

出力:

   Compiling hello_world v0.1.0 (/path/to/hello_world)
    Finished dev [unoptimized + debuginfo] target(s) in 0.50s

実行ファイルの場所:

target/debug/hello_world       # Linux/macOS
target/debug/hello_world.exe   # Windows

cargo run(ビルド+実行)

ビルドして、すぐに実行します。

cargo run

出力:

   Compiling hello_world v0.1.0 (/path/to/hello_world)
    Finished dev [unoptimized + debuginfo] target(s) in 0.50s
     Running `target/debug/hello_world`
Hello, world!

開発中は、これが一番便利ですね。

cargo build –release(最適化ビルド)

リリース用の最適化されたビルドを作成します。

cargo build --release

違い:

  • デバッグビルド(cargo build):コンパイルが速い、実行が遅い、デバッグ情報あり
  • リリースビルド(--release):コンパイルが遅い、実行が速い、サイズが小さい

出力先:

target/release/hello_world

性能差:
リリースビルドは、デバッグビルドの2〜10倍速く実行されることがあります。

cargo check(構文チェック)

コンパイルせずに、エラーチェックだけを行います。

cargo check

利点:

  • ビルドより圧倒的に速い
  • コードを書きながら頻繁にチェックできる

開発フロー:

コードを書く
  ↓
cargo check(エラー確認、数秒)
  ↓
修正
  ↓
cargo run(動作確認)

cargo test(テスト実行)

プロジェクト内のすべてのテストを実行します。

cargo test

詳しくは後述します。

cargo doc(ドキュメント生成)

コードからHTMLドキュメントを生成します。

cargo doc --open

--openオプションで、生成後にブラウザで自動的に開きます。

cargo clean(クリーンアップ)

targetディレクトリを削除します。

cargo clean

ビルド結果を削除して、ディスク容量を節約したいときに使います。


プロジェクト構造を理解する

Cargo.tomlファイル

Cargo.tomlは、プロジェクトの設定ファイルです(TOML形式)。

基本構造:

[package]
name = "my_project"           # プロジェクト名
version = "0.1.0"             # バージョン
edition = "2021"              # Rustのエディション
authors = ["Your Name <you@example.com>"]
description = "A sample project"
license = "MIT"

# ここに依存ライブラリを追加

srcディレクトリ

ソースコードを格納するディレクトリです。

実行可能プロジェクト:

src/
└── main.rs         # エントリーポイント(main関数)

ライブラリプロジェクト:

src/
└── lib.rs          # ライブラリのルート

複数ファイルの構成:

src/
├── main.rs         # メイン
├── lib.rs          # ライブラリ部分
└── utils.rs        # ユーティリティモジュール

targetディレクトリ

ビルド結果が格納されるディレクトリです。

target/
├── debug/          # デバッグビルド
│   ├── hello_world      # 実行ファイル
│   └── deps/            # 依存関係のビルド結果
└── release/        # リリースビルド
    └── hello_world

注意: .gitignoreに含まれているので、Gitには追加されません。


依存関係の管理

外部クレートの追加

crates.ioは、Rustの公式パッケージレジストリです。

例:乱数生成ライブラリ「rand」を追加

方法1:Cargo.tomlに直接書く

[dependencies]
rand = "0.8"

方法2:cargo addコマンド(Rust 1.62以降)

cargo add rand

自動的にCargo.tomlに追加されます。

バージョンの指定方法

完全一致:

rand = "=0.8.5"

互換バージョン(デフォルト):

rand = "0.8"        # 0.8.0 〜 0.9.0未満
rand = "0.8.5"      # 0.8.5 〜 0.9.0未満

範囲指定:

rand = ">=0.8, <0.9"

ワイルドカード:

rand = "0.8.*"

最新版:

rand = "*"          # 非推奨(予期しない変更が入る)

依存関係のダウンロード

自動ダウンロード:

cargo build

初回ビルド時に、必要な依存関係が自動的にダウンロードされます。

手動ダウンロード:

cargo fetch

ビルドせずに、依存関係だけをダウンロードします。

Cargo.lockファイル

Cargo.lockは、実際に使用されたバージョンを記録したファイルです。

特徴:

  • 自動生成される
  • 依存関係の正確なバージョンを固定
  • チーム開発で全員が同じバージョンを使用できる

扱い方:

  • 実行可能プロジェクト: Gitにコミットする
  • ライブラリプロジェクト: Gitにコミットしない(.gitignoreに追加)

依存関係の更新

小規模な更新(互換範囲内):

cargo update

Cargo.tomlの範囲内で、最新版に更新します。

特定のクレートのみ更新:

cargo update -p rand

メジャーバージョンアップ:

# Cargo.tomlを手動で変更
rand = "0.9"

その後、cargo buildで新しいバージョンがダウンロードされます。


実践例:簡単なプロジェクトを作ろう

例1:乱数ゲーム

プロジェクト作成:

cargo new guessing_game
cd guessing_game

依存関係を追加:

cargo add rand

src/main.rs:

use rand::Rng;
use std::io;

fn main() {
    println!("数当てゲーム!");

    // 1〜100のランダムな数を生成
    let secret_number = rand::thread_rng().gen_range(1..=100);

    loop {
        println!("数を入力してください(1-100):");

        let mut guess = String::new();
        io::stdin()
            .read_line(&mut guess)
            .expect("読み込みエラー");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => {
                println!("数字を入力してください!");
                continue;
            }
        };

        match guess.cmp(&secret_number) {
            std::cmp::Ordering::Less => println!("もっと大きいです!"),
            std::cmp::Ordering::Greater => println!("もっと小さいです!"),
            std::cmp::Ordering::Equal => {
                println!("正解!おめでとう!");
                break;
            }
        }
    }
}

実行:

cargo run

動作するゲームが完成しました!

例2:Webスクレイピング

プロジェクト作成:

cargo new web_scraper
cd web_scraper

依存関係を追加:

cargo add reqwest --features blocking
cargo add scraper

Cargo.toml(確認):

[dependencies]
reqwest = { version = "0.11", features = ["blocking"] }
scraper = "0.18"

src/main.rs:

use reqwest::blocking::get;
use scraper::{Html, Selector};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Webページを取得
    let url = "https://example.com";
    let response = get(url)?;
    let body = response.text()?;

    // HTMLをパース
    let document = Html::parse_document(&body);

    // h1タグを抽出
    let h1_selector = Selector::parse("h1").unwrap();

    println!("見つかったh1タグ:");
    for element in document.select(&h1_selector) {
        println!("- {}", element.text().collect::<String>());
    }

    Ok(())
}

実行:

cargo run

Webページから情報を取得できました!

例3:コマンドラインツール

プロジェクト作成:

cargo new file_counter
cd file_counter

依存関係を追加:

cargo add clap --features derive

src/main.rs:

use clap::Parser;
use std::fs;

#[derive(Parser)]
#[command(name = "file_counter")]
#[command(about = "指定ディレクトリ内のファイル数をカウント")]
struct Args {
    /// カウント対象のディレクトリ
    #[arg(short, long, default_value = ".")]
    dir: String,
}

fn main() -> std::io::Result<()> {
    let args = Args::parse();

    let mut count = 0;
    for entry in fs::read_dir(&args.dir)? {
        let entry = entry?;
        if entry.file_type()?.is_file() {
            count += 1;
        }
    }

    println!("{}内のファイル数: {}", args.dir, count);

    Ok(())
}

実行:

# デフォルト(カレントディレクトリ)
cargo run

# ディレクトリ指定
cargo run -- --dir /path/to/directory

コマンドラインオプションが使えるツールができました!


テストの実行

ユニットテストの書き方

src/lib.rs(または任意の.rsファイル):

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

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

    #[test]
    fn test_add() {
        assert_eq!(add(2, 3), 5);
    }

    #[test]
    fn test_add_negative() {
        assert_eq!(add(-1, 1), 0);
    }
}

テスト実行:

cargo test

出力:

running 2 tests
test tests::test_add ... ok
test tests::test_add_negative ... ok

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

統合テスト

testsディレクトリに配置:

project/
├── Cargo.toml
├── src/
│   └── lib.rs
└── tests/
    └── integration_test.rs

tests/integration_test.rs:

use my_library::add;

#[test]
fn test_add_integration() {
    assert_eq!(add(10, 20), 30);
}

テストのフィルタリング

特定のテストだけ実行:

cargo test test_add

特定のモジュールのみ:

cargo test tests::

テストオプション

並列実行を無効化:

cargo test -- --test-threads=1

出力を表示:

cargo test -- --nocapture

通常は成功したテストのprintln!は表示されませんが、これで表示されます。


ドキュメントの生成

ドキュメントコメントの書き方

関数のドキュメント:

/// 2つの数を足し算します。
///
/// # 例
///
/// ```
/// let result = my_library::add(2, 3);
/// assert_eq!(result, 5);
/// ```
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

モジュールのドキュメント:

//! このクレートは数学関数を提供します。
//!
//! # 使い方
//!
//! ```
//! use my_library::add;
//!
//! let sum = add(1, 2);
//! ```

pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

ドキュメント生成

生成:

cargo doc

生成して開く:

cargo doc --open

ブラウザでtarget/doc/プロジェクト名/index.htmlが開きます。

依存関係のドキュメントも含める

cargo doc --no-deps    # 自分のプロジェクトのみ
cargo doc              # 依存関係も含める(デフォルト)

ワークスペース

ワークスペースとは

複数のパッケージを一つのプロジェクトで管理する仕組みです。

使用例:

  • 本体アプリとCLIツールを同じリポジトリで管理
  • ライブラリと使用例を一緒に管理

ワークスペースの作成

ディレクトリ構造:

my_workspace/
├── Cargo.toml       # ワークスペースの設定
├── app/
│   ├── Cargo.toml
│   └── src/
│       └── main.rs
└── library/
    ├── Cargo.toml
    └── src/
        └── lib.rs

my_workspace/Cargo.toml:

[workspace]
members = [
    "app",
    "library"
]

app/Cargo.toml:

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

library = { path = “../library” }

ワークスペースでのビルド

すべてビルド:

cargo build

特定のパッケージのみ:

cargo build -p app
cargo build -p library

特定のパッケージを実行:

cargo run -p app

設定とカスタマイズ

ビルドプロファイル

Cargo.tomlでカスタマイズ:

[profile.dev]
opt-level = 0        # 最適化レベル(0-3)

opt-level = 3 # 最大最適化 lto = true # Link Time Optimization codegen-units = 1 # 並列コンパイル数(少ないほど最適化される)

フィーチャーフラグ

条件付きコンパイル:

Cargo.toml:

[features]
default = ["json"]
json = ["serde_json"]
xml = ["quick-xml"]

serde_json = { version = “1.0”, optional = true } quick-xml = { version = “0.31”, optional = true }

使用側:

# デフォルトフィーチャー(json)
cargo build

# xmlフィーチャーを有効化
cargo build --features xml

# すべてのフィーチャーを有効化
cargo build --all-features

# デフォルトフィーチャーを無効化
cargo build --no-default-features

カスタムコマンド

cargo-expandのインストール:

cargo install cargo-expand

マクロ展開を表示:

cargo expand

よく使うサブコマンドまとめ

コマンド説明
cargo new新規プロジェクト作成
cargo buildビルド
cargo runビルド+実行
cargo checkエラーチェックのみ
cargo testテスト実行
cargo docドキュメント生成
cargo cleanビルド結果を削除
cargo add依存関係を追加
cargo update依存関係を更新
cargo publishcrates.ioに公開
cargo installバイナリをインストール
cargo searchcrates.ioを検索
cargo tree依存関係ツリー表示

トラブルシューティング

問題1:ビルドが遅い

原因:
依存関係が多い、フルビルドしている。

解決策:

インクリメンタルコンパイルを有効化(通常は有効):

[profile.dev]
incremental = true

cargo checkを活用:

cargo check  # フルビルドより速い

並列コンパイル数を増やす:

cargo build -j 8  # 8並列

問題2:依存関係の競合

症状:

error: failed to select a version for `serde`

解決策:

依存関係ツリーを確認:

cargo tree

バージョンを明示的に指定:

[dependencies]
serde = "=1.0.150"

問題3:古いバージョンが使われる

解決策:

Cargo.lockを削除して再ビルド:

rm Cargo.lock
cargo build

強制的に最新版に更新:

cargo update

問題4:ディスク容量不足

原因:
targetディレクトリが肥大化。

解決策:

クリーンアップ:

cargo clean

古いプロジェクトを一括クリーン:

cargo install cargo-cache
cargo cache --autoclean

よくある質問

Q1: cargo buildとcargo runの違いは?

A:

cargo build: ビルドのみ(実行ファイルを生成)

cargo run: ビルド+実行(開発中に便利)

実行だけしたい場合は、直接実行ファイルを起動することもできます:

./target/debug/プロジェクト名

Q2: releaseビルドはどれくらい速い?

A: 用途によりますが、2〜10倍速くなることがあります。

数値計算や画像処理など、CPU負荷の高い処理ほど差が大きくなります。

ベンチマーク時は必ずreleaseビルドを使いましょう。

Q3: Cargo.lockはGitにコミットすべき?

A:

実行可能プロジェクト: YES(コミットする)

ライブラリプロジェクト: NO(.gitignoreに追加)

実行可能プロジェクトでは、全員が同じバージョンの依存関係を使うべきです。ライブラリは、使う側が依存関係を決定します。

Q4: crates.ioにない非公開ライブラリを使いたい

A: Gitリポジトリやローカルパスを指定できます。

Gitリポジトリから:

[dependencies]
my_lib = { git = "https://github.com/user/my_lib" }

特定のブランチ:

my_lib = { git = "https://github.com/user/my_lib", branch = "develop" }

ローカルパス:

my_lib = { path = "../my_lib" }

Q5: ビルドのキャッシュはどこに?

A: targetディレクトリと~/.cargoディレクトリです。

target/ プロジェクトごとのビルド結果

~/.cargo/registry/ ダウンロードした依存関係

~/.cargo/git/ Gitから取得した依存関係

ディスク容量が気になる場合は、cargo cleancargo cacheで削除できます。


まとめ

Cargoは、Rustのプロジェクト管理・ビルド・テスト・ドキュメント生成をすべて一つで行える、強力で便利なツールです。

この記事のポイント:

  • CargoはRustの公式パッケージマネージャー兼ビルドシステム
  • cargo newで簡単にプロジェクト作成
  • cargo runでビルド+実行が一発
  • 依存関係はCargo.tomlに書くだけで自動管理
  • crates.ioに100万以上のライブラリが公開されている
  • cargo testでテストが簡単に実行できる
  • cargo docでドキュメントを自動生成
  • リリースビルド(--release)で実行速度が大幅向上
  • ワークスペースで複数パッケージを管理可能
  • フィーチャーフラグで条件付きコンパイル
  • Rust開発に必要なものがすべて揃っている

Cargoは、Rustプログラミングをする上で欠かせないツールです。他の言語のように、パッケージ管理とビルドツールを別々に学ぶ必要がなく、Cargoひとつですべてが完結するのが大きな魅力なんです。

最初は覚えることが多いように感じるかもしれませんが、基本的なコマンド(newrunbuildtest)を使えるようになれば、快適に開発できるようになりますよ。

まずはcargo newでプロジェクトを作って、簡単なコードを書いてcargo runで実行してみてください。Rustプログラミングの楽しさを実感できるはずです!

Cargoをマスターして、効率的なRust開発を楽しんでいきましょう!

コメント

タイトルとURLをコピーしました