]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/doc.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / src / bootstrap / doc.rs
CommitLineData
83c7162d 1//! Documentation generation for rustbuilder.
a7813a04
XL
2//!
3//! This module implements generation for all bits and pieces of documentation
4//! for the Rust project. This notably includes suites like the rust book, the
2c00a5a8 5//! nomicon, rust by example, standalone documentation, etc.
a7813a04
XL
6//!
7//! Everything here is basically just a shim around calling either `rustbook` or
8//! `rustdoc`.
9
0531ce1d 10use std::collections::HashSet;
0731742a 11use std::fs;
8bb4bdeb 12use std::io;
dfeec247 13use std::path::{Path, PathBuf};
7453a54e 14
0731742a 15use crate::Mode;
48663c56 16use build_helper::{t, up_to_date};
7453a54e 17
0731742a 18use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
dfeec247 19use crate::cache::{Interned, INTERNER};
0731742a 20use crate::compile;
3dfed10e 21use crate::config::{Config, TargetSelection};
dfeec247
XL
22use crate::tool::{self, prepare_tool_cargo, SourceType, Tool};
23use crate::util::symlink_dir;
3b2f2976
XL
24
25macro_rules! book {
416331ca 26 ($($name:ident, $path:expr, $book_name:expr;)+) => {
3b2f2976
XL
27 $(
28 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
29 pub struct $name {
3dfed10e 30 target: TargetSelection,
3b2f2976
XL
31 }
32
33 impl Step for $name {
34 type Output = ();
35 const DEFAULT: bool = true;
36
9fa01778 37 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 38 let builder = run.builder;
83c7162d 39 run.path($path).default_condition(builder.config.docs)
3b2f2976
XL
40 }
41
9fa01778 42 fn make_run(run: RunConfig<'_>) {
3b2f2976
XL
43 run.builder.ensure($name {
44 target: run.target,
45 });
46 }
47
9fa01778 48 fn run(self, builder: &Builder<'_>) {
dc9dc135 49 builder.ensure(RustbookSrc {
3b2f2976
XL
50 target: self.target,
51 name: INTERNER.intern_str($book_name),
dfeec247 52 src: INTERNER.intern_path(builder.src.join($path)),
3b2f2976
XL
53 })
54 }
55 }
56 )+
57 }
041b39d2
XL
58}
59
9fa01778
XL
60// NOTE: When adding a book here, make sure to ALSO build the book by
61// adding a build step in `src/bootstrap/builder.rs`!
3b2f2976 62book!(
dfeec247 63 CargoBook, "src/tools/cargo/src/doc", "cargo";
416331ca
XL
64 EditionGuide, "src/doc/edition-guide", "edition-guide";
65 EmbeddedBook, "src/doc/embedded-book", "embedded-book";
66 Nomicon, "src/doc/nomicon", "nomicon";
67 Reference, "src/doc/reference", "reference";
68 RustByExample, "src/doc/rust-by-example", "rust-by-example";
416331ca 69 RustdocBook, "src/doc/rustdoc", "rustdoc";
3b2f2976
XL
70);
71
f9f354fc
XL
72fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
73 if builder.config.dry_run || !builder.config.cmd.open() {
74 return;
75 }
76
77 let path = path.as_ref();
78 builder.info(&format!("Opening doc {}", path.display()));
79 if let Err(err) = opener::open(path) {
80 builder.info(&format!("{}\n", err));
81 }
82}
83
3dfed10e 84// "library/std" -> ["library", "std"]
f9f354fc
XL
85//
86// Used for deciding whether a particular step is one requested by the user on
87// the `x.py doc` command line, which determines whether `--open` will open that
88// page.
89fn components_simplified(path: &PathBuf) -> Vec<&str> {
90 path.iter().map(|component| component.to_str().unwrap_or("???")).collect()
91}
92
93fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
94 builder
95 .paths
96 .iter()
97 .map(components_simplified)
3dfed10e 98 .any(|requested| requested.iter().copied().eq(path.split('/')))
f9f354fc
XL
99}
100
3b2f2976
XL
101#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
102pub struct UnstableBook {
3dfed10e 103 target: TargetSelection,
3b2f2976 104}
cc61c64b 105
3b2f2976
XL
106impl Step for UnstableBook {
107 type Output = ();
108 const DEFAULT: bool = true;
cc61c64b 109
9fa01778 110 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 111 let builder = run.builder;
83c7162d 112 run.path("src/doc/unstable-book").default_condition(builder.config.docs)
3b2f2976
XL
113 }
114
9fa01778 115 fn make_run(run: RunConfig<'_>) {
dfeec247 116 run.builder.ensure(UnstableBook { target: run.target });
3b2f2976
XL
117 }
118
9fa01778 119 fn run(self, builder: &Builder<'_>) {
dfeec247 120 builder.ensure(UnstableBookGen { target: self.target });
3b2f2976
XL
121 builder.ensure(RustbookSrc {
122 target: self.target,
123 name: INTERNER.intern_str("unstable-book"),
dfeec247 124 src: INTERNER.intern_path(builder.md_doc_out(self.target).join("unstable-book")),
3b2f2976
XL
125 })
126 }
127}
128
129#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
130struct RustbookSrc {
3dfed10e 131 target: TargetSelection,
3b2f2976
XL
132 name: Interned<String>,
133 src: Interned<PathBuf>,
134}
135
136impl Step for RustbookSrc {
137 type Output = ();
138
9fa01778 139 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976
XL
140 run.never()
141 }
142
143 /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path.
144 ///
145 /// This will not actually generate any documentation if the documentation has
146 /// already been generated.
9fa01778 147 fn run(self, builder: &Builder<'_>) {
3b2f2976
XL
148 let target = self.target;
149 let name = self.name;
150 let src = self.src;
83c7162d 151 let out = builder.doc_out(target);
3b2f2976
XL
152 t!(fs::create_dir_all(&out));
153
154 let out = out.join(name);
3b2f2976
XL
155 let index = out.join("index.html");
156 let rustbook = builder.tool_exe(Tool::Rustbook);
83c7162d 157 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
f035d41b 158 if builder.config.dry_run || up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
dfeec247 159 return;
3b2f2976 160 }
83c7162d 161 builder.info(&format!("Rustbook ({}) - {}", target, name));
3b2f2976 162 let _ = fs::remove_dir_all(&out);
9fa01778 163
dfeec247 164 builder.run(rustbook_cmd.arg("build").arg(&src).arg("-d").arg(out));
3b2f2976
XL
165 }
166}
167
168#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
169pub struct TheBook {
170 compiler: Compiler,
3dfed10e 171 target: TargetSelection,
3b2f2976 172}
cc61c64b 173
3b2f2976
XL
174impl Step for TheBook {
175 type Output = ();
176 const DEFAULT: bool = true;
177
9fa01778 178 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 179 let builder = run.builder;
83c7162d 180 run.path("src/doc/book").default_condition(builder.config.docs)
3b2f2976
XL
181 }
182
9fa01778 183 fn make_run(run: RunConfig<'_>) {
3b2f2976 184 run.builder.ensure(TheBook {
83c7162d 185 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
3b2f2976 186 target: run.target,
3b2f2976
XL
187 });
188 }
189
9fa01778 190 /// Builds the book and associated stuff.
3b2f2976
XL
191 ///
192 /// We need to build:
193 ///
dfeec247
XL
194 /// * Book
195 /// * Older edition redirects
abe05a73 196 /// * Version info and CSS
3b2f2976
XL
197 /// * Index page
198 /// * Redirect pages
9fa01778 199 fn run(self, builder: &Builder<'_>) {
abe05a73 200 let compiler = self.compiler;
3b2f2976 201 let target = self.target;
13cf67c4
XL
202
203 // build book
dc9dc135 204 builder.ensure(RustbookSrc {
3b2f2976 205 target,
dfeec247
XL
206 name: INTERNER.intern_str("book"),
207 src: INTERNER.intern_path(builder.src.join("src/doc/book")),
3b2f2976
XL
208 });
209
13cf67c4 210 // building older edition redirects
dfeec247
XL
211 for edition in &["first-edition", "second-edition", "2018-edition"] {
212 builder.ensure(RustbookSrc {
213 target,
214 name: INTERNER.intern_string(format!("book/{}", edition)),
215 src: INTERNER.intern_path(builder.src.join("src/doc/book").join(edition)),
216 });
217 }
94b46f34 218
abe05a73 219 // build the version info page and CSS
dfeec247 220 builder.ensure(Standalone { compiler, target });
abe05a73 221
3b2f2976 222 // build the redirect pages
83c7162d
XL
223 builder.info(&format!("Documenting book redirect pages ({})", target));
224 for file in t!(fs::read_dir(builder.src.join("src/doc/book/redirects"))) {
3b2f2976
XL
225 let file = t!(file);
226 let path = file.path();
227 let path = path.to_str().unwrap();
228
abe05a73 229 invoke_rustdoc(builder, compiler, target, path);
3b2f2976 230 }
f9f354fc
XL
231
232 if is_explicit_request(builder, "src/doc/book") {
233 let out = builder.doc_out(target);
234 let index = out.join("book").join("index.html");
235 open(builder, &index);
236 }
3b2f2976
XL
237 }
238}
239
9fa01778
XL
240fn invoke_rustdoc(
241 builder: &Builder<'_>,
242 compiler: Compiler,
3dfed10e 243 target: TargetSelection,
9fa01778
XL
244 markdown: &str,
245) {
83c7162d 246 let out = builder.doc_out(target);
3b2f2976 247
83c7162d 248 let path = builder.src.join("src/doc").join(markdown);
cc61c64b 249
532ac7d7 250 let header = builder.src.join("src/doc/redirect.inc");
83c7162d 251 let footer = builder.src.join("src/doc/footer.inc");
cc61c64b
XL
252 let version_info = out.join("version_info.html");
253
532ac7d7 254 let mut cmd = builder.rustdoc_cmd(compiler);
cc61c64b
XL
255
256 let out = out.join("book");
257
dfeec247
XL
258 cmd.arg("--html-after-content")
259 .arg(&footer)
260 .arg("--html-before-content")
261 .arg(&version_info)
262 .arg("--html-in-header")
263 .arg(&header)
0531ce1d 264 .arg("--markdown-no-toc")
dfeec247
XL
265 .arg("--markdown-playground-url")
266 .arg("https://play.rust-lang.org/")
267 .arg("-o")
268 .arg(&out)
269 .arg(&path)
270 .arg("--markdown-css")
271 .arg("../rust.css");
cc61c64b 272
6a06907d
XL
273 if !builder.config.docs_minification {
274 cmd.arg("-Z").arg("unstable-options").arg("--disable-minification");
275 }
276
83c7162d 277 builder.run(&mut cmd);
cc61c64b
XL
278}
279
3b2f2976
XL
280#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
281pub struct Standalone {
282 compiler: Compiler,
3dfed10e 283 target: TargetSelection,
3b2f2976 284}
7453a54e 285
3b2f2976
XL
286impl Step for Standalone {
287 type Output = ();
288 const DEFAULT: bool = true;
7453a54e 289
9fa01778 290 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 291 let builder = run.builder;
83c7162d 292 run.path("src/doc").default_condition(builder.config.docs)
3b2f2976 293 }
7453a54e 294
9fa01778 295 fn make_run(run: RunConfig<'_>) {
3b2f2976 296 run.builder.ensure(Standalone {
83c7162d 297 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
3b2f2976
XL
298 target: run.target,
299 });
7453a54e
SL
300 }
301
3b2f2976
XL
302 /// Generates all standalone documentation as compiled by the rustdoc in `stage`
303 /// for the `target` into `out`.
304 ///
305 /// This will list all of `src/doc` looking for markdown files and appropriately
306 /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
307 /// `STAMP` along with providing the various header/footer HTML we've customized.
308 ///
309 /// In the end, this is just a glorified wrapper around rustdoc!
9fa01778 310 fn run(self, builder: &Builder<'_>) {
3b2f2976
XL
311 let target = self.target;
312 let compiler = self.compiler;
83c7162d
XL
313 builder.info(&format!("Documenting standalone ({})", target));
314 let out = builder.doc_out(target);
3b2f2976
XL
315 t!(fs::create_dir_all(&out));
316
83c7162d
XL
317 let favicon = builder.src.join("src/doc/favicon.inc");
318 let footer = builder.src.join("src/doc/footer.inc");
319 let full_toc = builder.src.join("src/doc/full-toc.inc");
320 t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
3b2f2976 321
83c7162d 322 let version_input = builder.src.join("src/doc/version_info.html.template");
3b2f2976
XL
323 let version_info = out.join("version_info.html");
324
83c7162d 325 if !builder.config.dry_run && !up_to_date(&version_input, &version_info) {
0731742a
XL
326 let info = t!(fs::read_to_string(&version_input))
327 .replace("VERSION", &builder.rust_release())
328 .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or(""))
329 .replace("STAMP", builder.rust_info.sha().unwrap_or(""));
330 t!(fs::write(&version_info, &info));
7453a54e
SL
331 }
332
83c7162d 333 for file in t!(fs::read_dir(builder.src.join("src/doc"))) {
3b2f2976
XL
334 let file = t!(file);
335 let path = file.path();
336 let filename = path.file_name().unwrap().to_str().unwrap();
337 if !filename.ends_with(".md") || filename == "README.md" {
dfeec247 338 continue;
3b2f2976
XL
339 }
340
341 let html = out.join(filename).with_extension("html");
532ac7d7 342 let rustdoc = builder.rustdoc(compiler);
dfeec247
XL
343 if up_to_date(&path, &html)
344 && up_to_date(&footer, &html)
345 && up_to_date(&favicon, &html)
346 && up_to_date(&full_toc, &html)
347 && (builder.config.dry_run || up_to_date(&version_info, &html))
348 && (builder.config.dry_run || up_to_date(&rustdoc, &html))
349 {
350 continue;
3b2f2976
XL
351 }
352
532ac7d7 353 let mut cmd = builder.rustdoc_cmd(compiler);
ba9703b0
XL
354 // Needed for --index-page flag
355 cmd.arg("-Z").arg("unstable-options");
356
dfeec247
XL
357 cmd.arg("--html-after-content")
358 .arg(&footer)
359 .arg("--html-before-content")
360 .arg(&version_info)
361 .arg("--html-in-header")
362 .arg(&favicon)
363 .arg("--markdown-no-toc")
364 .arg("--index-page")
365 .arg(&builder.src.join("src/doc/index.md"))
366 .arg("--markdown-playground-url")
367 .arg("https://play.rust-lang.org/")
368 .arg("-o")
369 .arg(&out)
370 .arg(&path);
3b2f2976 371
6a06907d
XL
372 if !builder.config.docs_minification {
373 cmd.arg("--disable-minification");
374 }
375
3b2f2976 376 if filename == "not_found.md" {
dfeec247 377 cmd.arg("--markdown-css").arg("https://doc.rust-lang.org/rust.css");
3b2f2976
XL
378 } else {
379 cmd.arg("--markdown-css").arg("rust.css");
380 }
83c7162d 381 builder.run(&mut cmd);
7453a54e 382 }
f9f354fc
XL
383
384 // We open doc/index.html as the default if invoked as `x.py doc --open`
3dfed10e 385 // with no particular explicit doc requested (e.g. library/core).
f9f354fc
XL
386 if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") {
387 let index = out.join("index.html");
388 open(builder, &index);
389 }
3b2f2976
XL
390 }
391}
392
393#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
394pub struct Std {
2c00a5a8 395 pub stage: u32,
3dfed10e 396 pub target: TargetSelection,
3b2f2976
XL
397}
398
399impl Step for Std {
400 type Output = ();
401 const DEFAULT: bool = true;
402
9fa01778 403 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 404 let builder = run.builder;
e1599b0c 405 run.all_krates("test").default_condition(builder.config.docs)
3b2f2976
XL
406 }
407
9fa01778 408 fn make_run(run: RunConfig<'_>) {
dfeec247 409 run.builder.ensure(Std { stage: run.builder.top_stage, target: run.target });
3b2f2976 410 }
7453a54e 411
3b2f2976
XL
412 /// Compile all standard library documentation.
413 ///
414 /// This will generate all documentation for the standard library and its
415 /// dependencies. This is largely just a wrapper around `cargo doc`.
9fa01778 416 fn run(self, builder: &Builder<'_>) {
3b2f2976
XL
417 let stage = self.stage;
418 let target = self.target;
83c7162d
XL
419 builder.info(&format!("Documenting stage{} std ({})", stage, target));
420 let out = builder.doc_out(target);
3b2f2976 421 t!(fs::create_dir_all(&out));
60c5eb7d 422 let compiler = builder.compiler(stage, builder.config.build);
3b2f2976
XL
423
424 builder.ensure(compile::Std { compiler, target });
3dfed10e 425 let out_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join("doc");
3b2f2976 426
a1dfa0c6 427 t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
3b2f2976 428
a1dfa0c6 429 let run_cargo_rustdoc_for = |package: &str| {
f035d41b
XL
430 let mut cargo =
431 builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc");
f9f354fc 432 compile::std_cargo(builder, target, compiler.stage, &mut cargo);
0531ce1d 433
dfeec247 434 cargo
3dfed10e
XL
435 .arg("-p")
436 .arg(package)
dfeec247
XL
437 .arg("--")
438 .arg("--markdown-css")
439 .arg("rust.css")
440 .arg("--markdown-no-toc")
ba9703b0
XL
441 .arg("-Z")
442 .arg("unstable-options")
dfeec247 443 .arg("--resource-suffix")
1b1a35ee 444 .arg(&builder.version)
dfeec247
XL
445 .arg("--index-page")
446 .arg(&builder.src.join("src/doc/index.md"));
a1dfa0c6 447
6a06907d
XL
448 if !builder.config.docs_minification {
449 cargo.arg("--disable-minification");
450 }
451
e1599b0c 452 builder.run(&mut cargo.into());
a1dfa0c6 453 };
f035d41b
XL
454 // Only build the following crates. While we could just iterate over the
455 // folder structure, that would also build internal crates that we do
456 // not want to show in documentation. These crates will later be visited
457 // by the rustc step, so internal documentation will show them.
3dfed10e
XL
458 //
459 // Note that the order here is important! The crates need to be
460 // processed starting from the leaves, otherwise rustdoc will not
461 // create correct links between crates because rustdoc depends on the
462 // existence of the output directories to know if it should be a local
463 // or remote link.
464 let krates = ["core", "alloc", "std", "proc_macro", "test"];
f9f354fc 465 for krate in &krates {
a1dfa0c6 466 run_cargo_rustdoc_for(krate);
7453a54e 467 }
3dfed10e 468 builder.cp_r(&out_dir, &out);
f9f354fc 469
3dfed10e 470 // Look for library/std, library/core etc in the `x.py doc` arguments and
f9f354fc
XL
471 // open the corresponding rendered docs.
472 for path in builder.paths.iter().map(components_simplified) {
3dfed10e
XL
473 if path.get(0) == Some(&"library") {
474 let requested_crate = &path[1];
f9f354fc
XL
475 if krates.contains(&requested_crate) {
476 let index = out.join(requested_crate).join("index.html");
477 open(builder, &index);
478 }
479 }
480 }
8bb4bdeb 481 }
3b2f2976 482}
8bb4bdeb 483
0531ce1d
XL
484#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
485pub struct Rustc {
486 stage: u32,
3dfed10e 487 target: TargetSelection,
0531ce1d
XL
488}
489
490impl Step for Rustc {
491 type Output = ();
492 const DEFAULT: bool = true;
493 const ONLY_HOSTS: bool = true;
494
9fa01778 495 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
0531ce1d 496 let builder = run.builder;
83c7162d 497 run.krate("rustc-main").default_condition(builder.config.docs)
0531ce1d
XL
498 }
499
9fa01778 500 fn make_run(run: RunConfig<'_>) {
dfeec247 501 run.builder.ensure(Rustc { stage: run.builder.top_stage, target: run.target });
0531ce1d
XL
502 }
503
9fa01778 504 /// Generates compiler documentation.
0531ce1d
XL
505 ///
506 /// This will generate all documentation for compiler and dependencies.
507 /// Compiler documentation is distributed separately, so we make sure
508 /// we do not merge it with the other documentation from std, test and
509 /// proc_macros. This is largely just a wrapper around `cargo doc`.
9fa01778 510 fn run(self, builder: &Builder<'_>) {
0531ce1d
XL
511 let stage = self.stage;
512 let target = self.target;
83c7162d 513 builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
94b46f34 514
83c7162d 515 if !builder.config.compiler_docs {
8faf50e0 516 builder.info("\tskipping - compiler/librustdoc docs disabled");
0531ce1d
XL
517 return;
518 }
519
5869c6ff
XL
520 // This is the intended out directory for compiler documentation.
521 let out = builder.compiler_doc_out(target);
522 t!(fs::create_dir_all(&out));
523
94b46f34 524 // Build rustc.
5869c6ff 525 let compiler = builder.compiler(stage, builder.config.build);
0531ce1d 526 builder.ensure(compile::Rustc { compiler, target });
94b46f34 527
3dfed10e
XL
528 // This uses a shared directory so that librustdoc documentation gets
529 // correctly built and merged with the rustc documentation. This is
530 // needed because rustdoc is built in a different directory from
531 // rustc. rustdoc needs to be able to see everything, for example when
532 // merging the search index, or generating local (relative) links.
533 let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target.triple).join("doc");
83c7162d 534 t!(symlink_dir_force(&builder.config, &out, &out_dir));
5869c6ff
XL
535 // Cargo puts proc macros in `target/doc` even if you pass `--target`
536 // explicitly (https://github.com/rust-lang/cargo/issues/7677).
537 let proc_macro_out_dir = builder.stage_out(compiler, Mode::Rustc).join("doc");
538 t!(symlink_dir_force(&builder.config, &out, &proc_macro_out_dir));
0531ce1d 539
94b46f34 540 // Build cargo command.
f035d41b 541 let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
3dfed10e
XL
542 cargo.rustdocflag("--document-private-items");
543 cargo.rustdocflag("--enable-index-page");
544 cargo.rustdocflag("-Zunstable-options");
5869c6ff 545 cargo.rustdocflag("-Znormalize-docs");
60c5eb7d 546 compile::rustc_cargo(builder, &mut cargo, target);
0531ce1d
XL
547
548 // Only include compiler crates, no dependencies of those, such as `libc`.
549 cargo.arg("--no-deps");
550
551 // Find dependencies for top level crates.
552 let mut compiler_crates = HashSet::new();
0731742a 553 for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
29967ef6
XL
554 compiler_crates.extend(
555 builder
556 .in_tree_crates(root_crate, Some(target))
557 .into_iter()
558 .map(|krate| krate.name),
559 );
0531ce1d
XL
560 }
561
562 for krate in &compiler_crates {
0731742a
XL
563 // Create all crate output directories first to make sure rustdoc uses
564 // relative links.
565 // FIXME: Cargo should probably do this itself.
566 t!(fs::create_dir_all(out_dir.join(krate)));
0531ce1d
XL
567 cargo.arg("-p").arg(krate);
568 }
569
e1599b0c 570 builder.run(&mut cargo.into());
0531ce1d
XL
571 }
572}
573
94b46f34
XL
574#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
575pub struct Rustdoc {
576 stage: u32,
3dfed10e 577 target: TargetSelection,
94b46f34
XL
578}
579
580impl Step for Rustdoc {
581 type Output = ();
582 const DEFAULT: bool = true;
583 const ONLY_HOSTS: bool = true;
584
9fa01778 585 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
94b46f34
XL
586 run.krate("rustdoc-tool")
587 }
588
9fa01778 589 fn make_run(run: RunConfig<'_>) {
dfeec247 590 run.builder.ensure(Rustdoc { stage: run.builder.top_stage, target: run.target });
94b46f34
XL
591 }
592
9fa01778 593 /// Generates compiler documentation.
94b46f34
XL
594 ///
595 /// This will generate all documentation for compiler and dependencies.
596 /// Compiler documentation is distributed separately, so we make sure
597 /// we do not merge it with the other documentation from std, test and
598 /// proc_macros. This is largely just a wrapper around `cargo doc`.
9fa01778 599 fn run(self, builder: &Builder<'_>) {
94b46f34
XL
600 let stage = self.stage;
601 let target = self.target;
602 builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target));
603
604 // This is the intended out directory for compiler documentation.
605 let out = builder.compiler_doc_out(target);
606 t!(fs::create_dir_all(&out));
607
f035d41b 608 let compiler = builder.compiler(stage, builder.config.build);
94b46f34
XL
609
610 if !builder.config.compiler_docs {
8faf50e0 611 builder.info("\tskipping - compiler/librustdoc docs disabled");
94b46f34
XL
612 return;
613 }
614
0731742a
XL
615 // Build rustc docs so that we generate relative links.
616 builder.ensure(Rustc { stage, target });
94b46f34
XL
617
618 // Build rustdoc.
74b04a01 619 builder.ensure(tool::Rustdoc { compiler });
94b46f34
XL
620
621 // Symlink compiler docs to the output directory of rustdoc documentation.
3dfed10e 622 let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target.triple).join("doc");
94b46f34 623 t!(fs::create_dir_all(&out_dir));
94b46f34
XL
624 t!(symlink_dir_force(&builder.config, &out, &out_dir));
625
626 // Build cargo command.
627 let mut cargo = prepare_tool_cargo(
8faf50e0
XL
628 builder,
629 compiler,
630 Mode::ToolRustc,
631 target,
632 "doc",
633 "src/tools/rustdoc",
634 SourceType::InTree,
dfeec247 635 &[],
8faf50e0 636 );
94b46f34 637
0731742a
XL
638 // Only include compiler crates, no dependencies of those, such as `libc`.
639 cargo.arg("--no-deps");
640 cargo.arg("-p").arg("rustdoc");
6a06907d 641 cargo.arg("-p").arg("rustdoc-json-types");
0731742a 642
3dfed10e 643 cargo.rustdocflag("--document-private-items");
5869c6ff
XL
644 cargo.rustdocflag("--enable-index-page");
645 cargo.rustdocflag("-Zunstable-options");
e1599b0c 646 builder.run(&mut cargo.into());
94b46f34
XL
647 }
648}
649
f035d41b 650#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
3b2f2976 651pub struct ErrorIndex {
3dfed10e 652 pub target: TargetSelection,
54a0048b
SL
653}
654
3b2f2976
XL
655impl Step for ErrorIndex {
656 type Output = ();
657 const DEFAULT: bool = true;
658 const ONLY_HOSTS: bool = true;
659
9fa01778 660 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 661 let builder = run.builder;
83c7162d 662 run.path("src/tools/error_index_generator").default_condition(builder.config.docs)
3b2f2976
XL
663 }
664
9fa01778 665 fn make_run(run: RunConfig<'_>) {
f035d41b 666 let target = run.target;
5869c6ff 667 run.builder.ensure(ErrorIndex { target });
3b2f2976
XL
668 }
669
670 /// Generates the HTML rendered error-index by running the
671 /// `error_index_generator` tool.
9fa01778 672 fn run(self, builder: &Builder<'_>) {
f035d41b
XL
673 builder.info(&format!("Documenting error index ({})", self.target));
674 let out = builder.doc_out(self.target);
3b2f2976 675 t!(fs::create_dir_all(&out));
5869c6ff 676 let mut index = tool::ErrorIndex::command(builder);
3b2f2976
XL
677 index.arg("html");
678 index.arg(out.join("error-index.html"));
1b1a35ee 679 index.arg(&builder.version);
3b2f2976 680
83c7162d 681 builder.run(&mut index);
3b2f2976
XL
682 }
683}
684
685#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
686pub struct UnstableBookGen {
3dfed10e 687 target: TargetSelection,
54a0048b 688}
8bb4bdeb 689
3b2f2976
XL
690impl Step for UnstableBookGen {
691 type Output = ();
692 const DEFAULT: bool = true;
693 const ONLY_HOSTS: bool = true;
041b39d2 694
9fa01778 695 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
3b2f2976 696 let builder = run.builder;
83c7162d 697 run.path("src/tools/unstable-book-gen").default_condition(builder.config.docs)
3b2f2976
XL
698 }
699
9fa01778 700 fn make_run(run: RunConfig<'_>) {
dfeec247 701 run.builder.ensure(UnstableBookGen { target: run.target });
3b2f2976
XL
702 }
703
9fa01778 704 fn run(self, builder: &Builder<'_>) {
3b2f2976
XL
705 let target = self.target;
706
83c7162d
XL
707 builder.info(&format!("Generating unstable book md files ({})", target));
708 let out = builder.md_doc_out(target).join("unstable-book");
709 builder.create_dir(&out);
710 builder.remove_dir(&out);
3b2f2976 711 let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
3dfed10e 712 cmd.arg(builder.src.join("library"));
1b1a35ee 713 cmd.arg(builder.src.join("compiler"));
83c7162d 714 cmd.arg(builder.src.join("src"));
3b2f2976
XL
715 cmd.arg(out);
716
83c7162d 717 builder.run(&mut cmd);
3b2f2976 718 }
041b39d2
XL
719}
720
83c7162d
XL
721fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> {
722 if config.dry_run {
723 return Ok(());
724 }
8bb4bdeb
XL
725 if let Ok(m) = fs::symlink_metadata(dst) {
726 if m.file_type().is_dir() {
a1dfa0c6 727 fs::remove_dir_all(dst)?;
8bb4bdeb
XL
728 } else {
729 // handle directory junctions on windows by falling back to
730 // `remove_dir`.
dfeec247 731 fs::remove_file(dst).or_else(|_| fs::remove_dir(dst))?;
8bb4bdeb
XL
732 }
733 }
734
83c7162d 735 symlink_dir(config, src, dst)
8bb4bdeb 736}
1b1a35ee
XL
737
738#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
739pub struct RustcBook {
740 pub compiler: Compiler,
741 pub target: TargetSelection,
fc512014 742 pub validate: bool,
1b1a35ee
XL
743}
744
745impl Step for RustcBook {
746 type Output = ();
747 const DEFAULT: bool = true;
748 const ONLY_HOSTS: bool = true;
749
750 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
751 let builder = run.builder;
752 run.path("src/doc/rustc").default_condition(builder.config.docs)
753 }
754
755 fn make_run(run: RunConfig<'_>) {
756 run.builder.ensure(RustcBook {
757 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
758 target: run.target,
fc512014 759 validate: false,
1b1a35ee
XL
760 });
761 }
762
763 /// Builds the rustc book.
764 ///
765 /// The lints are auto-generated by a tool, and then merged into the book
766 /// in the "md-doc" directory in the build output directory. Then
767 /// "rustbook" is used to convert it to HTML.
768 fn run(self, builder: &Builder<'_>) {
769 let out_base = builder.md_doc_out(self.target).join("rustc");
770 t!(fs::create_dir_all(&out_base));
771 let out_listing = out_base.join("src/lints");
772 builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base);
773 builder.info(&format!("Generating lint docs ({})", self.target));
774
775 let rustc = builder.rustc(self.compiler);
776 // The tool runs `rustc` for extracting output examples, so it needs a
777 // functional sysroot.
778 builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
779 let mut cmd = builder.tool_cmd(Tool::LintDocs);
780 cmd.arg("--src");
781 cmd.arg(builder.src.join("compiler"));
782 cmd.arg("--out");
783 cmd.arg(&out_listing);
784 cmd.arg("--rustc");
785 cmd.arg(&rustc);
786 cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg());
787 if builder.config.verbose() {
788 cmd.arg("--verbose");
789 }
fc512014
XL
790 if self.validate {
791 cmd.arg("--validate");
792 }
1b1a35ee
XL
793 // If the lib directories are in an unusual location (changed in
794 // config.toml), then this needs to explicitly update the dylib search
795 // path.
796 builder.add_rustc_lib_path(self.compiler, &mut cmd);
797 builder.run(&mut cmd);
798 // Run rustbook/mdbook to generate the HTML pages.
799 builder.ensure(RustbookSrc {
800 target: self.target,
801 name: INTERNER.intern_str("rustc"),
802 src: INTERNER.intern_path(out_base),
803 });
804 if is_explicit_request(builder, "src/doc/rustc") {
805 let out = builder.doc_out(self.target);
806 let index = out.join("rustc").join("index.html");
807 open(builder, &index);
808 }
809 }
810}