🦉

Cargo のワークスペースの構造がやっと理解できた

2022/04/01に公開約2,300字

はじめに

これは本家のドキュメントで躓いた理解力の乏しい人向けの記事です。

本家では addadderadd-one を作る例になっていたため私はまず名前で混乱しました。その上、常識的に考えて add が人に説明するときのワークスペース名なわけがないだろうと勝手な先入観を持ってしまいました。そこでドキュメントには書いてないけどあらかじめワークスペースとなるその親ディレクトリを cargo new で用意しとかないといけないのかな? と、ディレクトリ構造を深くしてしまったり、add 自体を cargo new で作ったりと無駄な試行錯誤を重ねてしまいました。

わかったことを一言で言えば、
共通の何もない親に子のディレクトリ名を列挙した Cargo.toml を置く
たったそれだけのことでした。

なんなら本家のドキュメントその1行でよかったぐらいです。

確認用スクリプト

少し長いかもしれないけどこの内容と実行結果を見るだけで確実に理解できると思います。

#!/bin/sh
rm -fr /tmp/my_workspace1
mkdir -p /tmp/my_workspace1
cd /tmp/my_workspace1

cargo new --bin my_project1
cargo new --bin my_project2

(cd my_project1 && cargo build)
(cd my_project2 && cargo build)

exa -T -F -I "deps|incremental|debug|*.d|*.TAG"

(cd my_project1 && cargo clean)
(cd my_project2 && cargo clean)

cat <<'EOF' > Cargo.toml
[workspace]
members = [
  "my_project1",
  "my_project2",
]
EOF

cargo build

exa -T -F -I "deps|incremental|debug|*.d|*.TAG"

実行結果

./
├── my_project1/
│  ├── Cargo.lock
│  ├── Cargo.toml
│  ├── src/
│  │  └── main.rs
│  └── target/
└── my_project2/
   ├── Cargo.lock
   ├── Cargo.toml
   ├── src/
   │  └── main.rs
   └── target/
./
├── Cargo.lock
├── Cargo.toml
├── my_project1/
│  ├── Cargo.lock
│  ├── Cargo.toml
│  └── src/
│     └── main.rs
├── my_project2/
│  ├── Cargo.lock
│  ├── Cargo.toml
│  └── src/
│     └── main.rs
└── target/

1つ目は単に my_project1my_project2 が別々にあるだけです。
2つ目は親に Cargo.tomltarget ディレクトリ があるのがわかります。

まとめ・わかったこと

  1. cargo のサブコマンドとして workspace があるわけではない
    • ググると cargo workspace という表記があったりするがなんも関係なかった
  2. 共通のワークスペースディレクトリ(親)を cargo new で作ってはならぬ
  3. 親は空でよい
    • cargo new で作った子のディレクトリがあるだけという意味
  4. 子のディレクトリ名を列挙した Cargo.toml を新規で親に置く
    • 親の Cargo.toml子を作ったあとで置く
    • 先に作ってしまうと cargo new --bin my_project1 をするとき、別に今読む必要はないのに親の Cargo.toml を読み込んで、あとから作成する予定の my_project2 がないと騷ぎ立てるため面倒なことになる
  5. 親で cargo build すると子がビルドされる
  6. ビルド結果は親の target/ に生成される
  7. いろいろ集約されることで依存関係がいい感じになったりビルド時間が短縮できる
  8. 親から cargo test すると子のテストを順に実行してくる
  9. とはいえ親から cargo run としても子を順番に実行したりはしない
    • 何を実行したらいいのかわからないと言われる
  10. 親から cargo run -p my_project1 とすると実行するものを指定できる
    • my_project1 のなかで cargo run するのと同じなので別に親から実行しないといけないわけじゃない

参照

https://doc.rust-jp.rs/book-ja/ch14-03-cargo-workspaces.html

Discussion

ログインするとコメントできます