rustc-dev-guide/rustdoc-internals.html

464 lines
30 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML>
<html lang="en" class="light sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Rustdoc internals - Rust Compiler Development Guide</title>
<!-- Custom HTML head -->
<meta name="description" content="A guide to developing the Rust compiler (rustc)">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="favicon.svg">
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "";
const default_light_theme = "light";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="toc.js"></script>
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('light')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Rust Compiler Development Guide</h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/rust-lang/rustc-dev-guide/edit/master/src/rustdoc-internals.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="rustdoc-internals"><a class="header" href="#rustdoc-internals">Rustdoc Internals</a></h1>
<ul>
<li><a href="#from-crate-to-clean">From Crate to Clean</a>
<ul>
<li><a href="#passes-anything-but-a-gas-station-or-hot-potato">Passes Anything But a Gas Station (or: Hot Potato)</a></li>
</ul>
</li>
<li><a href="#from-clean-to-html">From Clean To HTML</a>
<ul>
<li><a href="#from-soup-to-nuts-or-an-unbroken-thread-stretches-from-those-first-cells-to-us">From Soup to Nuts (or: "An Unbroken Thread Stretches From Those First <code>Cell</code>s To Us")</a></li>
</ul>
</li>
<li><a href="#other-tricks-up-its-sleeve">Other Tricks Up Its Sleeve</a></li>
<li><a href="#testing-locally">Testing Locally</a></li>
<li><a href="#see-also">See Also</a></li>
</ul>
<p>This page describes <a href="https://github.com/rust-lang/rust/tree/master/src/tools/rustdoc"><code>rustdoc</code></a>'s passes and modes. For an overview of <code>rustdoc</code>,
see the <a href="./rustdoc.html">"Rustdoc overview" chapter</a>.</p>
<h2 id="from-crate-to-clean"><a class="header" href="#from-crate-to-clean">From Crate to Clean</a></h2>
<p>In <a href="https://github.com/rust-lang/rust/blob/master/src/librustdoc/core.rs"><code>core.rs</code></a> are two central items: the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/struct.DocContext.html"><code>rustdoc::core::DocContext</code></a>
<code>struct</code>, and the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/fn.run_global_ctxt.html"><code>rustdoc::core::run_global_ctxt</code></a> function. The latter is
where <code>rustdoc</code> calls out to <code>rustc</code> to compile a crate to the point where
<code>rustdoc</code> can take over. The former is a state container used when crawling
through a crate to gather its documentation.</p>
<p>The main process of crate crawling is done in <a href="https://github.com/rust-lang/rust/blob/master/src/librustdoc/clean/mod.rs"><code>clean/mod.rs</code></a> through several
functions with names that start with <code>clean_</code>. Each function accepts an <code>hir</code>
or <code>ty</code> data structure, and outputs a <code>clean</code> structure used by <code>rustdoc</code>. For
example, <a href="https://doc.rust-lang.org/nightly/nightly-rustc/src/rustdoc/clean/mod.rs.html#256-267">this function for converting lifetimes</a>:</p>
<pre><code class="language-rust ignore">fn clean_lifetime&lt;'tcx&gt;(lifetime: &amp;hir::Lifetime, cx: &amp;mut DocContext&lt;'tcx&gt;) -&gt; Lifetime {
if let Some(
rbv::ResolvedArg::EarlyBound(did)
| rbv::ResolvedArg::LateBound(_, _, did)
| rbv::ResolvedArg::Free(_, did),
) = cx.tcx.named_bound_var(lifetime.hir_id)
&amp;&amp; let Some(lt) = cx.args.get(&amp;did).and_then(|arg| arg.as_lt())
{
return lt.clone();
}
Lifetime(lifetime.ident.name)
}</code></pre>
<p>Also, <code>clean/mod.rs</code> defines the types for the "cleaned" <a href="./ast-validation.html">Abstract Syntax Tree
(<code>AST</code>)</a> used later to render documentation pages. Each usually accompanies a
<code>clean_*</code> function that takes some <a href="./ast-validation.html"><code>AST</code></a> or <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/index.html">High-Level Intermediate
Representation (<code>HIR</code>)</a> type from <code>rustc</code> and converts it into the
appropriate "cleaned" type. "Big" items like modules or associated items may
have some extra processing in its <code>clean</code> function, but for the most part these
<code>impl</code>s are straightforward conversions. The "entry point" to this module is
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/clean/utils/fn.krate.html#"><code>clean::utils::krate</code></a>, which is called by <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/core/fn.run_global_ctxt.html"><code>run_global_ctxt</code></a>.</p>
<p>The first step in <a href="https://doc.rust-lang.org/nightly/nightly-rustc/src/rustdoc/clean/utils.rs.html#31-77"><code>clean::utils::krate</code></a> is to invoke
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/visit_ast/struct.RustdocVisitor.html"><code>visit_ast::RustdocVisitor</code></a> to process the module tree into an intermediate
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/visit_ast/struct.Module.html"><code>visit_ast::Module</code></a>. This is the step that actually crawls the
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Crate.html"><code>rustc_hir::Crate</code></a>, normalizing various aspects of name resolution, such as:</p>
<ul>
<li>handling <code>#[doc(inline)]</code> and <code>#[doc(no_inline)]</code></li>
<li>handling import globs and cycles, so there are no duplicates or infinite
directory trees</li>
<li>inlining public <code>use</code> exports of private items, or showing a "Reexport"
line in the module page</li>
<li>inlining items with <code>#[doc(hidden)]</code> if the base item is hidden but the</li>
<li>showing <code>#[macro_export]</code>-ed macros at the crate root, regardless of whether
they're defined as a reexport or not</li>
</ul>
<p>After this step, <code>clean::krate</code> invokes <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/clean/fn.clean_doc_module.html"><code>clean_doc_module</code></a>, which actually
converts the <code>HIR</code> items to the cleaned <a href="./ast-validation.html"><code>AST</code></a>. This is also the step where cross-
crate inlining is performed, which requires converting <code>rustc_middle</code> data
structures into the cleaned <a href="./ast-validation.html"><code>AST</code></a>.</p>
<p>The other major thing that happens in <code>clean/mod.rs</code> is the collection of doc
comments and <code>#[doc=""]</code> attributes into a separate field of the <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/clean/types/struct.Attributes.html"><code>Attributes</code></a>
<code>struct</code>, present on anything that gets hand-written documentation. This makes it
easier to collect this documentation later in the process.</p>
<p>The primary output of this process is a <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/clean/types/struct.Crate.html"><code>clean::types::Crate</code></a> with a tree of <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/clean/types/struct.Item.html"><code>Item</code></a>s
which describe the publicly-documentable items in the target crate.</p>
<h3 id="passes-anything-but-a-gas-station-or-hot-potato"><a class="header" href="#passes-anything-but-a-gas-station-or-hot-potato">Passes Anything But a Gas Station (or: <a href="https://www.youtube.com/watch?v=WNFBIt5HxdY">Hot Potato</a>)</a></h3>
<p>Before moving on to the next major step, a few important "passes" occur over
the cleaned <a href="./ast-validation.html"><code>AST</code></a>. Several of these passes are <code>lint</code>s and reports, but some of
them mutate or generate new items.</p>
<p>These are all implemented in the <a href="https://github.com/rust-lang/rust/tree/master/src/librustdoc/passes"><code>librustdoc/passes</code></a> directory, one file per pass.
By default, all of these passes are run on a crate, but the ones
regarding dropping private/hidden items can be bypassed by passing
<code>--document-private-items</code> to <code>rustdoc</code>. Note that unlike the previous set of <a href="./ast-validation.html"><code>AST</code></a>
transformations, the passes are run on the <em>cleaned</em> crate.</p>
<p>Here is the list of passes as of <!-- date-check --> March 2023:</p>
<ul>
<li>
<p><code>calculate-doc-coverage</code> calculates information used for the <code>--show-coverage</code>
flag.</p>
</li>
<li>
<p><code>check-doc-test-visibility</code> runs <code>doctest</code> visibilityrelated <code>lint</code>s. This pass
runs before <code>strip-private</code>, which is why it needs to be separate from
<code>run-lints</code>.</p>
</li>
<li>
<p><code>collect-intra-doc-links</code> resolves <a href="https://doc.rust-lang.org/nightly/rustdoc/write-documentation/linking-to-items-by-name.html">intra-doc links</a>.</p>
</li>
<li>
<p><code>collect-trait-impls</code> collects <code>trait</code> <code>impl</code>s for each item in the crate. For
example, if we define a <code>struct</code> that implements a <code>trait</code>, this pass will note
that the <code>struct</code> implements that <code>trait</code>.</p>
</li>
<li>
<p><code>propagate-doc-cfg</code> propagates <code>#[doc(cfg(...))]</code> to child items.</p>
</li>
<li>
<p><code>run-lints</code> runs some of <code>rustdoc</code>'s <code>lint</code>s, defined in <code>passes/lint</code>. This is
the last pass to run.</p>
<ul>
<li>
<p><code>bare_urls</code> detects links that are not linkified, e.g., in Markdown such as
<code>Go to https://example.com/.</code> It suggests wrapping the link with angle brackets:
<code>Go to &lt;https://example.com/&gt;.</code> to linkify it. This is the code behind the <!--
date-check: may 2022 --> <code>rustdoc::bare_urls</code> <code>lint</code>.</p>
</li>
<li>
<p><code>check_code_block_syntax</code> validates syntax inside Rust code blocks
(<code>```rust</code>)</p>
</li>
<li>
<p><code>html_tags</code> detects invalid <code>HTML</code> (like an unclosed <code>&lt;span&gt;</code>)
in doc comments.</p>
</li>
</ul>
</li>
<li>
<p><code>strip-hidden</code> and <code>strip-private</code> strip all <code>doc(hidden)</code> and private items
from the output. <code>strip-private</code> implies <code>strip-priv-imports</code>. Basically, the
goal is to remove items that are not relevant for public documentation. This
pass is skipped when <code>--document-hidden-items</code> is passed.</p>
</li>
<li>
<p><code>strip-priv-imports</code> strips all private import statements (<code>use</code>, <code>extern crate</code>) from a crate. This is necessary because <code>rustdoc</code> will handle <em>public</em>
imports by either inlining the item's documentation to the module or creating
a "Reexports" section with the import in it. The pass ensures that all of
these imports are actually relevant to documentation. It is technically
only run when <code>--document-private-items</code> is passed, but <code>strip-private</code>
accomplishes the same thing.</p>
</li>
<li>
<p><code>strip-private</code> strips all private items from a crate which cannot be seen
externally. This pass is skipped when <code>--document-private-items</code> is passed.</p>
</li>
</ul>
<p>There is also a <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/passes/stripper/index.html"><code>stripper</code></a> module in <code>librustdoc/passes</code>, but it is a
collection of utility functions for the <code>strip-*</code> passes and is not a pass
itself.</p>
<h2 id="from-clean-to-html"><a class="header" href="#from-clean-to-html">From Clean To HTML</a></h2>
<p>This is where the "second phase" in <code>rustdoc</code> begins. This phase primarily lives
in the <a href="https://github.com/rust-lang/rust/tree/master/src/librustdoc/formats"><code>librustdoc/formats</code></a> and <a href="https://github.com/rust-lang/rust/tree/master/src/librustdoc/html"><code>librustdoc/html</code></a> folders, and it all starts with
<a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/formats/renderer/fn.run_format.html"><code>formats::renderer::run_format</code></a>. This code is responsible for setting up a type that
<code>impl FormatRenderer</code>, which for <code>HTML</code> is <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/html/render/context/struct.Context.html"><code>Context</code></a>.</p>
<p>This structure contains methods that get called by <code>run_format</code> to drive the
doc rendering, which includes:</p>
<ul>
<li><code>init</code> generates <code>static.files</code>, as well as search index and <code>src/</code></li>
<li><code>item</code> generates the item <code>HTML</code> files themselves</li>
<li><code>after_krate</code> generates other global resources like <code>all.html</code></li>
</ul>
<p>In <code>item</code>, the "page rendering" occurs, via a mixture of <a href="https://docs.rs/askama/latest/askama/">Askama</a> templates
and manual <code>write!()</code> calls, starting in <a href="https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/layout.rs"><code>html/layout.rs</code></a>. The parts that have
not been converted to templates occur within a series of <code>std::fmt::Display</code>
implementations and functions that pass around a <code>&amp;mut std::fmt::Formatter</code>.</p>
<p>The parts that actually generate <code>HTML</code> from the items and documentation start
with <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/html/render/print_item/fn.print_item.html"><code>print_item</code></a> defined in <a href="https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/print_item.rs"><code>html/render/print_item.rs</code></a>, which switches out
to one of several <code>item_*</code> functions based on kind of <code>Item</code> being rendered.</p>
<p>Depending on what kind of rendering code you're looking for, you'll probably
find it either in <a href="https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/mod.rs"><code>html/render/mod.rs</code></a> for major items like "what sections
should I print for a <code>struct</code> page" or <a href="https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/format.rs"><code>html/format.rs</code></a> for smaller component
pieces like "how should I print a where clause as part of some other item".</p>
<p>Whenever <code>rustdoc</code> comes across an item that should print hand-written
documentation alongside, it calls out to <a href="https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/markdown.rs"><code>html/markdown.rs</code></a> which interfaces
with the Markdown parser. This is exposed as a series of types that wrap a
string of Markdown, and implement <code>fmt::Display</code> to emit <code>HTML</code> text. It takes
special care to enable certain features like footnotes and tables and add
syntax highlighting to Rust code blocks (via <code>html/highlight.rs</code>) before
running the Markdown parser. There's also a function <a href="https://doc.rust-lang.org/nightly/nightly-rustc/src/rustdoc/html/markdown.rs.html#749-818"><code>find_codes</code></a> which is
called by <code>find_testable_codes</code> that specifically scans for Rust code blocks so
the test-runner code can find all the <code>doctest</code>s in the crate.</p>
<h3 id="from-soup-to-nuts-or-an-unbroken-thread-stretches-from-those-first-cells-to-us"><a class="header" href="#from-soup-to-nuts-or-an-unbroken-thread-stretches-from-those-first-cells-to-us">From Soup to Nuts (or: <a href="https://www.youtube.com/watch?v=hOLAGYmUQV0">"An Unbroken Thread Stretches From Those First <code>Cell</code>s To Us"</a>)</a></h3>
<p>It's important to note that <code>rustdoc</code> can ask the compiler for type information
directly, even during <code>HTML</code> generation. This <a href="https://github.com/rust-lang/rust/pull/80090">didn't used to be the case</a>, and
a lot of <code>rustdoc</code>'s architecture was designed around not doing that, but a
<code>TyCtxt</code> is now passed to <code>formats::renderer::run_format</code>, which is used to
run generation for both <code>HTML</code> and the
(unstable as of <!-- date-check --> March 2023) JSON format.</p>
<p>This change has allowed other changes to remove data from the "clean" <a href="./ast-validation.html"><code>AST</code></a>
that can be easily derived from <code>TyCtxt</code> queries, and we'll usually accept
PRs that remove fields from "clean" (it's been soft-deprecated), but this
is complicated from two other constraints that <code>rustdoc</code> runs under:</p>
<ul>
<li>Docs can be generated for crates that don't actually pass type checking.
This is used for generating docs that cover mutually-exclusive platform
configurations, such as <code>libstd</code> having a single package of docs that
cover all supported operating systems. This means <code>rustdoc</code> has to be able
to generate docs from <code>HIR</code>.</li>
<li>Docs can inline across crates. Since crate metadata doesn't contain <code>HIR</code>,
it must be possible to generate inlined docs from the <code>rustc_middle</code> data.</li>
</ul>
<p>The "clean" <a href="./ast-validation.html"><code>AST</code></a> acts as a common output format for both input formats. There
is also some data in clean that doesn't correspond directly to <code>HIR</code>, such as
synthetic <code>impl</code>s for auto traits and blanket <code>impl</code>s generated by the
<code>collect-trait-impls</code> pass.</p>
<p>Some additional data is stored in
<code>html::render::context::{Context, SharedContext}</code>. These two types serve as
ways to segregate <code>rustdoc</code>'s data for an eventual future with multithreaded doc
generation, as well as just keeping things organized:</p>
<ul>
<li><a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/html/render/context/struct.Context.html"><code>Context</code></a> stores data used for generating the current page, such as its
path, a list of <code>HTML</code> IDs that have been used (to avoid duplicate <code>id=""</code>),
and the pointer to <code>SharedContext</code>.</li>
<li><a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/html/render/context/struct.SharedContext.html"><code>SharedContext</code></a> stores data that does not vary by page, such as the <code>tcx</code>
pointer, and a list of all types.</li>
</ul>
<h2 id="other-tricks-up-its-sleeve"><a class="header" href="#other-tricks-up-its-sleeve">Other Tricks Up Its Sleeve</a></h2>
<p>All this describes the process for generating <code>HTML</code> documentation from a Rust
crate, but there are couple other major modes that <code>rustdoc</code> runs in. It can also
be run on a standalone Markdown file, or it can run <code>doctest</code>s on Rust code or
standalone Markdown files. For the former, it shortcuts straight to
<code>html/markdown.rs</code>, optionally including a mode which inserts a Table of
Contents to the output <code>HTML</code>.</p>
<p>For the latter, <code>rustdoc</code> runs a similar partial-compilation to get relevant
documentation in <code>test.rs</code>, but instead of going through the full clean and
render process, it runs a much simpler crate walk to grab <em>just</em> the
hand-written documentation. Combined with the aforementioned
"<code>find_testable_code</code>" in <code>html/markdown.rs</code>, it builds up a collection of
tests to run before handing them off to the test runner. One notable location
in <code>test.rs</code> is the function <code>make_test</code>, which is where hand-written
<code>doctest</code>s get transformed into something that can be executed.</p>
<p>Some extra reading about <code>make_test</code> can be found
<a href="https://quietmisdreavus.net/code/2018/02/23/how-the-doctests-get-made/">here</a>.</p>
<h2 id="testing-locally"><a class="header" href="#testing-locally">Testing Locally</a></h2>
<p>Some features of the generated <code>HTML</code> documentation might require local
storage to be used across pages, which doesn't work well without an <code>HTTP</code>
server. To test these features locally, you can run a local <code>HTTP</code> server, like
this:</p>
<pre><code class="language-bash">$ ./x doc library
# The documentation has been generated into `build/[YOUR ARCH]/doc`.
$ python3 -m http.server -d build/[YOUR ARCH]/doc
</code></pre>
<p>Now you can browse your documentation just like you would if it was hosted
on the internet. For example, the url for <code>std</code> will be <code>rust/std/</code>.</p>
<h2 id="see-also"><a class="header" href="#see-also">See Also</a></h2>
<ul>
<li>The <a href="https://doc.rust-lang.org/nightly/nightly-rustc/rustdoc/"><code>rustdoc</code> api docs</a></li>
<li><a href="./rustdoc.html">An overview of <code>rustdoc</code></a></li>
<li><a href="https://doc.rust-lang.org/nightly/rustdoc/">The rustdoc user guide</a></li>
</ul>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="parallel-rustc.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="rustdoc-internals/search.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="parallel-rustc.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="rustdoc-internals/search.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="elasticlunr.min.js"></script>
<script src="mark.min.js"></script>
<script src="searcher.js"></script>
<script src="clipboard.min.js"></script>
<script src="highlight.js"></script>
<script src="book.js"></script>
<!-- Custom JS scripts -->
<script src="mermaid.min.js"></script>
<script src="mermaid-init.js"></script>
</div>
</body>
</html>