4 分で読了 #rust #cargo-and-build
このページの目次

ワークスペースとプロジェクト管理

プロジェクトに複数の相互依存するクレート(コアライブラリ+APIサーバー+CLIなど)が含まれている場合、ワークスペースはそれらに同じ Cargo.lock と target ディレクトリを共有させます。これにより、コンパイルキャッシュの再利用や依存バージョンの統一が可能になります。patch を使用すると、開発中に特定の依存のソースコードを一時的に置き換えることができ、build.rs はコンパイル前にコード生成を実行します。

ワークスペース: 1つのリポジトリで複数のクレート

プロジェクトに複数の相互依存するクレート(コアライブラリ+APIサーバー+CLIなど)が含まれている場合、1つのワークスペースに配置することには以下の3つの利点があります。

[workspace]
members = ["crates/core", "crates/api", "crates/cli"]
resolver = "2"
  1. ビルド成果物の共有⁠: すべてのメンバーが target/ ディレクトリを共有するため、依存関係は1回だけコンパイルされ、ディスク容量とコンパイル時間が大幅に削減されます。
  2. バージョンの一貫性⁠: Cargo.lock はワークスペースレベルで共有されるため、すべてのメンバーが同じバージョンの依存関係を確認できます。
  3. 内部からの相互参照⁠: apipath = "../../crates/core" を使用して core を直接参照できます(crates.io への公開は不要です)。

[workspace.dependencies]: バージョン宣言の共有

1.64以降では、ルート Cargo.toml でバージョンを宣言し、メンバーがキーで参照できるようになりました。

[workspace.dependencies]
serde = "1"
tokio = { version = "1", features = ["full"] }

# 各メンバー: [dependencies] → serde = { workspace = true }

これにより、複数のクレートを含むプロジェクトにおける「依存バージョンが各所に散在しており、アップグレード時に特定の箇所を見逃してしまう」という古典的な問題を解決します。バージョンを1箇所変更するだけで、すべてのメンバーが更新されます。

[patch]: 依存の一時的な置き換え

アップストリームのクレートにバグがあり、アップストリームが修正するまでフォーク版を使用したい場合:

[patch.crates-io]
serde = { git = "https://github.com/myfork/serde", branch = "fix" }

注意:[patch] 内のバージョンはワークスペース全体で互換性がある必要があります。メンバーの1つが serde 1.0 を、もう1つが serde 1.3 を依存している場合、フォークは両方のAPIを満たす必要があります。そのため、フォークでは内部ロジックのみを変更し、公開APIを変更しないことが推奨されます。

build.rs の高度な活用

// build.rs — メインコードのコンパイル前に実行される
fn main() {
    // 再実行条件: これらの条件が変化した時のみ再実行
    println!("cargo:rerun-if-changed=src/c/wrapper.h");
    println!("cargo:rerun-if-env-changed=MY_LIB_PATH");

    // システムライブラリのリンク
    println!("cargo:rustc-link-search=native={}", my_lib_dir);
    println!("cargo:rustc-link-lib=static=my_lib");

    // メインコードに cfg を渡す — #[cfg(has_avx2)] を有効にする
    println!("cargo:rustc-cfg=has_avx2");
}

build.rs は主に、C/C++ の依存関係のコンパイル(cc クレート経由)、システムライブラリの存在確認、コード生成(protobuf, OpenAPI)、feature フラグの設定に使用されます。

参考

  • Cargo Book: ワークスペース、ビルドスクリプト
  • cc crate: docs.rs/cc

Keywords: ワークスペース, メンバー, patch, build.rs, 共有依存関係, マルチクレート, Cargo.lock