Cargoパッケージマネージャ

Cargo [The Cargo Book] はRustに付属するパッケージマネージャです。CargoパッケージマネージャはCargoパッケージと呼ばれる単位で依存関係解決、バージョン管理、およびビルドを行います。Rustで書かれたライブラリ (標準ライブラリ含む) はCargoパッケージで表されますが、ライブラリの最終消費者であるアプリケーションや外部コードとリンク可能なスタティックライブラリ等も特別な設定をしたCargoパッケージとして表されます。

../../_images/cargo-deps.svg

SOLID-Rustの「Rustプロジェクト」は1つの主要なCargoパッケージを持ち、これをCargoを使用してビルドすることでスタティックライブラリを出力します。依存パッケージのダウンロードやビルドはCargoが必要に応じて自動的に行います。

Note

SOLID-Rustにおける複数Cargoパッケージから構成されるアプリケーションの扱い方については検討中です。

Cargoパッケージの定義は Cargo.toml というTOML形式のファイルで行います [The Cargo Book] 。以下に例を示します。

# パッケージ全般の設定項目。
[package]

# パッケージ名
name = "rust_lib1"

# パッケージバージョンを指定します。SOLID-Rustプロジェクトのようなパッケージ最終消費者に対しては
# あまり意味はありません。
version = "0.1.0"

# パッケージが使用するRustのエディションを指定します。エディションはRust言語に対して破壊的な変更
# (例えば、非推奨構文の削除) を導入するために使用されます。現時点で存在するエディションは2015,
# 2018, 2021です。
edition = "2021"

# このセクションで依存パッケージを指定します。
[dependencies]

[lib]
# SOLID-Rustプロジェクトでは外部コードとリンクするためのスタティックライブラリを
# 生成したいため、 "staticlib" を指定します。
crate-type = ["staticlib"]

crates.io

crates.ioはCargoパッケージマネージャがデフォルトで使用するパッケージレジストリです。Rustの多くのオープンソースライブラリはここで公開されています。ここで公開されているライブラリは Cargo.toml に簡単な記述 [The Cargo Book] を追加するだけで使用できます。

[dependencies]
log = "0.4"
env_logger = { version = "0.8.3", default-features = false }
hyper = "0.14"
itron = { version = "0.1.7", features = ["solid_asp3", "dcre"] }

Rustの標準ライブラリは後方互換性がきわめて重要であることから機能が最小限に絞られています。このため、簡単なプログラムでもcrates.io由来のパッケージを使用することは一般的なプラクティスです。

代表的なパッケージの例については Cargoパッケージの例 をご覧下さい。

crates.ioで提供されているライブラリをプロジェクトに追加する手順についてはチュートリアル crates.ioからパッケージを追加する をご覧下さい。

crates.io外のパッケージを利用する

Cargoはcrates.io以外の場所にあるパッケージを利用する方法をいくつか提供しています。ここではその一部を説明します。

git 属性で指定した依存パッケージはGitレポジトリから取得されます [The Cargo Book]

[dependencies]
regex = { git = "https://github.com/rust-lang/regex" }

path 属性で指定した依存パッケージはローカルファイルシステム上の別のディレクトリから取得されます [The Cargo Book]

[dependencies]
app_utils = { path = "../app_utils" }

crates.ioに接続できない状況でビルドできるようにするためにcrates.ioのパッケージをローカルにコピーして使用する方法があります (vendoringと呼びます)。cargo vendor コマンドについてはCargoの公式ドキュメント The Cargo Book を参照してください。

パッケージのバージョン指定

Cargo.toml ファイルの [dependencies] セクションでは、依存パッケージに求められるバージョンの条件を指定できます。

バージョン番号を単純に指定した場合、Semantic Versoning に基づいてそれと互換 (アプリケーションコードの修正なしで更新可能) なバージョン範囲を指すものとして扱われます。 例えば、以下のように指定した場合、log v0.4.2, v0.4.3, v0.4.10などが選択肢に含まれますが、v0.4.0, v0.5.0, v1.0.0が使用されることはありません。

[dependencies]
log = "0.4.2"

特別な要求に応えるために、単一バージョン指定 (e.g., log = "= 0.4.2") や任意の範囲指定など他の指定方法が存在します。 詳しくは公式ドキュメント The Cargo Book を参照してください。

バージョン指定に基づいて選択された最終的なバージョンはロックファイル (Cargo.lock) に記録されます。

ロックファイル

ロックファイル (Cargo.lock) はCargoが自動的に生成するTOML形式のファイルです。 ここには Cargo.tomlバージョン指定に基づいて選択された最終的なパッケージバージョン (間接的依存関係含む) が記録されます。 ロックファイルが一度作成されると、アプリケーションのビルド時にはここに記録されたパッケージバージョンが毎回使用されます。

注釈

パッケージの各バージョンに対応するソースコードは不変なので、Cargo.lock はプログラムのビルドに必要な外部コードを一意に表していると言えます。

バージョン管理システムを使用している場合、Cargo.lock を管理対象に含めることを推奨します。

Cargo.tomllog = "0.4" と指定した場合に生成される Cargo.lock の例を以下に示します。 この例では log = "0.4" を追加した時点のlogクレートの最新版がv0.4.17だったため、v0.4.17の情報が記録されています。

[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
 "cfg-if",
]

ロックファイルに含まれるバージョンが古くなっても、意図しないコードの変化を防ぐために、Cargo.toml のバージョン指定を満たしている限りは自動的に更新されることはありません。最新バージョンに更新するには cargo update コマンドを使用します (パッケージの更新)。

パッケージの更新

一度 Cargo.lock (ロックファイル) で固定されたパッケージバージョンは、依存関係解決で必要に迫られない限りは勝手に更新されることはありません。 パッケージを最新版に更新するには、コマンドプロンプトを起動し、Cargo.lock が含まれるディレクトリで cargo update コマンド [The Cargo Book] を実行してください。

全パッケージの更新

引数無しで cargo update を実行すると、更新可能なすべてのパッケージが更新されます。 コマンドの実行が完了すると、Cargo.lock に適用された変更点が出力されます。例:

> cargo update
    Updating crates.io index
      Adding gimli v0.28.1
    Updating libc v0.2.144 -> v0.2.154
    Updating log v0.4.17 -> v0.4.21
    Updating memchr v2.5.0 -> v2.7.2
      Adding miniz_oxide v0.7.2
...
特定パッケージの更新

cargo update-p パッケージ名 引数を渡すことで、特定パッケージのみを最新版に更新できます。 対象パッケージの依存パッケージが変化した場合、必要に応じて他のパッケージも更新・追加・削除される場合があります。例:

> cargo update -p log
    Updating crates.io index
    Removing cfg-if v1.0.0
    Updating log v0.4.17 -> v0.4.21

cargo update では Cargo.toml を変更することはなく、Cargo.toml にある既存のバージョン指定が許す範囲でのみ更新が行われます。 多くのライブラリは Semantic Versoning に準拠していることから、バージョン番号のみを指定する方法でバージョンを指定している場合、マイナーアップデート (アプリケーションコードの修正が不要な範囲内の更新) のみが行われます。

ヒント

マイナーアップデート (アプリケーションコードの修正が不要な更新) は cargo update で一括で行い、 メジャーアップデート (アプリケーションコードの修正が必要な更新) は更新対象のライブラリのリリースノートを読んだ上で Cargo.toml を手動で編集して行うのが推奨されるワークフローです。 この利点として、「Cargo.toml の指定がアプリケーションコードと互換なバージョン範囲を表している」状態を維持できる点が挙げられます。

SOLIDサポートパッケージ

crates.io で述べたようにRust標準ライブラリは後方互換性を重要視しているため、プラットフォームによる差が大きいコンセプトを対象とした抽象化APIは外部パッケージに委ねています。最もよく使用されている外部パッケージの例としてcrates.ioの12%のパッケージが直接的または間接的に依存している getrandom (エントロピー源API) があります。

こうしたパッケージをSOLIDターゲットで使用するためにはSOLIDターゲットに対応したフォーク版が必要となります。フォーク版のパッケージは solid-rs GitHub organization でGitレポジトリの形でホストされています。

注釈

これらのパッケージは出典と同等のライセンスで提供されています。随時更新しており、コントリビューションも歓迎しますが、動作保証はいたしかねます。

これらのパッケージの大部分はcrates.ioにパブリッシュされていませんが、Cargoのパッチ機能を利用することでGitレポジトリから直接パッケージを追加し、標準版のパッケージを置き換えることができます。手元のパッケージの Cargo.toml ファイルに以下の記述を追加してください。

[patch.crates-io]
chrono = { git = "https://github.com/solid-rs/chrono.git", branch = "solid-rs/0.4.x" }
hyper = { git = "https://github.com/solid-rs/hyper.git", branch = "solid-rs/0.14.x" }
mio = { git = "https://github.com/solid-rs/mio.git", branch = "solid-rs/0.8.x" }
ring = { git = "https://github.com/solid-rs/ring.git", branch = "solid-rs/0.16.x" }
socket2 = { git = "https://github.com/solid-rs/socket2.git", branch = "solid-rs/0.4.x" }
time1 = { package = "time", git = "https://github.com/solid-rs/time.git", branch = "solid-rs/0.1.x" }
tokio = { git = "https://github.com/solid-rs/tokio.git", branch = "solid-rs/1.x" }