Rustdoc の概要
rustdoc は、コンパイラおよび標準ライブラリと同じツリー内にあります。
この章では、その仕組みについて説明します。
Rustdoc の機能とその使い方については、
Rustdoc book を参照してください。
rustdoc の仕組みの詳細については、“Rustdoc internals” の章を参照してください。
rustdoc は rustc の内部機構(そして、もちろん標準ライブラリ)を使用するため、
rustdoc をビルドする前に、コンパイラと std を一度ビルドする必要があります。
Rustdoc は、クレート librustdoc 内に完全に実装されています。
これは、クレートの内部表現(HIR)が得られ、アイテムの型に関するいくつかのクエリを実行できるようになる地点までコンパイラを実行します。
HIR と queries については、リンク先の章で説明されています。
その後、librustdoc は一連のドキュメントをレンダリングするために、主に 2 つのステップを実行します。
- AST を、ドキュメントの作成により適した形式へ「クリーン」します(また、 コンパイラ内の変更の影響をやや受けにくくします)。
- このクリーンされた AST を使用して、クレートのドキュメントを 1 ページずつレンダリングします。
当然ながら、実際にはこれ以外にも多くの処理があり、これらの説明では 多くの詳細を簡略化していますが、これが大まかな概要です。
(補足: librustdoc はライブラリクレートです!
rustdoc バイナリは src/tools/rustdoc のプロジェクトを使用して作成されます。
ただし、文字どおりそれが行っていることは、このクレートの lib.rs にある main() を呼び出すことだけです。)
チートシート
- 開始する前に
./x setup toolsを実行します。 これにより、rustdoc やその他のツールの開発に適した設定でxが構成されます。これには、 rustc をビルドする代わりにコピーをダウンロードすることも含まれます。 - コンパイルエラーをすばやく確認するには、
./x check rustdocを使用します。 - 他のプロジェクトで実行できる利用可能な rustdoc を作成するには、
./x build library rustdocを使用します。rustdoc --testを使用できるようにするには、library/testを追加します。stage2という名前のカスタムツールチェーンを rustup 環境に追加するには、rustup toolchain link stage2 build/host/stage2を実行します。 それを実行した後は、任意のディレクトリでcargo +stage2 docを実行すると、 ローカルでコンパイルした rustdoc を使用してビルドされます。
- この rustdoc を使用して標準ライブラリのドキュメントを生成するには、
./x doc libraryを使用します。- 完成したドキュメントは
build/host/doc(core、alloc、stdの下)で利用できます。 - それらのドキュメントを Web サーバーにコピーしたい場合は、
build/host/doc全体をコピーしてください。CSS、JS、フォント、ランディングページはそこにあるためです。 - フロントエンドのデバッグでは、
bootstrap.tomlのrust.docs-minificationオプションを無効にします。
- 完成したドキュメントは
- stage1 rustdoc を使用してテストを実行するには、
./x test tests/rustdoc*を使用します。- テストの詳細については、Rustdoc internals を参照してください。
- rustdoc の JavaScript チェック(
eslint、es-check、tsc)を実行するには、./x test tidy --extra-checks=jsを使用します。
注:
./x test tidyは、JS/TS ソースが変更された場合、これらのチェックをすでに自動的に実行します。--extra-checks=jsはそれらを明示的に強制します。
JavaScript CI チェック
Rustdoc の JavaScript と TypeScript は、CI 中に eslint、es-check、tsc によってチェックされます(compiletest によってではありません)。
これらは tidy ジョブの一部として実行されます。
./x test tidy --extra-checks=js
--extra-checks=js フラグは、CI で実行されるフロントエンドの lint を有効にします。
コード構造
このセクション内のすべてのパスは、rust-lang/rust リポジトリ内の src/librustdoc/ からの相対パスです。
- HTML 出力コードのほとんどは、
html/format.rsとhtml/render/mod.rsにあります。 それらは、impl std::fmt::Displayを返す多数の関数内にあります。 - 上記の関数によってレンダリングされるデータ型は、
clean/types.rsで定義されています。HIRとrustc_middle::tyIR からそれらを作成する役割を持つ関数は、clean/mod.rsにあります。 - rustdoc をテストハーネスとして使用することに特有の部分は、
doctest.rsにあります。 - Markdown レンダラーは
html/markdown.rsで読み込まれます。これには、 指定された Markdown ブロックから doctest を抽出する関数も含まれます。 - フロントエンドの CSS と JavaScript は
html/static/に保存されています。- JavaScript について。
型注釈は TypeScript-flavored JSDoc
コメントと外部の
.d.tsファイルを使用して記述されます。 この方法により、コード自体はプレーンで有効な JavaScript のままになります。tscは linter としてのみ使用します。
- JavaScript について。
型注釈は TypeScript-flavored JSDoc
コメントと外部の
テスト
rustdoc の統合テストは、複数のテストスイートに分割されています。
詳細については、Rustdoc テストスイートを参照してください。
制約
私たちは、JavaScript が無効な場合やローカルファイルを閲覧している場合でも、rustdoc がある程度適切に動作するように努めています。 [サポート対象ブラウザーの一覧][a list of supported browsers]があります。
ローカルファイル(file:/// URL)のサポートには、いくつかの意外な制約が伴います。
localStorage や Service Workers のように、安全なオリジンを必要とする特定のブラウザー機能は、
信頼性高く動作しません。
そのような機能は引き続き使用できますが、それらがなくてもページが引き続き利用可能であることを確認する必要があります。
Rustdoc は[関数本体の型チェックを行いません][platform-specific docs]。
これは、[typeck の組み込みクエリをオーバーライドすること][override queries]、
[名前解決エラーを抑制すること][silencing name resolution errors]、および[不透明型を解決しないこと][not resolving opaque types]によって機能します。
これにはいくつかの注意点があります。特に、rustdoc は
本体の型チェックを必要とするコンパイラのどの部分も実行できません。
たとえば、.rlib ファイルを生成したり、ほとんどの lint を実行したりすることはできません。
最終的にはこのモデルから移行したいと考えていますが、
[これを使用している人々][async-std]のために、何らかの代替手段が必要です。
[さまざまな][zulip stop accepting broken code]
[以前の][rustdoc meeting 2024-07-08] [Zulip][compiler meeting 2023-01-26] [議論][notriddle rfc]を参照してください。
このハックが削除された場合に壊れるコードの例については、
[tests/rustdoc-ui/error-in-impl-trait] を参照してください。
[platform-specific docs]: https://doc.rust-lang.org/rustdoc/advanced-features.html#interactions-between-platform-specific-docs
[override queries]: https://github.com/rust-lang/rust/blob/52bf0cf795dfecc8b929ebb1c1e2545c3f41d4c9/src/librustdoc/core.rs#L299-L323
[silencing name resolution errors]: https://github.com/rust-lang/rust/blob/52bf0cf795dfecc8b929ebb1c1e2545c3f41d4c9/compiler/rustc_resolve/src/late.rs#L4517
[not resolving opaque types]: https://github.com/rust-lang/rust/blob/52bf0cf795dfecc8b929ebb1c1e2545c3f41d4c9/compiler/rustc_hir_analysis/src/check/check.rs#L188-L194
[async-std]: https://github.com/rust-lang/rust/issues/75100
[rustdoc meeting 2024-07-08]: https://rust-lang.zulipchat.com/#narrow/channel/393423-t-rustdoc.2Fmeetings/topic/meeting.202024-07-08/near/449969836
[compiler meeting 2023-01-26]: https://rust-lang.zulipchat.com/#narrow/channel/238009-t-compiler.2Fmeetings/topic/.5Bweekly.5D.202023-01-26/near/323755789
[zulip stop accepting broken code]: https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/stop.20accepting.20broken.20code
[notriddle rfc]: https://rust-lang.zulipchat.com/#narrow/channel/266220-t-rustdoc/topic/Pre-RFC.3A.20stop.20accepting.20broken.20code
[tests/rustdoc-ui/error-in-impl-trait]: https://github.com/rust-lang/rust/tree/163cb4ea3f0ae3bc7921cc259a08a7bf92e73ee6/tests/rustdoc-ui/error-in-impl-trait
[a list of supported browsers]: https://rust-lang.github.io/rfcs/1985-tiered-browser-support.html#supported-browsers
複数回の実行、同じ出力ディレクトリ
Rustdoc は、さまざまな入力に対して複数回実行し、その出力先を同じディレクトリに設定できます。 これは、cargo が現在のクレートの依存関係のドキュメントを生成する方法です。 ユーザーが、自分にとって必要なすべてのドキュメントを含む大きな ドキュメントバンドルを望む場合は、手動で行うこともできます。
HTML は各クレートについて個別に生成されますが、出力ディレクトリにクレートを追加するにつれて 更新する、クレート間にまたがる情報がいくつかあります。
crates<SUFFIX>.jsは、出力ディレクトリ内のすべてのクレートのリストを保持します。search-index<SUFFIX>.jsは、検索可能なすべての項目のリストを保持します。- 各トレイトについて、
implementors/.../trait.TraitName.jsの下にファイルがあり、 そのトレイトの実装者のリストが含まれます。 実装者はそのトレイトとは異なる クレートに存在する場合があり、新しい実装者を見つけるたびに JS ファイルが更新されます。
ユースケース
rustdoc に取り組む際に念頭に置いておくべき、主要なユースケースがいくつかあります。
標準ライブラリドキュメント
これらは Rust のリリースプロセスの一環として https://doc.rust-lang.org/std で公開されます。 Stable リリースは、https://doc.rust-lang.org/1.57.0/std/ のような 特定のバージョン付き URL にもアップロードされます。 Beta と nightly のドキュメントは、 https://doc.rust-lang.org/beta/std/ と https://doc.rust-lang.org/nightly/std/ で公開されます。 ドキュメントは promote-release tool でアップロードされ、S3 から CloudFront で配信されます。
標準ライブラリドキュメントには、alloc、core、proc_macro、std、test の 5 つのクレートが含まれます。
docs.rs
クレートが crates.io に公開されると、docs.rs は自動的にそのドキュメントをビルドして 公開します。たとえば https://docs.rs/serde/latest/serde/ です。 これは常に現在の nightly rustdoc でビルドされるため、rustdoc に取り込まれた変更は、docs.rs に即座に公開される影響を 与えるという意味で「insta-stable」です。 古いドキュメントは再ビルドされる場合もありますが、常にそうとは限らないため、 docs.rs で古いリリースを閲覧していると UI に多少の違いが見られます。 クレート作者は再ビルドをリクエストでき、その場合は最新の rustdoc で実行されます。
docs.rs は、ストレージを節約し、上部にナビゲーションバーを表示するために、
rustdoc の出力にいくつかの変換を行います。
特に、main.js や rustdoc.css のような特定の静的
ファイルは、同じバージョンの rustdoc の複数の呼び出し間で共有される場合があります。
crates.js や sidebar-items.js のような他のファイルは、呼び出しごとに異なります。
フォントのようなさらに別のものは、決して変更されません。
これらのカテゴリは
src/librustdoc/html/render/write_shared.rs の SharedResource enum を使用して区別されます
docs.rs 上のドキュメントは常に一度に 1 つのクレートについて生成されるため、 検索機能とサイドバー機能には現在のクレートの依存関係は含まれません。
ローカルで生成されたドキュメント
クレート作者は、ローカルにチェックアウトしたクレートで cargo doc --open を実行してドキュメントを確認できます。
これは、書いているドキュメントが有用で正しく表示されることを確認するのに役立ちます。
また、自分が作者ではないものの利用したいクレートのドキュメントを閲覧する人にとっても有用です。
どちらの場合でも、通常は表示されないプライベートメソッドやフィールドなどを
確認するために、Cargo フラグ --document-private-items を使用できます。
デフォルトでは、cargo doc はクレートとそのすべての依存関係のドキュメントを生成します。
その結果、非常に大きなドキュメントバンドルになり、大きな(そして遅い)検索コーパスになることがあります。
Cargo フラグ --no-deps はこの挙動を抑制し、そのクレートだけのドキュメントを生成します。
セルフホストされたプロジェクトドキュメント
一部のプロジェクトは独自のドキュメントをホストしています。
これは、ローカルでドキュメントを生成し、それを単純に Web サーバーへコピーすることで簡単に行えます。
Rustdoc の HTML 出力は、フラグによって広範にカスタマイズできます。
ユーザーはテーマを追加し、デフォルトテーマを設定し、任意の HTML を注入できます。
詳細は rustdoc --help を参照してください。