SOLID未分類 SOLID for Raspberry Pi 4 (連載7)
(2022/12/7)
今までは、用意された環境でビルドをおこなってきたので、気にしなくても良かったのですが、Rustを知るならば避けて通れない、
パッケージマネージャ:Cargo
について、いよいよ学んでいこうと思います。
まず、パッケージ、とは何を指すのか。
Cargoにおけるパッケージとは、
「パッケージマネージャで管理できるRustコードの単位」
と理解することができます。
では、管理、とは。
おおざっぱに言うと、
「そのRustコードをビルド・リンクする際に必要なパッケージ(だいたいライブラリ)を把握し、ダウンロードし、ビルド&リンクを実行すること」
となります。
これがCargoの役目です。
具体的にどういう事をしているのか、見ていきましょう。
まずCargo使わない場合どうなるか見てみます。
以下のURLに説明が掲載されています。
https://doc.rust-jp.rs/book-ja/ch01-02-hello-world.html
手順を抜粋すると、
①ソースコード等格納のためのフォルダを作成
②main.rsを、好きなエディタで書く
③コンパイル:rustc main.rs
④実行:./main.exe
gccでコンパイルする時と、あまり変わりありませんね。
ライブラリを使わない、ごくごく小さなプログラムだと、これでいい、という事ですね。
では、開発が大規模になり、多種多様なライブラリを使いたくなった場合はどうでしょうか。
例えばgccの場合、あらかじめ必要なライブラリを準備し、ビルド手順を明示的に表すためmakefileを作ることになります。
Rustの場合はどうなるのでしょうか。
そう、Cargoを使うわけです。
以下のURLに説明が掲載されていますので、見ていきます。
https://doc.rust-jp.rs/book-ja/ch01-03-hello-cargo.html
すなわち、Cargoの役目とは、
「ビルド&リンクフェーズにおけるパッケージ情報を管理する」
ということがわかりました。
では、
・Cargoパッケージの情報を記述するCargoマニフェストファイルであるCargo.toml(※)
・プロジェクトの全依存関係を記録するCargo.lock(※)
について、見ていきましょう。
「依存関係」とは、そのソースコードで必要とする、パッケージを明記したものです。
パッケージのことを「クレート」と呼びます。
[※]
厳密に言えばCargoの用語では「クレート」はCargoパッケージのひとつの要素であってパッケージそのものではありません。
依存関係の定義においてはCargoパッケージに含まれるライブラリクレートだけに注目するので、ややカジュアルな呼び方としてCargoパッケージをクレートを呼ぶことがあります。
実際に見てみましょう。
今まで作ったプロジェクトを開き、ソリューションエクスプローラーを見てみると、Cargo.tomlとCargo.lockがありました。
まず、Cargo.tomlを見ていきましょう。
Cargo.tomlを見ると、こうなっています。
[package]
name = "rust_blinky_lib"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tock-registers = "0.7.0"
itron = { version = "= 0.1.9", features = ["unstable", "nightly", "solid_fmp3"] }
bcm2711_pac = { git = "https://github.com/KyotoMicrocomputer/solid-rapi4-examples.git" }
[lib]
crate-type = ["staticlib"]
「依存関係」が明言されているのは、[dependencies]の部分です。
したがって、Cargo buildの際に、これらのクレートをダウンロードして展開し、ビルド対象ファイルとして含める、ということになります。
さらに、「lib」のところ。
crate-type = ["staticlib"] と記述されています。
デフォルトは crate-type = ["lib"] です。
crate-type = ["staticlib"] :
C++など他の言語のプログラムで使用できるスタティックライブラリを生成するための crate-type です。
crate-type = ["lib"] :
下流クレートで再利用できるよう、Rust固有の中間コード等を含む独自形式のライブラリファイルを生成するための crate-type です。
ここでは下流クレートで再利用したいのではなく、ビルド出力をSOLIDツールチェーンのリンカに渡したいので staticlib を指定しています。
ところで、https://crates.io/というURLが良く出てきます。
これ、Rust用クレートのレジストリになっていて、膨大な量のクレートが配布されています。探せばいろいろと便利なものがありそうですね。
(なんとなくですが、C#のNuGetと同じような感じがします。。。)
Cargo.lockを見ると、こういう風な記述がたくさん書かれています。
[[package]]
name = "itron"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab72a2ac7834689b3478b66077c32269d712c650ce138c2fd093a340e3fcc68b"
dependencies = [
"tt-call",
]
[[package]]
name = "rust_blinky_lib"
version = "0.1.0"
dependencies = [
"bcm2711_pac",
"itron",
"tock-registers",
]
[[package]]
name = "tt-call"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e66dcbec4290c69dd03c57e76c2469ea5c7ce109c6dd4351c13055cf71ea055"
※これで全部ではありません。一部抜粋です。
このファイルは、ビルドが最初に成功した時の依存パッケージとそのバージョンがすべてが記載されています。
Cargoにより生成されるファイルであり、私たちユーザが編集するものではありません。
ここでCargo.tomlを思い出してみましょう。
Cargo.tomlは、依存関係をユーザが明記していました。
使いたいパッケージを書き、ビルド時にそれを含めて欲しい、という意図でした。
あれ?なら、Cargo.tomlが依存関係知ってるってこと?
それじゃ、Cargo.lockの存在は?
??
なんだか疑問だらけになってしまい、筆者も混乱してしまって、理解するのに時間を要してしまいました。
ヒントは、依存しているパッケージの先のお話。
Cargo.tomlには、「ユーザが自分の作成するプログラムが」必要とする依存パッケージを明記します。
さらに、その、必要とされたパッケージにも依存関係があり、Cargo.tomlを持っているはず。
さらに、その必要とされたパッケージが必要とするパッケージにも依存関係が。。。(以下省略)
深い!
そこでCargo.lockの登場です。
Cargo.lockは
「ビルドが最初に成功した時の依存パッケージすべてが記載されている」
先程のCargo.lockを見てみると、
・rust_blinky_libパッケージ(自分)の依存関係は"bcm2711_pac","itron","tock-registers"。
・そのitronパッケージのバージョンは0.1.9で依存関係は"tt-call"。
・そのtt-callパッケージのバージョンは1.0.8で依存関係なし。
等々。。。がすべて記載されています。
Cargo.tomlをたどらなくていいんですね、
必要としたパッケージが必要としたパッケージの依存関係、もCargo.lockは知っている。
そのまた先も。
しかも、依存関係とした時のバージョンも記載されています。
例えば先程のCargo.lockでは、itronパッケージが使用しているtt-callのバージョンが1.0.8、とわかります。
バージョンが違う場合、だいたいにおいて下位互換であり、気にしなくていいのかもしれないのですが、まれに(自分の欲している)互換性が途切れたりしますよね。
Cargo.lockは、そういう事がないよう、バージョン固定してくれる、便利なシステムだったんですね。
ところで。一体、これらのライセンスってどうなっているのでしょう?
Rust API Guidelinesによれば、できるだけMIT or Apache 2.0か、そうでなければ寛大なライセンスにするべき、と記載されています。
Rust API Guidelines:
https://rust-lang.github.io/api-guidelines/necessities.html#crate-and-its-dependencies-have-a-permissive-license-c-permissive
製品に適用するような場合は、各クレートのライセンス条項を確認するようにしないといけないような気がします。。。
今回は以上です。
次回は「クレートを作ってみよう」の予定です。