Rustでアプリケーションやライブラリを開発する際、避けては通れないのがパッケージマネージャーであるCargoの存在です。
そのCargoの設定を司るのがCargo.tomlというファイルです。
プロジェクトの名前やバージョン、依存するライブラリの管理、さらにはコンパイル時の最適化設定まで、Rustプロジェクトのあらゆる挙動がこの1つのファイルに集約されています。
本記事では、Rust初学者から中級者までが押さえておくべきCargo.tomlの書き方の基本から、効率的なプロジェクト管理のための応用テクニックまでを詳しく解説します。
Cargo.tomlの基本構造と役割
Cargo.tomlは、TOML(Tom’s Obvious, Minimal Language)形式で記述される設定ファイルです。
Rustプロジェクトのルートディレクトリに配置され、プロジェクトの構成要素をセクション([ ]で囲まれたブロック)単位で定義します。
このファイルの主な役割は、プロジェクト自体のメタデータを定義することと、外部ライブラリ(クレート)との依存関係を整理することにあります。
Cargo.tomlを適切に記述することで、開発環境の構築が容易になり、チーム開発においても一貫したビルド環境を維持することが可能になります。
[package]セクション:プロジェクトのアイデンティティ
もっとも基本的なセクションが[package]です。
ここではプロジェクト自体の名前、バージョン、使用するRustのバージョンなどを指定します。
基本的なメタデータの設定
まずは、プロジェクトの土台となる設定項目を見ていきましょう。
[package]
name = "my_rust_project" # プロジェクト名
version = "0.1.0" # セマンティックバージョニングに従ったバージョン
edition = "2024" # 使用するRustのエディション(2021や2024など)
authors = ["Your Name <email@example.com>"] # 開発者情報(任意)
description = "Cargo.tomlの書き方を学ぶためのサンプルプロジェクト"
license = "MIT" # ライセンス情報の指定
ここで特に重要なのがeditionです。
Rustには数年ごとに「エディション」という大きな区切りがあり、新しい言語機能を利用するためには適切なエディションを指定する必要があります。
2026年現在では、edition = “2024”を指定するのが標準的な選択となります。
公開用メタデータの追加
もし作成したライブラリをcrates.ioに公開する場合は、以下の項目も重要になります。
repository: ソースコードが管理されているURL(GitHubなど)homepage: プロジェクトの公式サイトkeywords: 検索で見つけやすくするためのキーワード(最大5つ)categories: crates.io上のカテゴリ分類
これらの情報を丁寧に記述することで、他の開発者があなたのライブラリを見つけやすくなり、信頼性も向上します。
[dependencies]セクション:依存関係の管理
Rustの強力なエコシステムを支えているのが依存関係の管理です。
外部のライブラリ(クレート)を使用する場合、[dependencies]セクションに記述します。
セマンティックバージョニング(SemVer)
Rustではバージョンの指定にセマンティックバージョニングを採用しています。
| 記述例 | 意味 |
|---|---|
serde = "1.0" | ^1.0.0 と同じ。1.x.x系で互換性がある最新版を使用 | |
serde = "1.0.150" | 1.0.150以上、2.0.0未満の最新版を使用 | |
serde = "=1.0.150" | 1.0.150ちょうどを使用(固定) | |
serde = ">1.0, <1.1" | 1.0より大きく1.1未満の範囲を指定 | |
通常は"1.0"のような記述(キャレット指定)が推奨されます。
これにより、破壊的変更を含まない安全なアップデートが自動的に適用されるようになります。
多様なソースからの取り込み
crates.io以外の場所にあるライブラリを取り込むことも可能です。
[dependencies]
# GitHubなどのリポジトリから直接取得
tokio = { git = "https://github.com/tokio-rs/tokio", branch = "master" }
# ローカルディレクトリにある自作クレートを利用
my_utils = { path = "../my_utils" }
開発中の複数のクレートを連携させる場合、path指定は非常に便利です。
また、特定の修正が必要な場合に一時的にgit参照に切り替えるといった運用もよく行われます。
開発・ビルド専用の依存関係
すべてのライブラリが最終的な製品(バイナリ)に含まれるわけではありません。
用途に応じてセクションを使い分けることで、ビルド効率を高めることができます。
[dev-dependencies]
テストコードやベンチマーク、サンプルの実行時にのみ必要なライブラリを記述します。
例えば、テスト時のみ使用するモックライブラリなどはここに含めます。
これにより、通常ビルド時のバイナリサイズを軽量に保つことができます。
[build-dependencies]
Rustのソースコードをコンパイルする前に実行される「ビルドスクリプト(build.rs)」が必要とするライブラリを記述します。
C言語のライブラリをリンクするための設定ツールなどがこれに該当します。
[features]セクション:機能の条件付きコンパイル
大規模なライブラリを開発する場合、すべての機能を常に有効にするとビルド時間が長くなり、バイナリサイズも肥大化します。
これを解決するのがFeatureフラグです。
[dependencies]
serde = { version = "1.0", features = ["derive"] } # derive機能を有効化
[features]
default = [“json”] # デフォルトで有効にする機能 json = [“serde”, “serde_json”] # json機能を有効にすると関連ライブラリも読み込む full = [“json”, “extra_feature”] # 複数の機能をまとめることも可能
利用者は、以下のように必要な機能だけを選択してインストールできます。
// 利用側のCargo.toml
[dependencies]
my_library = { version = “1.0”, features = [“json”] }
コード内では#[cfg(feature = "json")]という属性を使用することで、特定の機能が有効なときだけコンパイルされるブロックを作成できます。
[profile]セクション:ビルド設定の最適化
開発時とリリース時で、コンパイルの挙動を調整したい場合があります。
Cargo.tomlでは[profile.dev](デバッグ用)や[profile.release](本番用)というセクションを使ってこれらを制御します。
パフォーマンスとバイナリサイズの最適化
リリース用バイナリを極限まで速く、あるいは小さくしたい場合は以下のような設定を検討します。
[profile.release]
opt-level = 3 # 0〜3で最適化レベルを指定(3が最高速)
lto = true # Link Time Optimizationを有効化(実行速度向上)
codegen-units = 1 # コンパイル単位を1に制限(最適化の機会が増えるがビルドは遅くなる)
panic = "abort" # パニック時にスタックトレースを破棄してバイナリを削減
LTOを有効にすると、リンク時にプロジェクト全体を横断して最適化が行われるため、実行速度が劇的に向上することがあります。
ただし、コンパイル時間は相応に長くなるため、開発効率とのトレードオフになります。
Workspaces:大規模プロジェクトの管理
複数のクレートを1つのリポジトリで管理する「モノレポ」構成の場合、Workspace機能が欠かせません。
ルートディレクトリのCargo.tomlに以下のように記述します。
[workspace]
members = [
"crate_a",
"crate_b",
"utils/*",
]
resolver = "2" # 新しい依存関係解決アルゴリズムの使用
依存関係の共有(workspace.dependencies)
最近のRustでは、ワークスペース全体でライブラリのバージョンを統一する仕組みが導入されています。
# ルートのCargo.toml
[workspace.dependencies]
serde = “1.0.150” # 子クレート(crate_a/Cargo.toml)
[dependencies]
serde = { workspace = true } # ルートで定義したバージョンが使われる
これにより、プロジェクト全体でライブラリのバージョンがバラバラになることを防ぎ、メンテナンス性を大幅に向上させることができます。
[lints]セクション:コード品質の統一
Rust 1.74以降、Cargo.toml内でコンパイラの警告(Lints)を一括管理できるようになりました。
これにより、チーム全体で同じコーディング規約を強制することが容易になりました。
[lints.rust]
unsafe_code = "forbid" # unsafeコードを禁止
unused_variables = "warn" # 未使用変数に警告を出す
[lints.clippy]
pedantic = “warn” # Clippyのより厳しいチェックを有効化
従来は各ソースファイルの先頭に#![warn(...)]と書く必要がありましたが、Cargo.tomlで管理することでプロジェクト全体の見通しが良くなります。
Cargo.lockとの違い
Cargo.tomlを編集すると、ビルド時にCargo.lockというファイルが自動生成または更新されます。
この2つの違いを理解しておくことは非常に重要です。
- Cargo.toml: 開発者が「どのような範囲のバージョンを許可するか」という意図を記述するもの。
- Cargo.lock: 実際にビルドで使用された「特定のバージョン」を固定(ロック)するもの。
アプリケーション開発においては、Cargo.lockもGit管理に含めるべきです。
これにより、他の開発者の環境やデプロイ環境でも寸分違わぬ依存ライブラリの構成でビルドされることが保証されます。
一方、ライブラリ開発の場合は、利用者の環境で柔軟にアップデートが行われるよう、Cargo.lockをGit管理に含めないのが一般的です。
まとめ
Cargo.tomlは単なる依存関係のリストではなく、Rustプロジェクトの品質やパフォーマンス、そして開発体験を左右する重要な設計図です。
[package]で適切なメタデータとエディションを設定する。[dependencies]ではSemVerを意識し、必要に応じてgitやpathを使い分ける。[features]を活用して、再利用性の高い構成を目指す。[profile]設定によって、用途に応じた最適なバイナリを生成する。[workspace]や[lints]を利用して、大規模開発の保守性を高める。
これらの書き方をマスターすることで、Rustのビルドシステムが持つ強力な恩恵を最大限に引き出すことができます。
2026年のモダンなRust開発においても、基本を大切にしつつ、新しく追加された便利な機能を積極的に取り入れて、より洗練されたプロジェクト管理を実践していきましょう。
