cargoのどこがいいのか
κeenです。久しぶりのブログですね。 LLイベントに行ってきたらパッケージマネージャの話がありました。 その懇親会でcargoについて振られたんですがタイミングがなくて喋れなかったのでブログに書いておきます。
ざっくりまとめると
- パッケージマネージャ/ビルドツールに要求される要件を卒なくこなしている
- 面倒を見る範囲が広く、要はワンストップソリューションだから便利
- コンパイラと同じ母体が開発してるのでグダグダがない
じゃないかなと思います。あとバイナリなのでキビキビ動く。 因みにcargoが便利という声の中にはcrates.ioで欲しいパッケージを探しやすいだとかみんな割とセマンティックバージョニングを守るので理不尽にビルドがコケたりしないなどもあると思います。
1に関しては最近のよくあるベストプラクティスを全部やったらこうなったって感じですね。
- セマンティックバージョニングで依存関係を管理
- 必要とあればgitからソースを取得することも可能
- 依存関係のプロジェクト毎の隔離。他のプロジェクトをビルドしてグローバル環境が壊れたりしない。
- lockファイルで再現性のあるビルド
- パッケージのフェッチからビルドまで1アクション
- 設定を書かなくてもソースはsrc以下に放り込んだら勝手にビルド
- ビルド成果物も他のプロジェクトとコンフリクトしたりしない
- ライブラリもバイナリも扱える
- テスト用などの開発時専用依存関係も書ける
ほとんどの他のパッケージマネージャも8, 9割くらいは同じことを実現できてると思いますがcargoは全部やってます。
2に関しては
- スケルトン作成 (cargo new)
- エラーチェック (cargo check)
- プロジェクト定義/パッケージ定義/依存関係定義 (Cargo.toml)
- ビルド (cargo build)
- なんなら(プロジェクトのFFIで呼び出す)Cのソースのビルド/リンクも出来る (build.rs)
- 実行 (cargo run)
- テスト (cargo test)
- これはRustが言語組み込みでテスト機能を持ってるのにも依存している
- exampleの実行 (cargo run –example)
- ドキュメント生成
- 依存ライブラリのも含むので開発用に参照する用途にも使える
- パッケージの登録 (cargo publish)
- パッケージバイナリのインストール (cargo install)
- パッケージレジストリも(今の所)唯一のcrates.ioだけなのでゼロコンフィギュレーションで使える
この他には細かいところだとワークスペース機能があるので複数のプロジェクトをまとめることもできます。 あとはプラグインシステムでサブコマンドを自由に作れるのでCargo.tomlをCLIで編集するcargo-edit、プロジェクトのソースコード全てをフォーマットするcargo-fmt等も有ります。
とにかくパッケージを登録するまで全てcargoが面倒を見るのでユーザ側もCargo.tomlだけ書いていればいいのが非常に楽です。 ライブラリのソースコードを読むときも私は大体Cargo.tomlから見ます。
3はたとえばrustがeditionという概念を導入したら同時にcargoがeditionディレクティブを入れたり最新の機能がスムーズに利用できるようになってます。 地味にコンパイラと一緒に配布されているのでコンパイラバージョンとビルドツールバージョンの組み合わせを考えなくていいのもいいポイントですね。
有志で作ると個人の限界で複数のツールに分かれがちなところをマンパワーで殴ってワンストップソリューションまでもっていけたのが効いてるんですかね。
もちろん、cargo以外にも良いパッケージマネージャ/ビルドツールはあると思います。cargoを一例として挙げてみました。
逆にCargoに足りないものもあります。
1つには名前空間があります。 たとえばIronというフレームワークのミドルウェアの1つが“mount”という名前になっていたりする世界観です。 そのせいか名前予約のために空のクレートを登録するなどの治安事案も発生していたりします。
あるいはシンプルにcrates.ioのウェブサイトが遅い。代替のcrates.rsなんかが作られたりしています。
並列ビルドや差分コンパイルも悩みの種です。 cargoというかrustは1プロジェクト(クレート)単位でコンパイルするので1つの巨大なコードベースだとコンパイルが遅くなりますし、1行編集するだけで全体が再コンパイルになります。 一応インクリメンタルコンパイルが入っていたりはしますが…。
まとめ
cargoは巨大なマンパワーで快適さが実現されてる