Rust では、リリースプロフィール(release profiles) は異なるオプションを持つ事前定義かつカスタマイズ可能な設定であり、プログラマがコードのコンパイルオプションを柔軟に制御できるようにします。各設定は互いに独立しています。
Cargo には主に2つの設定があります。cargo build を実行したときの dev 設定と、cargo build --release を実行したときの release 設定です。dev 設定は開発時の良いデフォルト設定であり、release 設定はリリースビルドに適した良いデフォルト設定です。
これらの名前はビルドの出力でも見かけるかもしれません:
$ cargo build
Compiling cargo1 v0.1.0 (/rust/cargo1)
Finished dev [unoptimized + debuginfo] target(s) in 0.67s
$ cargo build --release
Compiling cargo1 v0.1.0 (/rust/cargo1)
Finished release [optimized] target(s) in 0.11s
ビルド出力の dev と release はコンパイラが異なる設定を使っていることを示しています。
プロジェクトの Cargo.toml に [profile.] セクションを明示的に追加していない場合、Cargo はすべての設定でデフォルト設定を使います。任意の設定のサブセットを上書きしたい場合は、対応する [profile.] セクションを追加すればよいです。例えば dev と release の opt-level のデフォルト値は以下の通りです:
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
opt-level は Rust がコードに施す最適化の強度を制御します。この値は 0 から 3 まであります。高い最適化レベルはコンパイルにより時間がかかるため、頻繁にコンパイルしたい開発中は多少パフォーマンスを犠牲にしてコンパイルを速くしたいことが多いです。そのため dev の opt-level はデフォルトで 0 になっています。リリース時はコンパイルにより時間をかける方が良いです。リリースビルドは一回だけコンパイルして、その後は何度も実行されるため、コンパイル時間を長くしても実行時の性能が上がる利点があります。これが release 設定の opt-level がデフォルトで 3 である理由です。
Cargo.toml に異なる値を指定することで任意にデフォルトを上書きできます。例えば、開発用で opt-level を 1 にしたい場合は Cargo.toml に以下のように追加します:
[profile.dev]
opt-level = 1
これによりデフォルトの 0 が上書きされ、cargo build を実行すると dev 設定のデフォルトに加えて opt-level が 1 になります。これにより Cargo はデフォルトよりも多く最適化を行いますが、リリースビルドほどではありません。
ドキュメントコメント
ドキュメントコメントでは /// 三つのスラッシュを使い、二つのスラッシュと異なり Markdown 記法がサポートされます。コメントはドキュメント化したい項目の直前に置きます。新しいプロジェクトを作成してみましょう:
$ cargo new learn_cratel
$ cd learn_cratel
$ cargo new mylib --lib
mylib の lib.rs を開いて、デフォルトの add 関数にドキュメントコメントを追加します:
/// 2つの usize を加算する
pub fn add(left: usize, right: usize) -> usize {
left + right
}
cargo doc を実行すると、このドキュメントコメントから HTML ドキュメントが生成されます。このコマンドは Rust 配布のツール rustdoc を呼び出し、生成された HTML ドキュメントは target/doc ディレクトリに入ります。
cargo doc --open を実行すると、現在のクレート(と依存クレートのドキュメント)をビルドしてブラウザで開きます。add 関数をたどると、ドキュメントコメントがどのようにレンダリングされるか確認できます。
さらにドキュメントコメントを充実させることもできます:
/// 2つの数値を加算します
/// # Example
/// ```
/// let left = 1;
/// let right = 2;
/// assert_eq!(3, mylib::add(left, right));
/// ```
pub fn add(left: usize, right: usize) -> usize {
left + right
}
ここでは add 関数の説明と Example セクション、add の使い方を示すコード例を示しています。
ドキュメントコメントをテストとして使う
ドキュメントコメント中のサンプルコードはライブラリの使い方の説明になりますが、もうひとつの利点は cargo test がドキュメント内の例コードもテストとして実行することです。例のあるドキュメントは素晴らしいですが、コード変更後に例が壊れるのが最悪です。cargo test で add のドキュメントテストを実行すると、以下のように表示されます:
Doc-tests mylib
running 1 test
test src/lib.rs - add (line 3) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.18s
関数や例を変えて assert_eq! が失敗するようにすれば、cargo test はドキュメントテストの失敗を報告します。
含み注釈について
//! スタイルは項目そのものに対するドキュメント追加で、その項目の直後ではありません。通常これはクレートルート(通常 src/lib.rs)やモジュールルートファイルで使い、クレートやモジュール全体のドキュメントを提供します。
//! # My Crate
//!
//! `learn_cratel` はユーティリティ集です
/// 2つの数値を加算
/// # Example
/// ```
/// let left = 1;
/// let right = 2;
/// assert_eq!(3, mylib::add(left, right));
/// ```
pub fn add(left: usize, right: usize) -> usize {
left + right
}
//! の末尾にコードは続きません。//! は含む項目に属するドキュメントです。この例では src/lib.rs がクレートルートなので、ドキュメントはクレート単位の説明になります。
cargo doc --open を実行すると、これらのコメントは learn_cratel ドキュメントのトップページに表示され、パブリック項目リストの上に位置します。項目内のドキュメントコメントはクレートやモジュールの説明に役立ち、ユーザがコードの構造を理解するのに助けになります。
Crates.io にクレートを公開する
crates.io の依存クレートは使いましたが、自分のクレートを公開してコードを他人と共有することもできます。crates.io はオープンソースのコードの配布元となります。
Crates.io アカウントの作成
公開前に crates.io でアカウント登録をして API token を入手する必要があります。ホームページで GitHub アカウントでログインします。(今は GitHub アカウントのみですが将来は他も対応予定です)ログイン後、https://crates.io/me/ でアカウント設定画面から API token を取得します。その後、取得した token を使って cargo login を実行:
$ cargo login あなたのAPIトークン
このコマンドで Cargo は token を認識し、~/.cargo/credentials に保存します。この token は秘密情報なので他者と共有しないでください。
Crates.io への公開
アカウント作成と token 保存の後、crate の特定バージョンをアップロードして他のユーザが依存として使えるようにします。
公開は永久的で、一度公開したバージョンは上書きや削除ができません。crates.io はコードの永続的ドキュメントサーバーになることが狙いで、依存先のプロジェクトがずっと正常に動くようにしたいからです。公開するバージョン番号は制限がありません。
cargo publish を実行すると例えば以下のエラーが出ることがあります:
Caused by:
the remote server responded with an error: missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for how to upload metadata
これは description と license の情報が不足しているためです。Cargo.toml に追加します:
description = "This is a test project"
license = "MIT OR Apache-2.0"
再度 cargo publish を実行すれば成功するはずです。
$ cargo publish
Updating crates.io index
warning: manifest has no documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
Packaging mylib-hekang v0.1.0 (/rust/learn_cratel/mylib)
Verifying mylib-hekang v0.1.0 (/rust/learn_cratel/mylib)
Compiling mylib-hekang v0.1.0 (/rust/learn_cratel/mylib/target/package/mylib-hekang-0.1.0)
Finished dev [unoptimized + debuginfo] target(s) in 0.84s
Packaged 3 files, 1.3KiB (901.0B compressed)
Uploading mylib-hekang v0.1.0 (/rust/learn_cratel/mylib)
Updating crates.io index
Waiting on `mylib-hekang` to propagate to crates.io index (ctrl-c to wait asynchronously)
Updating crates.io index
Updating crates.io index
Updating crates.io index
Updating crates.io index
Updating crates.io index
これでコードを Rust コミュニティと共有でき、誰でも簡単に依存に追加可能です。
既存クレートの新バージョン公開
crate を修正して新バージョンを公開する場合は、Cargo.toml の version を変更し、セマンティックバージョニング に従いバージョン番号を決めます。その後 cargo publish でアップロードします。
cargo yank で Crates.io のバージョンを非推奨にする
過去のバージョンは削除できませんが、新しいプロジェクトが依存に使えないように「撤回(yank)」できます。これにより壊れたバージョンの影響を抑えられます。
撤回したバージョンは既存の依存プロジェクトは使い続けられますが、新規依存の Cargo.lock は使えなくなります。
撤回は以下のように実行します(例:バージョン 0.1.0 を撤回):
$ cargo yank --vers 0.1.0
Updating crates.io index
Yank mylib-hekang@0.1.0
撤回を解除し再度依存可能にする場合は --undo を付けます:
$ cargo yank --vers 0.1.0 --undo
Updating crates.io index
Unyank mylib-hekang@0.1.0
撤回はコード削除ではありません。誤ってアップロードした秘密情報などは再発行してください。