Contents
Cargo の概要と crates.io との連携
Cargo は Rust 標準のビルドツール兼パッケージマネージャです。コードコンパイルだけでなく、依存クレートの取得・バージョン解決・ロックファイル管理までを一貫して行うため、個人開発でもチーム開発でも必須となります。このセクションでは Cargo の全体像と、デフォルトで利用される公式レジストリ crates.io への接続方法を確認します。
Cargo が担う主な役割
Cargo は以下の3つの大きな機能を提供します。
- ビルドとテストの自動化
cargo build,cargo testなどの単一コマンドでコンパイル・ユニットテスト・ベンチマークが実行できます。 - 依存解決とキャッシュ
Cargo.tomlに記載されたバージョン範囲から最適なクレートを自動的に選択し、取得したソースはローカルの~/.cargo/registryと~/.cargo/gitに保存されます。キャッシュはプロジェクト間で共有できるため、同一バージョンの再取得が不要です(詳しくは Qiita の解説記事を参照: https://qiita.com/takashi/items/4c0b9a5d1e6f2b8e7b3a)。 - レジストリとの安全な通信
Cargo は TLS 経由で crates.io とやり取りし、Git リポジトリ形式のインデックスからメタ情報を取得します。インデックス自体は~/.cargo/gitにクローンされ、ローカルで高速に検索できます。
crates.io との接続方法
crates.io は Cargo のデフォルトレジストリです。特別な設定を行わなくても以下の流れで利用可能です。
| 手順 | 説明 |
|---|---|
| 1. トークン取得 | crates.io の Web UI から「API token」を発行します。 |
| 2. ローカルに保存 | cargo login <token> を実行し、~/.cargo/credentials に安全に保管します。 |
| 3. デフォルト設定の確認 | ~/.cargo/config.toml が無い場合は Cargo が内部でデフォルト設定(index = "https://github.com/rust-lang/crates.io-index")を使用します。 |
公式ドキュメント: https://doc.rust-lang.org/cargo/reference/registry.html
Cargo.toml の基本構造とバージョン指定
Cargo.toml はプロジェクトのメタ情報と依存関係を記述する中心ファイルです。ここでは主要セクションと、実務で頻繁に使うバージョン演算子の正しい意味を解説します。
主要セクションの概要
Cargo.toml はテーブル形式で項目が区分けされており、目的別に依存を管理できます。以下は代表的なテーブルとそのキー例です。
| セクション | 用途 | 主なキー例 |
|---|---|---|
[package] |
パッケージ情報(名前・バージョン・著者等) | name = "my_project" |
[dependencies] |
本番ビルドで必要なクレート | serde = "1.0" |
[dev-dependencies] |
テスト・ベンチマーク用のクレート | rand = "^0.8" |
[build-dependencies] |
ビルドスクリプト (build.rs) が利用するクレート |
cc = "1.0" |
[workspace] |
複数クレートをまとめて管理(メンバーリスト) | members = ["core", "cli"] |
バージョン演算子の正しい意味
バージョン指定は SemVer(セマンティック・バージョニング)に基づく互換性保証と、更新頻度のバランスを取るために重要です。各演算子の挙動は次の通りです。
| 演算子 | 意味 | 例 |
|---|---|---|
^(キャレット) |
メジャーバージョンが同じ 範囲を許容。例えば ^1.2.3 は >=1.2.3 <2.0.0 に相当します。 |
serde = "^1.0" → 1.x 系全体 |
~(チルダ) |
マイナーバージョンが同じ 範囲を許容。~1.2.3 は >=1.2.3 <1.3.0 に相当します。 |
regex = "~1.5" → 1.5.x 系 |
=(等号) |
完全に固定 したバージョンを指定。Cargo.lock がなくても常に同じものが使用されます。 | log = "=0.4.14" |
*(アスタリスク) |
任意のバージョン を許容します。依存解決時には、他の制約が無い限り 利用可能な最新バージョン が選択されますが、必ずしも「最新版」になるわけではなく、同一レジストリ内で最も新しいものが対象です。破壊的変更が入るリスクがあるため、実務では使用を控えることが推奨されます。 | log = "*" |
参考: Rust 官方文档「Dependency Specification」https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
実務シナリオ別:依存関係の追加・更新・削除
プロジェクトのライフサイクルに応じて、依存管理のベストプラクティスは変わります。この章では「新規追加」「手動編集と cargo add の使い分け」「バージョン固定と cargo update」の3つのシナリオを具体例とともに示します。
新規プロジェクトで依存クレートを追加する手順
まずは Cargo が提供するサブコマンド cargo add(cargo-edit クレート)を利用した流れです。
- プロジェクト作成
bash
cargo new my_project
cd my_project - 依存クレートの追加(例:
serdeとtokio)
bash
cargo add serde --features derive
cargo add tokio --features full - 生成された Cargo.toml の確認
- 期待したバージョン範囲が設定されているか。
- 必要に応じて
^や~に手動で書き換える。
手動編集と cargo add/remove の使い分け
| ケース | 推奨方法 | 理由 |
|---|---|---|
条件コンパイル (cfg) 用の依存 |
手動で [target.'cfg(windows)'.dependencies] を記述 |
Cargo.toml に構造的な情報が必要になるため。 |
| 複数クレートに同一バージョンを一括適用 | cargo edit の replace-version など手動でスクリプト化 |
大規模リファクタリングでは正確性が重要。 |
| 単純な追加・削除(例: テスト依存) | cargo add <crate> / cargo remove <crate> |
コマンドだけで Cargo.lock が自動更新されるため高速。 |
Aetheria の実務記事では、cargo add --optional, --default-features false など高度なオプションの使い方が詳しく解説されています(参照: https://aetheria.jp/articles/cargo-add-options)。
バージョン固定と cargo update の活用
安定運用では Cargo.lock と組み合わせてバージョンをロックし、必要に応じて計画的に更新します。
| 操作 | コマンド例 | 効果 |
|---|---|---|
| 正確なバージョンで追加(ロック) | cargo add foo = "1.2.3" |
Cargo.lock にハッシュが保存され、ビルド再現性が保証される。 |
| 範囲内の最新マイナーバージョン取得 | cargo update -p foo |
[dependencies] の範囲に従い、ロックファイルを更新。 |
| 全体更新(注意) | cargo update |
すべての依存が再解決される。CI ではブレを防ぐため --locked オプションと組み合わせることが推奨される。 |
ローカルパス・Git リポジトリからの依存設定と Workspace の活用
社内クレートや開発中ブランチを直接参照したいケースは多くあります。また、複数クレートを統合的に管理できる Workspace は大規模プロジェクトで必須です。
ローカルディレクトリ依存の記述例
ローカルパスを使うと、ビルドが高速になるだけでなく、変更が即座に反映されます。
|
1 2 3 |
[dependencies] my_utils = { path = "../my_utils" } |
- ポイント
- 相対パスでも絶対パスでも指定可。
- Cargo.lock にハッシュが保存されるため、CI 上でも同一ソースが再現できます。
Git リポジトリ依存の記述例
Git URL とブランチ・タグ・コミットハッシュを組み合わせて柔軟に指定できます。
|
1 2 3 4 5 |
[dependencies] awesome_lib = { git = "https://github.com/example/awesome_lib.git", rev = "a1b2c3d" } # タグ指定の場合 # awesome_lib = { git = "https://github.com/example/awesome_lib.git", tag = "v0.2.0" } |
- 注意点
rev(コミットハッシュ)で固定すると、再現性が完全に保証されます。branch指定は開発ブランチの最新を取得するため、cargo updateが必要になるケースがあります。
Workspace によるクレート階層管理
Workspace はルート Cargo.toml にメンバーリストを列挙し、全体で単一の Cargo.lock を共有します。これによりビルド時間が短縮され、依存バージョンの衝突も防げます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# ルート Cargo.toml(workspace のみ) [workspace] members = [ "core", "cli", "utils" ] # core/Cargo.toml の例 [package] name = "core" version = "0.1.0" [dependencies] serde = "^1.0" |
- メリット(KumaROOT ドキュメント参照: https://kumaroot.com/docs/workspace)
- 複数クレートが同一
Cargo.lockを共有し、全体の依存バージョンが統一される。 cargo test --workspaceやcargo build --workspaceで一括操作が可能になる。
Cargo.lock の扱いと CI/CD における再現性確保
ロックファイルは「同一の依存ツリーでビルドできる」ことを保証する重要なアーティファクトです。プロジェクト種別(バイナリ vs ライブラリ)に応じた取り扱いと、CI でのキャッシュ戦略について詳しく解説します。
Cargo.lock の基本的な役割
- バイナリ(実行可能ファイル)プロジェクト
Cargo.lockを 必ずコミット。これによりローカル開発者・CI 環境が同一依存ツリーでビルドでき、予期せぬアップデートによるビルドエラーを防止します。- ライブラリ(crate)プロジェクト
- 基本的に
Cargo.lockは コミットしない。利用側のアプリケーションがロックファイルを生成するため、上位プロジェクトでバージョン統一が可能です。ただし、以下の例外があります。
| ケース | 推奨方針 |
|---|---|
ライブラリ単体で CI ビルド(例: cargo test だけを走らせる) |
Cargo.lock をコミットしておくとビルド時間が安定し、キャッシュのヒット率が上がります。 |
| Workspace のルートにロックファイルが存在する場合 | Workspace 全体で共有されるため、個別クレートは Cargo.lock を持たなくても問題ありません。 |
CI では
cargo build --lockedやcargo test --lockedを使用すると、ロックファイルと乖離した依存取得がブロックされます。
CI パイプラインでのキャッシュ活用例(GitHub Actions)
以下は Cargo のレジストリと Git リポジトリをキャッシュし、ビルド時間を短縮するテンプレートです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
name: CI on: push: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 # Cargo のレジストリキャッシュ(crate ソース) - name: Cache cargo registry uses: actions/cache@v3 with: path: ~/.cargo/registry key: ${{ runner.os }}-cargo-registry-${{ hashFiles('Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-registry- # Cargo の Git リポジトリキャッシュ(git 依存) - name: Cache cargo git repos uses: actions/cache@v3 with: path: ~/.cargo/git key: ${{ runner.os }}-cargo-git-${{ hashFiles('Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-git- # ビルド(ロックファイルに忠実に実行) - name: Build run: cargo build --locked --verbose # テスト実行 - name: Test run: cargo test --locked --no-fail-fast |
- ポイント
hashFiles('Cargo.lock')をキーに入れることで、依存が変わったときだけキャッシュが再生成されます。--lockedオプションはロックファイルと不整合がある場合にビルドを失敗させるため、CI の再現性が保証されます。
crates.io への公開手順と運用ベストプラクティス
社外向けのクレートを公開する際は、正しい手順とトラブル時の対処法を把握しておくことが重要です。ここでは cargo publish の流れ、事前チェック項目、そしてバージョニング・yank の活用方法をまとめます。
公開前の準備チェックリスト
- 認証トークンの設定
bash
cargo login <your-token> - ローカルでビルドとテスト(全機能が通ることを確認)
bash
cargo test --all
cargo clippy -- -D warnings - パッケージ内容の検証 (
Cargo.tomlのexclude/includeを活用)
bash
cargo package --list # 何が含まれるか一覧表示
cargo package --allow-dirty # 未コミットでも確認できる(CI 用) - ドキュメントと例のビルド
cargo doc --no-depsが成功すること。- README が Markdown で正しくレンダリングされるかをプレビュー。
詳細な手順は issoh の実践記事にまとめられています(参照: https://issoh.dev/blog/cargo-publish-yank)。
cargo publish 実行と失敗時の対処
|
1 2 |
cargo publish |
- 失敗例:バージョンがすでに存在する、または依存解決エラー。
- バージョンをインクリメント(パッチアップデート)して再挑戦。
cargo yank <version>で問題のあるバージョンだけ非表示にし、次のバージョンで再公開。
SemVer に基づくバージョン管理
| バージョン種別 | 増分例 | 用途 |
|---|---|---|
パッチ (0.1.x → 0.1.y) |
cargo publish 前に patch を増やす |
バグ修正、軽微な改善 |
マイナー (0.x.0 → 0.y.0) |
cargo publish 前に minor を増やす |
後方互換性のある新機能追加 |
メジャー (x.0.0 → y.0.0) |
cargo publish 前に major を増やす |
破壊的変更、API の大幅改変 |
緊急で問題が見つかった場合は次のコマンドでバージョンを非表示にできます。
|
1 2 |
cargo yank <version> |
社内プライベートレジストリの設定例
社内向けクレートは GitHub Packages や Azure Artifacts などのプライベートレジストリに公開します。以下は実際に使える ~/.cargo/config.toml のサンプルです。
|
1 2 3 4 5 6 7 8 |
# .cargo/config.toml [registry] # crates.io とは別に社内インデックスを指定 index = "https://my-registry.example.com/git/index" [registries.my-company] index = "https://my-registry.example.com/index" |
- ポイント
indexはレジストリの Git インデックス URL。実際に運用しているサーバーのパスを記述してください(例:https://registry.mycorp.com/git/crates-index)。- CI では同じ設定ファイルをプロジェクトルートかホームディレクトリに配置し、認証情報は GitHub Actions の
secrets.CARGO_REGISTRY_TOKEN等で安全に供給します。
まとめ
本稿では Cargo の全体像から実務的な依存管理手法、CI/CD における再現性確保、そして crates.io / プライベートレジストリへの公開までを網羅的に解説しました。以下のポイントを押さえておけば、ビルドエラーやバージョン衝突に悩まされることが格段に減少します。
- Cargo の役割と crates.io へのデフォルト接続は把握しているか
Cargo.tomlのバージョン演算子の意味を正しく使い分けているか(特に*は避ける)- ロックファイルの扱いをプロジェクト種別に合わせて管理できているか(バイナリは必ずコミット、ライブラリは状況次第)
- CI でキャッシュと
--lockedオプションを活用し、ビルドの再現性を保証しているか - 公開前チェックリストと SemVer に基づくバージョニング手順を実践できているか
これらを日常的に意識すれば、Rust 開発チーム全体の生産性が向上し、安定したデリバリーが可能になります。ぜひ本ガイドを手元に置き、プロジェクトごとに適用してみてください。