]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/doc.rs
New upstream version 1.26.2+dfsg1
[rustc.git] / src / bootstrap / doc.rs
CommitLineData
7453a54e
SL
1// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
a7813a04
XL
11//! Documentation generation for rustbuild.
12//!
13//! This module implements generation for all bits and pieces of documentation
14//! for the Rust project. This notably includes suites like the rust book, the
2c00a5a8 15//! nomicon, rust by example, standalone documentation, etc.
a7813a04
XL
16//!
17//! Everything here is basically just a shim around calling either `rustbook` or
18//! `rustdoc`.
19
0531ce1d 20use std::collections::HashSet;
7453a54e
SL
21use std::fs::{self, File};
22use std::io::prelude::*;
8bb4bdeb 23use std::io;
3b2f2976 24use std::path::{PathBuf, Path};
7453a54e 25
0531ce1d 26use {Build, Mode};
8bb4bdeb 27use build_helper::up_to_date;
7453a54e 28
3b2f2976
XL
29use util::{cp_r, symlink_dir};
30use builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
31use tool::Tool;
32use compile;
33use cache::{INTERNER, Interned};
34
35macro_rules! book {
36 ($($name:ident, $path:expr, $book_name:expr;)+) => {
37 $(
38 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
39 pub struct $name {
40 target: Interned<String>,
41 }
42
43 impl Step for $name {
44 type Output = ();
45 const DEFAULT: bool = true;
46
47 fn should_run(run: ShouldRun) -> ShouldRun {
48 let builder = run.builder;
49 run.path($path).default_condition(builder.build.config.docs)
50 }
51
52 fn make_run(run: RunConfig) {
53 run.builder.ensure($name {
54 target: run.target,
55 });
56 }
57
58 fn run(self, builder: &Builder) {
59 builder.ensure(Rustbook {
60 target: self.target,
61 name: INTERNER.intern_str($book_name),
62 })
63 }
64 }
65 )+
66 }
041b39d2
XL
67}
68
3b2f2976 69book!(
abe05a73 70 Nomicon, "src/doc/nomicon", "nomicon";
3b2f2976
XL
71 Reference, "src/doc/reference", "reference";
72 Rustdoc, "src/doc/rustdoc", "rustdoc";
2c00a5a8 73 RustByExample, "src/doc/rust-by-example", "rust-by-example";
3b2f2976
XL
74);
75
76#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
77struct Rustbook {
78 target: Interned<String>,
79 name: Interned<String>,
7453a54e
SL
80}
81
3b2f2976
XL
82impl Step for Rustbook {
83 type Output = ();
84
85 // rustbook is never directly called, and only serves as a shim for the nomicon and the
86 // reference.
87 fn should_run(run: ShouldRun) -> ShouldRun {
88 run.never()
89 }
90
91 /// Invoke `rustbook` for `target` for the doc book `name`.
92 ///
93 /// This will not actually generate any documentation if the documentation has
94 /// already been generated.
95 fn run(self, builder: &Builder) {
96 let src = builder.build.src.join("src/doc");
97 builder.ensure(RustbookSrc {
98 target: self.target,
99 name: self.name,
100 src: INTERNER.intern_path(src),
101 });
cc61c64b
XL
102 }
103}
104
3b2f2976
XL
105#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
106pub struct UnstableBook {
107 target: Interned<String>,
108}
cc61c64b 109
3b2f2976
XL
110impl Step for UnstableBook {
111 type Output = ();
112 const DEFAULT: bool = true;
cc61c64b 113
3b2f2976
XL
114 fn should_run(run: ShouldRun) -> ShouldRun {
115 let builder = run.builder;
116 run.path("src/doc/unstable-book").default_condition(builder.build.config.docs)
117 }
118
119 fn make_run(run: RunConfig) {
120 run.builder.ensure(UnstableBook {
121 target: run.target,
122 });
123 }
124
125 fn run(self, builder: &Builder) {
126 builder.ensure(UnstableBookGen {
127 target: self.target,
128 });
129 builder.ensure(RustbookSrc {
130 target: self.target,
131 name: INTERNER.intern_str("unstable-book"),
132 src: builder.build.md_doc_out(self.target),
133 })
134 }
135}
136
abe05a73
XL
137#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
138pub struct CargoBook {
139 target: Interned<String>,
140 name: Interned<String>,
141}
142
143impl Step for CargoBook {
144 type Output = ();
145 const DEFAULT: bool = true;
146
147 fn should_run(run: ShouldRun) -> ShouldRun {
148 let builder = run.builder;
149 run.path("src/tools/cargo/src/doc/book").default_condition(builder.build.config.docs)
150 }
151
152 fn make_run(run: RunConfig) {
153 run.builder.ensure(CargoBook {
154 target: run.target,
155 name: INTERNER.intern_str("cargo"),
156 });
157 }
158
159 fn run(self, builder: &Builder) {
160 let build = builder.build;
161
162 let target = self.target;
163 let name = self.name;
2c00a5a8 164 let src = build.src.join("src/tools/cargo/src/doc");
abe05a73
XL
165
166 let out = build.doc_out(target);
167 t!(fs::create_dir_all(&out));
168
169 let out = out.join(name);
170
171 println!("Cargo Book ({}) - {}", target, name);
172
173 let _ = fs::remove_dir_all(&out);
174
175 build.run(builder.tool_cmd(Tool::Rustbook)
176 .arg("build")
177 .arg(&src)
178 .arg("-d")
179 .arg(out));
180 }
181}
182
3b2f2976
XL
183#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
184struct RustbookSrc {
185 target: Interned<String>,
186 name: Interned<String>,
187 src: Interned<PathBuf>,
188}
189
190impl Step for RustbookSrc {
191 type Output = ();
192
193 fn should_run(run: ShouldRun) -> ShouldRun {
194 run.never()
195 }
196
197 /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path.
198 ///
199 /// This will not actually generate any documentation if the documentation has
200 /// already been generated.
201 fn run(self, builder: &Builder) {
202 let build = builder.build;
203 let target = self.target;
204 let name = self.name;
205 let src = self.src;
206 let out = build.doc_out(target);
207 t!(fs::create_dir_all(&out));
208
209 let out = out.join(name);
210 let src = src.join(name);
211 let index = out.join("index.html");
212 let rustbook = builder.tool_exe(Tool::Rustbook);
213 if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
214 return
215 }
216 println!("Rustbook ({}) - {}", target, name);
217 let _ = fs::remove_dir_all(&out);
218 build.run(builder.tool_cmd(Tool::Rustbook)
219 .arg("build")
220 .arg(&src)
221 .arg("-d")
222 .arg(out));
223 }
224}
225
226#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
227pub struct TheBook {
228 compiler: Compiler,
229 target: Interned<String>,
230 name: &'static str,
231}
cc61c64b 232
3b2f2976
XL
233impl Step for TheBook {
234 type Output = ();
235 const DEFAULT: bool = true;
236
237 fn should_run(run: ShouldRun) -> ShouldRun {
238 let builder = run.builder;
239 run.path("src/doc/book").default_condition(builder.build.config.docs)
240 }
241
242 fn make_run(run: RunConfig) {
243 run.builder.ensure(TheBook {
244 compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
245 target: run.target,
246 name: "book",
247 });
248 }
249
250 /// Build the book and associated stuff.
251 ///
252 /// We need to build:
253 ///
254 /// * Book (first edition)
255 /// * Book (second edition)
abe05a73 256 /// * Version info and CSS
3b2f2976
XL
257 /// * Index page
258 /// * Redirect pages
259 fn run(self, builder: &Builder) {
260 let build = builder.build;
abe05a73 261 let compiler = self.compiler;
3b2f2976
XL
262 let target = self.target;
263 let name = self.name;
264 // build book first edition
265 builder.ensure(Rustbook {
266 target,
267 name: INTERNER.intern_string(format!("{}/first-edition", name)),
268 });
269
270 // build book second edition
271 builder.ensure(Rustbook {
272 target,
273 name: INTERNER.intern_string(format!("{}/second-edition", name)),
274 });
275
abe05a73
XL
276 // build the version info page and CSS
277 builder.ensure(Standalone {
278 compiler,
279 target,
280 });
281
3b2f2976
XL
282 // build the index page
283 let index = format!("{}/index.md", name);
284 println!("Documenting book index ({})", target);
abe05a73 285 invoke_rustdoc(builder, compiler, target, &index);
3b2f2976
XL
286
287 // build the redirect pages
288 println!("Documenting book redirect pages ({})", target);
289 for file in t!(fs::read_dir(build.src.join("src/doc/book/redirects"))) {
290 let file = t!(file);
291 let path = file.path();
292 let path = path.to_str().unwrap();
293
abe05a73 294 invoke_rustdoc(builder, compiler, target, path);
3b2f2976
XL
295 }
296 }
297}
298
3b2f2976
XL
299fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String>, markdown: &str) {
300 let build = builder.build;
301 let out = build.doc_out(target);
302
303 let path = build.src.join("src/doc").join(markdown);
cc61c64b
XL
304
305 let favicon = build.src.join("src/doc/favicon.inc");
306 let footer = build.src.join("src/doc/footer.inc");
cc61c64b
XL
307 let version_info = out.join("version_info.html");
308
3b2f2976 309 let mut cmd = builder.rustdoc_cmd(compiler.host);
cc61c64b
XL
310
311 let out = out.join("book");
312
cc61c64b
XL
313 cmd.arg("--html-after-content").arg(&footer)
314 .arg("--html-before-content").arg(&version_info)
315 .arg("--html-in-header").arg(&favicon)
0531ce1d 316 .arg("--markdown-no-toc")
cc61c64b
XL
317 .arg("--markdown-playground-url")
318 .arg("https://play.rust-lang.org/")
319 .arg("-o").arg(&out)
320 .arg(&path)
321 .arg("--markdown-css")
abe05a73 322 .arg("../rust.css");
cc61c64b
XL
323
324 build.run(&mut cmd);
325}
326
3b2f2976
XL
327#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
328pub struct Standalone {
329 compiler: Compiler,
330 target: Interned<String>,
331}
7453a54e 332
3b2f2976
XL
333impl Step for Standalone {
334 type Output = ();
335 const DEFAULT: bool = true;
7453a54e 336
3b2f2976
XL
337 fn should_run(run: ShouldRun) -> ShouldRun {
338 let builder = run.builder;
339 run.path("src/doc").default_condition(builder.build.config.docs)
340 }
7453a54e 341
3b2f2976
XL
342 fn make_run(run: RunConfig) {
343 run.builder.ensure(Standalone {
344 compiler: run.builder.compiler(run.builder.top_stage, run.builder.build.build),
345 target: run.target,
346 });
7453a54e
SL
347 }
348
3b2f2976
XL
349 /// Generates all standalone documentation as compiled by the rustdoc in `stage`
350 /// for the `target` into `out`.
351 ///
352 /// This will list all of `src/doc` looking for markdown files and appropriately
353 /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
354 /// `STAMP` along with providing the various header/footer HTML we've customized.
355 ///
356 /// In the end, this is just a glorified wrapper around rustdoc!
357 fn run(self, builder: &Builder) {
358 let build = builder.build;
359 let target = self.target;
360 let compiler = self.compiler;
361 println!("Documenting standalone ({})", target);
362 let out = build.doc_out(target);
363 t!(fs::create_dir_all(&out));
364
365 let favicon = build.src.join("src/doc/favicon.inc");
366 let footer = build.src.join("src/doc/footer.inc");
367 let full_toc = build.src.join("src/doc/full-toc.inc");
368 t!(fs::copy(build.src.join("src/doc/rust.css"), out.join("rust.css")));
369
370 let version_input = build.src.join("src/doc/version_info.html.template");
371 let version_info = out.join("version_info.html");
372
373 if !up_to_date(&version_input, &version_info) {
374 let mut info = String::new();
375 t!(t!(File::open(&version_input)).read_to_string(&mut info));
376 let info = info.replace("VERSION", &build.rust_release())
377 .replace("SHORT_HASH", build.rust_info.sha_short().unwrap_or(""))
378 .replace("STAMP", build.rust_info.sha().unwrap_or(""));
379 t!(t!(File::create(&version_info)).write_all(info.as_bytes()));
7453a54e
SL
380 }
381
3b2f2976
XL
382 for file in t!(fs::read_dir(build.src.join("src/doc"))) {
383 let file = t!(file);
384 let path = file.path();
385 let filename = path.file_name().unwrap().to_str().unwrap();
386 if !filename.ends_with(".md") || filename == "README.md" {
387 continue
388 }
389
390 let html = out.join(filename).with_extension("html");
391 let rustdoc = builder.rustdoc(compiler.host);
392 if up_to_date(&path, &html) &&
393 up_to_date(&footer, &html) &&
394 up_to_date(&favicon, &html) &&
395 up_to_date(&full_toc, &html) &&
396 up_to_date(&version_info, &html) &&
397 up_to_date(&rustdoc, &html) {
398 continue
399 }
400
401 let mut cmd = builder.rustdoc_cmd(compiler.host);
402 cmd.arg("--html-after-content").arg(&footer)
403 .arg("--html-before-content").arg(&version_info)
404 .arg("--html-in-header").arg(&favicon)
405 .arg("--markdown-playground-url")
406 .arg("https://play.rust-lang.org/")
407 .arg("-o").arg(&out)
408 .arg(&path);
409
410 if filename == "not_found.md" {
411 cmd.arg("--markdown-no-toc")
412 .arg("--markdown-css")
413 .arg("https://doc.rust-lang.org/rust.css");
414 } else {
415 cmd.arg("--markdown-css").arg("rust.css");
416 }
417 build.run(&mut cmd);
7453a54e 418 }
3b2f2976
XL
419 }
420}
421
422#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
423pub struct Std {
2c00a5a8
XL
424 pub stage: u32,
425 pub target: Interned<String>,
3b2f2976
XL
426}
427
428impl Step for Std {
429 type Output = ();
430 const DEFAULT: bool = true;
431
432 fn should_run(run: ShouldRun) -> ShouldRun {
433 let builder = run.builder;
2c00a5a8 434 run.all_krates("std").default_condition(builder.build.config.docs)
3b2f2976
XL
435 }
436
437 fn make_run(run: RunConfig) {
438 run.builder.ensure(Std {
439 stage: run.builder.top_stage,
440 target: run.target
441 });
442 }
7453a54e 443
3b2f2976
XL
444 /// Compile all standard library documentation.
445 ///
446 /// This will generate all documentation for the standard library and its
447 /// dependencies. This is largely just a wrapper around `cargo doc`.
448 fn run(self, builder: &Builder) {
449 let build = builder.build;
450 let stage = self.stage;
451 let target = self.target;
452 println!("Documenting stage{} std ({})", stage, target);
453 let out = build.doc_out(target);
454 t!(fs::create_dir_all(&out));
455 let compiler = builder.compiler(stage, build.build);
456 let rustdoc = builder.rustdoc(compiler.host);
457 let compiler = if build.force_use_stage1(compiler, target) {
458 builder.compiler(1, compiler.host)
7453a54e 459 } else {
3b2f2976
XL
460 compiler
461 };
462
463 builder.ensure(compile::Std { compiler, target });
464 let out_dir = build.stage_out(compiler, Mode::Libstd)
465 .join(target).join("doc");
466
467 // Here what we're doing is creating a *symlink* (directory junction on
468 // Windows) to the final output location. This is not done as an
469 // optimization but rather for correctness. We've got three trees of
470 // documentation, one for std, one for test, and one for rustc. It's then
471 // our job to merge them all together.
472 //
473 // Unfortunately rustbuild doesn't know nearly as well how to merge doc
474 // trees as rustdoc does itself, so instead of actually having three
475 // separate trees we just have rustdoc output to the same location across
476 // all of them.
477 //
478 // This way rustdoc generates output directly into the output, and rustdoc
479 // will also directly handle merging.
480 let my_out = build.crate_doc_out(target);
481 build.clear_if_dirty(&my_out, &rustdoc);
482 t!(symlink_dir_force(&my_out, &out_dir));
483
484 let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc");
0531ce1d
XL
485 compile::std_cargo(builder, &compiler, target, &mut cargo);
486
487 // Keep a whitelist so we do not build internal stdlib crates, these will be
488 // build by the rustc step later if enabled.
489 cargo.arg("--no-deps");
490 for krate in &["alloc", "core", "std", "std_unicode"] {
491 cargo.arg("-p").arg(krate);
492 // Create all crate output directories first to make sure rustdoc uses
493 // relative links.
494 // FIXME: Cargo should probably do this itself.
495 t!(fs::create_dir_all(out_dir.join(krate)));
7453a54e 496 }
3b2f2976 497
3b2f2976
XL
498 build.run(&mut cargo);
499 cp_r(&my_out, &out);
7453a54e
SL
500 }
501}
54a0048b 502
3b2f2976
XL
503#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
504pub struct Test {
505 stage: u32,
506 target: Interned<String>,
507}
508
509impl Step for Test {
510 type Output = ();
511 const DEFAULT: bool = true;
512
513 fn should_run(run: ShouldRun) -> ShouldRun {
514 let builder = run.builder;
0531ce1d 515 run.krate("test").default_condition(builder.build.config.docs)
476ff2be
SL
516 }
517
3b2f2976
XL
518 fn make_run(run: RunConfig) {
519 run.builder.ensure(Test {
520 stage: run.builder.top_stage,
521 target: run.target,
522 });
523 }
524
525 /// Compile all libtest documentation.
526 ///
527 /// This will generate all documentation for libtest and its dependencies. This
528 /// is largely just a wrapper around `cargo doc`.
529 fn run(self, builder: &Builder) {
530 let build = builder.build;
531 let stage = self.stage;
532 let target = self.target;
533 println!("Documenting stage{} test ({})", stage, target);
534 let out = build.doc_out(target);
535 t!(fs::create_dir_all(&out));
536 let compiler = builder.compiler(stage, build.build);
537 let rustdoc = builder.rustdoc(compiler.host);
538 let compiler = if build.force_use_stage1(compiler, target) {
539 builder.compiler(1, compiler.host)
540 } else {
541 compiler
542 };
543
544 // Build libstd docs so that we generate relative links
545 builder.ensure(Std { stage, target });
32a655c1 546
3b2f2976
XL
547 builder.ensure(compile::Test { compiler, target });
548 let out_dir = build.stage_out(compiler, Mode::Libtest)
549 .join(target).join("doc");
550
551 // See docs in std above for why we symlink
552 let my_out = build.crate_doc_out(target);
553 build.clear_if_dirty(&my_out, &rustdoc);
554 t!(symlink_dir_force(&my_out, &out_dir));
555
556 let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc");
557 compile::test_cargo(build, &compiler, target, &mut cargo);
0531ce1d
XL
558
559 cargo.arg("--no-deps").arg("-p").arg("test");
560
3b2f2976
XL
561 build.run(&mut cargo);
562 cp_r(&my_out, &out);
563 }
54a0048b
SL
564}
565
3b2f2976 566#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
0531ce1d 567pub struct WhitelistedRustc {
3b2f2976
XL
568 stage: u32,
569 target: Interned<String>,
54a0048b
SL
570}
571
0531ce1d 572impl Step for WhitelistedRustc {
3b2f2976
XL
573 type Output = ();
574 const DEFAULT: bool = true;
575 const ONLY_HOSTS: bool = true;
576
577 fn should_run(run: ShouldRun) -> ShouldRun {
578 let builder = run.builder;
579 run.krate("rustc-main").default_condition(builder.build.config.docs)
580 }
581
582 fn make_run(run: RunConfig) {
0531ce1d 583 run.builder.ensure(WhitelistedRustc {
3b2f2976
XL
584 stage: run.builder.top_stage,
585 target: run.target,
586 });
587 }
588
0531ce1d 589 /// Generate whitelisted compiler crate documentation.
3b2f2976 590 ///
0531ce1d
XL
591 /// This will generate all documentation for crates that are whitelisted
592 /// to be included in the standard documentation. This documentation is
593 /// included in the standard Rust documentation, so we should always
594 /// document it and symlink to merge with the rest of the std and test
595 /// documentation. We don't build other compiler documentation
596 /// here as we want to be able to keep it separate from the standard
597 /// documentation. This is largely just a wrapper around `cargo doc`.
3b2f2976
XL
598 fn run(self, builder: &Builder) {
599 let build = builder.build;
600 let stage = self.stage;
601 let target = self.target;
0531ce1d 602 println!("Documenting stage{} whitelisted compiler ({})", stage, target);
3b2f2976
XL
603 let out = build.doc_out(target);
604 t!(fs::create_dir_all(&out));
605 let compiler = builder.compiler(stage, build.build);
606 let rustdoc = builder.rustdoc(compiler.host);
607 let compiler = if build.force_use_stage1(compiler, target) {
608 builder.compiler(1, compiler.host)
609 } else {
610 compiler
611 };
612
613 // Build libstd docs so that we generate relative links
614 builder.ensure(Std { stage, target });
615
616 builder.ensure(compile::Rustc { compiler, target });
617 let out_dir = build.stage_out(compiler, Mode::Librustc)
618 .join(target).join("doc");
619
620 // See docs in std above for why we symlink
621 let my_out = build.crate_doc_out(target);
622 build.clear_if_dirty(&my_out, &rustdoc);
623 t!(symlink_dir_force(&my_out, &out_dir));
624
625 let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
2c00a5a8 626 compile::rustc_cargo(build, &mut cargo);
3b2f2976 627
0531ce1d
XL
628 // We don't want to build docs for internal compiler dependencies in this
629 // step (there is another step for that). Therefore, we whitelist the crates
630 // for which docs must be built.
631 cargo.arg("--no-deps");
632 for krate in &["proc_macro"] {
633 cargo.arg("-p").arg(krate);
8bb4bdeb 634 }
3b2f2976
XL
635
636 build.run(&mut cargo);
637 cp_r(&my_out, &out);
8bb4bdeb 638 }
3b2f2976 639}
8bb4bdeb 640
0531ce1d
XL
641#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
642pub struct Rustc {
643 stage: u32,
644 target: Interned<String>,
645}
646
647impl Step for Rustc {
648 type Output = ();
649 const DEFAULT: bool = true;
650 const ONLY_HOSTS: bool = true;
651
652 fn should_run(run: ShouldRun) -> ShouldRun {
653 let builder = run.builder;
654 run.krate("rustc-main").default_condition(builder.build.config.docs)
655 }
656
657 fn make_run(run: RunConfig) {
658 run.builder.ensure(Rustc {
659 stage: run.builder.top_stage,
660 target: run.target,
661 });
662 }
663
664 /// Generate compiler documentation.
665 ///
666 /// This will generate all documentation for compiler and dependencies.
667 /// Compiler documentation is distributed separately, so we make sure
668 /// we do not merge it with the other documentation from std, test and
669 /// proc_macros. This is largely just a wrapper around `cargo doc`.
670 fn run(self, builder: &Builder) {
671 let build = builder.build;
672 let stage = self.stage;
673 let target = self.target;
674 println!("Documenting stage{} compiler ({})", stage, target);
675 let out = build.compiler_doc_out(target);
676 t!(fs::create_dir_all(&out));
677 let compiler = builder.compiler(stage, build.build);
678 let rustdoc = builder.rustdoc(compiler.host);
679 let compiler = if build.force_use_stage1(compiler, target) {
680 builder.compiler(1, compiler.host)
681 } else {
682 compiler
683 };
684
685 if !build.config.compiler_docs {
686 println!("\tskipping - compiler docs disabled");
687 return;
688 }
689
690 // Build libstd docs so that we generate relative links
691 builder.ensure(Std { stage, target });
692
693 builder.ensure(compile::Rustc { compiler, target });
694 let out_dir = build.stage_out(compiler, Mode::Librustc)
695 .join(target).join("doc");
696 // We do not symlink to the same shared folder that already contains std library
697 // documentation from previous steps as we do not want to include that.
698 build.clear_if_dirty(&out, &rustdoc);
699 t!(symlink_dir_force(&out, &out_dir));
700
701 let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc");
702 compile::rustc_cargo(build, &mut cargo);
703
704 // Only include compiler crates, no dependencies of those, such as `libc`.
705 cargo.arg("--no-deps");
706
707 // Find dependencies for top level crates.
708 let mut compiler_crates = HashSet::new();
709 for root_crate in &["rustc", "rustc_driver"] {
710 let interned_root_crate = INTERNER.intern_str(root_crate);
711 find_compiler_crates(&build, &interned_root_crate, &mut compiler_crates);
712 }
713
714 for krate in &compiler_crates {
715 cargo.arg("-p").arg(krate);
716 }
717
718 build.run(&mut cargo);
719 }
720}
721
722fn find_compiler_crates(
723 build: &Build,
724 name: &Interned<String>,
725 crates: &mut HashSet<Interned<String>>
726) {
727 // Add current crate.
728 crates.insert(*name);
729
730 // Look for dependencies.
731 for dep in build.crates.get(name).unwrap().deps.iter() {
732 if build.crates.get(dep).unwrap().is_local(build) {
733 find_compiler_crates(build, dep, crates);
734 }
735 }
736}
737
3b2f2976
XL
738#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
739pub struct ErrorIndex {
740 target: Interned<String>,
54a0048b
SL
741}
742
3b2f2976
XL
743impl Step for ErrorIndex {
744 type Output = ();
745 const DEFAULT: bool = true;
746 const ONLY_HOSTS: bool = true;
747
748 fn should_run(run: ShouldRun) -> ShouldRun {
749 let builder = run.builder;
750 run.path("src/tools/error_index_generator").default_condition(builder.build.config.docs)
751 }
752
753 fn make_run(run: RunConfig) {
754 run.builder.ensure(ErrorIndex {
755 target: run.target,
756 });
757 }
758
759 /// Generates the HTML rendered error-index by running the
760 /// `error_index_generator` tool.
761 fn run(self, builder: &Builder) {
762 let build = builder.build;
763 let target = self.target;
54a0048b 764
3b2f2976
XL
765 println!("Documenting error index ({})", target);
766 let out = build.doc_out(target);
767 t!(fs::create_dir_all(&out));
768 let mut index = builder.tool_cmd(Tool::ErrorIndex);
769 index.arg("html");
770 index.arg(out.join("error-index.html"));
771
772 // FIXME: shouldn't have to pass this env var
ff7c6d11
XL
773 index.env("CFG_BUILD", &build.build)
774 .env("RUSTC_ERROR_METADATA_DST", build.extended_error_dir());
3b2f2976
XL
775
776 build.run(&mut index);
777 }
778}
779
780#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
781pub struct UnstableBookGen {
782 target: Interned<String>,
54a0048b 783}
8bb4bdeb 784
3b2f2976
XL
785impl Step for UnstableBookGen {
786 type Output = ();
787 const DEFAULT: bool = true;
788 const ONLY_HOSTS: bool = true;
041b39d2 789
3b2f2976
XL
790 fn should_run(run: ShouldRun) -> ShouldRun {
791 let builder = run.builder;
792 run.path("src/tools/unstable-book-gen").default_condition(builder.build.config.docs)
793 }
794
795 fn make_run(run: RunConfig) {
796 run.builder.ensure(UnstableBookGen {
797 target: run.target,
798 });
799 }
800
801 fn run(self, builder: &Builder) {
802 let build = builder.build;
803 let target = self.target;
804
805 builder.ensure(compile::Std {
806 compiler: builder.compiler(builder.top_stage, build.build),
807 target,
808 });
809
810 println!("Generating unstable book md files ({})", target);
811 let out = build.md_doc_out(target).join("unstable-book");
812 t!(fs::create_dir_all(&out));
813 t!(fs::remove_dir_all(&out));
814 let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
815 cmd.arg(build.src.join("src"));
816 cmd.arg(out);
817
818 build.run(&mut cmd);
819 }
041b39d2
XL
820}
821
8bb4bdeb
XL
822fn symlink_dir_force(src: &Path, dst: &Path) -> io::Result<()> {
823 if let Ok(m) = fs::symlink_metadata(dst) {
824 if m.file_type().is_dir() {
825 try!(fs::remove_dir_all(dst));
826 } else {
827 // handle directory junctions on windows by falling back to
828 // `remove_dir`.
829 try!(fs::remove_file(dst).or_else(|_| {
830 fs::remove_dir(dst)
831 }));
832 }
833 }
834
835 symlink_dir(src, dst)
836}