1 //! Documentation generation for rustbuilder.
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
5 //! nomicon, rust by example, standalone documentation, etc.
7 //! Everything here is basically just a shim around calling either `rustbook` or
10 use std::collections::HashSet;
13 use std::path::{PathBuf, Path};
16 use build_helper::up_to_date;
18 use crate::util::symlink_dir;
19 use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
20 use crate::tool::{self, prepare_tool_cargo, Tool, SourceType};
22 use crate::cache::{INTERNER, Interned};
23 use crate::config::Config;
26 ($($name:ident, $path:expr, $book_name:expr, $book_ver:expr;)+) => {
28 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
30 target: Interned<String>,
35 const DEFAULT: bool = true;
37 fn should_run(run: ShouldRun) -> ShouldRun {
38 let builder = run.builder;
39 run.path($path).default_condition(builder.config.docs)
42 fn make_run(run: RunConfig) {
43 run.builder.ensure($name {
48 fn run(self, builder: &Builder) {
49 builder.ensure(Rustbook {
51 name: INTERNER.intern_str($book_name),
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`!
63 EditionGuide, "src/doc/edition-guide", "edition-guide", RustbookVersion::MdBook1;
64 EmbeddedBook, "src/doc/embedded-book", "embedded-book", RustbookVersion::MdBook2;
65 Nomicon, "src/doc/nomicon", "nomicon", RustbookVersion::MdBook1;
66 Reference, "src/doc/reference", "reference", RustbookVersion::MdBook1;
67 RustByExample, "src/doc/rust-by-example", "rust-by-example", RustbookVersion::MdBook1;
68 RustcBook, "src/doc/rustc", "rustc", RustbookVersion::MdBook1;
69 RustdocBook, "src/doc/rustdoc", "rustdoc", RustbookVersion::MdBook1;
72 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
73 enum RustbookVersion {
78 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
80 target: Interned<String>,
81 name: Interned<String>,
82 version: RustbookVersion,
85 impl Step for Rustbook {
88 // rustbook is never directly called, and only serves as a shim for the nomicon and the
90 fn should_run(run: ShouldRun) -> ShouldRun {
94 /// Invoke `rustbook` for `target` for the doc book `name`.
96 /// This will not actually generate any documentation if the documentation has
97 /// already been generated.
98 fn run(self, builder: &Builder) {
99 let src = builder.src.join("src/doc");
100 builder.ensure(RustbookSrc {
103 src: INTERNER.intern_path(src),
104 version: self.version,
109 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
110 pub struct UnstableBook {
111 target: Interned<String>,
114 impl Step for UnstableBook {
116 const DEFAULT: bool = true;
118 fn should_run(run: ShouldRun) -> ShouldRun {
119 let builder = run.builder;
120 run.path("src/doc/unstable-book").default_condition(builder.config.docs)
123 fn make_run(run: RunConfig) {
124 run.builder.ensure(UnstableBook {
129 fn run(self, builder: &Builder) {
130 builder.ensure(UnstableBookGen {
133 builder.ensure(RustbookSrc {
135 name: INTERNER.intern_str("unstable-book"),
136 src: builder.md_doc_out(self.target),
137 version: RustbookVersion::MdBook1,
142 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
143 pub struct CargoBook {
144 target: Interned<String>,
145 name: Interned<String>,
148 impl Step for CargoBook {
150 const DEFAULT: bool = true;
152 fn should_run(run: ShouldRun) -> ShouldRun {
153 let builder = run.builder;
154 run.path("src/tools/cargo/src/doc/book").default_condition(builder.config.docs)
157 fn make_run(run: RunConfig) {
158 run.builder.ensure(CargoBook {
160 name: INTERNER.intern_str("cargo"),
164 fn run(self, builder: &Builder) {
165 let target = self.target;
166 let name = self.name;
167 let src = builder.src.join("src/tools/cargo/src/doc");
169 let out = builder.doc_out(target);
170 t!(fs::create_dir_all(&out));
172 let out = out.join(name);
174 builder.info(&format!("Cargo Book ({}) - {}", target, name));
176 let _ = fs::remove_dir_all(&out);
178 builder.run(builder.tool_cmd(Tool::Rustbook)
186 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
188 target: Interned<String>,
189 name: Interned<String>,
190 src: Interned<PathBuf>,
191 version: RustbookVersion,
194 impl Step for RustbookSrc {
197 fn should_run(run: ShouldRun) -> ShouldRun {
201 /// Invoke `rustbook` for `target` for the doc book `name` from the `src` path.
203 /// This will not actually generate any documentation if the documentation has
204 /// already been generated.
205 fn run(self, builder: &Builder) {
206 let target = self.target;
207 let name = self.name;
209 let out = builder.doc_out(target);
210 t!(fs::create_dir_all(&out));
212 let out = out.join(name);
213 let src = src.join(name);
214 let index = out.join("index.html");
215 let rustbook = builder.tool_exe(Tool::Rustbook);
216 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
217 if up_to_date(&src, &index) && up_to_date(&rustbook, &index) {
220 builder.info(&format!("Rustbook ({}) - {}", target, name));
221 let _ = fs::remove_dir_all(&out);
223 let vers = match self.version {
224 RustbookVersion::MdBook1 => "1",
225 RustbookVersion::MdBook2 => "2",
228 builder.run(rustbook_cmd
238 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
241 target: Interned<String>,
245 impl Step for TheBook {
247 const DEFAULT: bool = true;
249 fn should_run(run: ShouldRun) -> ShouldRun {
250 let builder = run.builder;
251 run.path("src/doc/book").default_condition(builder.config.docs)
254 fn make_run(run: RunConfig) {
255 run.builder.ensure(TheBook {
256 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
262 /// Build the book and associated stuff.
264 /// We need to build:
266 /// * Book (first edition)
267 /// * Book (second edition)
268 /// * Version info and CSS
271 fn run(self, builder: &Builder) {
272 let compiler = self.compiler;
273 let target = self.target;
274 let name = self.name;
277 builder.ensure(Rustbook {
279 name: INTERNER.intern_string(name.to_string()),
280 version: RustbookVersion::MdBook1,
283 // building older edition redirects
285 let source_name = format!("{}/first-edition", name);
286 builder.ensure(Rustbook {
288 name: INTERNER.intern_string(source_name),
289 version: RustbookVersion::MdBook1,
292 let source_name = format!("{}/second-edition", name);
293 builder.ensure(Rustbook {
295 name: INTERNER.intern_string(source_name),
296 version: RustbookVersion::MdBook1,
299 let source_name = format!("{}/2018-edition", name);
300 builder.ensure(Rustbook {
302 name: INTERNER.intern_string(source_name),
303 version: RustbookVersion::MdBook1,
306 // build the version info page and CSS
307 builder.ensure(Standalone {
312 // build the redirect pages
313 builder.info(&format!("Documenting book redirect pages ({})", target));
314 for file in t!(fs::read_dir(builder.src.join("src/doc/book/redirects"))) {
316 let path = file.path();
317 let path = path.to_str().unwrap();
319 invoke_rustdoc(builder, compiler, target, path);
324 fn invoke_rustdoc(builder: &Builder, compiler: Compiler, target: Interned<String>, markdown: &str) {
325 let out = builder.doc_out(target);
327 let path = builder.src.join("src/doc").join(markdown);
329 let favicon = builder.src.join("src/doc/favicon.inc");
330 let footer = builder.src.join("src/doc/footer.inc");
331 let version_info = out.join("version_info.html");
333 let mut cmd = builder.rustdoc_cmd(compiler.host);
335 let out = out.join("book");
337 cmd.arg("--html-after-content").arg(&footer)
338 .arg("--html-before-content").arg(&version_info)
339 .arg("--html-in-header").arg(&favicon)
340 .arg("--markdown-no-toc")
341 .arg("--markdown-playground-url")
342 .arg("https://play.rust-lang.org/")
345 .arg("--markdown-css")
348 builder.run(&mut cmd);
351 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
352 pub struct Standalone {
354 target: Interned<String>,
357 impl Step for Standalone {
359 const DEFAULT: bool = true;
361 fn should_run(run: ShouldRun) -> ShouldRun {
362 let builder = run.builder;
363 run.path("src/doc").default_condition(builder.config.docs)
366 fn make_run(run: RunConfig) {
367 run.builder.ensure(Standalone {
368 compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
373 /// Generates all standalone documentation as compiled by the rustdoc in `stage`
374 /// for the `target` into `out`.
376 /// This will list all of `src/doc` looking for markdown files and appropriately
377 /// perform transformations like substituting `VERSION`, `SHORT_HASH`, and
378 /// `STAMP` along with providing the various header/footer HTML we've customized.
380 /// In the end, this is just a glorified wrapper around rustdoc!
381 fn run(self, builder: &Builder) {
382 let target = self.target;
383 let compiler = self.compiler;
384 builder.info(&format!("Documenting standalone ({})", target));
385 let out = builder.doc_out(target);
386 t!(fs::create_dir_all(&out));
388 let favicon = builder.src.join("src/doc/favicon.inc");
389 let footer = builder.src.join("src/doc/footer.inc");
390 let full_toc = builder.src.join("src/doc/full-toc.inc");
391 t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
393 let version_input = builder.src.join("src/doc/version_info.html.template");
394 let version_info = out.join("version_info.html");
396 if !builder.config.dry_run && !up_to_date(&version_input, &version_info) {
397 let info = t!(fs::read_to_string(&version_input))
398 .replace("VERSION", &builder.rust_release())
399 .replace("SHORT_HASH", builder.rust_info.sha_short().unwrap_or(""))
400 .replace("STAMP", builder.rust_info.sha().unwrap_or(""));
401 t!(fs::write(&version_info, &info));
404 for file in t!(fs::read_dir(builder.src.join("src/doc"))) {
406 let path = file.path();
407 let filename = path.file_name().unwrap().to_str().unwrap();
408 if !filename.ends_with(".md") || filename == "README.md" {
412 let html = out.join(filename).with_extension("html");
413 let rustdoc = builder.rustdoc(compiler.host);
414 if up_to_date(&path, &html) &&
415 up_to_date(&footer, &html) &&
416 up_to_date(&favicon, &html) &&
417 up_to_date(&full_toc, &html) &&
418 up_to_date(&version_info, &html) &&
419 (builder.config.dry_run || up_to_date(&rustdoc, &html)) {
423 let mut cmd = builder.rustdoc_cmd(compiler.host);
424 cmd.arg("--html-after-content").arg(&footer)
425 .arg("--html-before-content").arg(&version_info)
426 .arg("--html-in-header").arg(&favicon)
427 .arg("--markdown-no-toc")
428 .arg("--index-page").arg(&builder.src.join("src/doc/index.md"))
429 .arg("--markdown-playground-url")
430 .arg("https://play.rust-lang.org/")
434 if filename == "not_found.md" {
435 cmd.arg("--markdown-css")
436 .arg("https://doc.rust-lang.org/rust.css");
438 cmd.arg("--markdown-css").arg("rust.css");
440 builder.run(&mut cmd);
445 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
448 pub target: Interned<String>,
453 const DEFAULT: bool = true;
455 fn should_run(run: ShouldRun) -> ShouldRun {
456 let builder = run.builder;
457 run.all_krates("std").default_condition(builder.config.docs)
460 fn make_run(run: RunConfig) {
461 run.builder.ensure(Std {
462 stage: run.builder.top_stage,
467 /// Compile all standard library documentation.
469 /// This will generate all documentation for the standard library and its
470 /// dependencies. This is largely just a wrapper around `cargo doc`.
471 fn run(self, builder: &Builder) {
472 let stage = self.stage;
473 let target = self.target;
474 builder.info(&format!("Documenting stage{} std ({})", stage, target));
475 let out = builder.doc_out(target);
476 t!(fs::create_dir_all(&out));
477 let compiler = builder.compiler(stage, builder.config.build);
478 let compiler = if builder.force_use_stage1(compiler, target) {
479 builder.compiler(1, compiler.host)
484 builder.ensure(compile::Std { compiler, target });
485 let out_dir = builder.stage_out(compiler, Mode::Std)
486 .join(target).join("doc");
488 // Here what we're doing is creating a *symlink* (directory junction on
489 // Windows) to the final output location. This is not done as an
490 // optimization but rather for correctness. We've got three trees of
491 // documentation, one for std, one for test, and one for rustc. It's then
492 // our job to merge them all together.
494 // Unfortunately rustbuild doesn't know nearly as well how to merge doc
495 // trees as rustdoc does itself, so instead of actually having three
496 // separate trees we just have rustdoc output to the same location across
499 // This way rustdoc generates output directly into the output, and rustdoc
500 // will also directly handle merging.
501 let my_out = builder.crate_doc_out(target);
502 t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
503 t!(fs::copy(builder.src.join("src/doc/rust.css"), out.join("rust.css")));
505 let run_cargo_rustdoc_for = |package: &str| {
506 let mut cargo = builder.cargo(compiler, Mode::Std, target, "rustdoc");
507 compile::std_cargo(builder, &compiler, target, &mut cargo);
509 // Keep a whitelist so we do not build internal stdlib crates, these will be
510 // build by the rustc step later if enabled.
511 cargo.arg("-Z").arg("unstable-options")
512 .arg("-p").arg(package);
513 // Create all crate output directories first to make sure rustdoc uses
515 // FIXME: Cargo should probably do this itself.
516 t!(fs::create_dir_all(out_dir.join(package)));
518 .arg("--markdown-css").arg("rust.css")
519 .arg("--markdown-no-toc")
520 .arg("--index-page").arg(&builder.src.join("src/doc/index.md"));
522 builder.run(&mut cargo);
523 builder.cp_r(&my_out, &out);
525 for krate in &["alloc", "core", "std"] {
526 run_cargo_rustdoc_for(krate);
531 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
534 target: Interned<String>,
539 const DEFAULT: bool = true;
541 fn should_run(run: ShouldRun) -> ShouldRun {
542 let builder = run.builder;
543 run.krate("test").default_condition(builder.config.docs)
546 fn make_run(run: RunConfig) {
547 run.builder.ensure(Test {
548 stage: run.builder.top_stage,
553 /// Compile all libtest documentation.
555 /// This will generate all documentation for libtest and its dependencies. This
556 /// is largely just a wrapper around `cargo doc`.
557 fn run(self, builder: &Builder) {
558 let stage = self.stage;
559 let target = self.target;
560 builder.info(&format!("Documenting stage{} test ({})", stage, target));
561 let out = builder.doc_out(target);
562 t!(fs::create_dir_all(&out));
563 let compiler = builder.compiler(stage, builder.config.build);
564 let compiler = if builder.force_use_stage1(compiler, target) {
565 builder.compiler(1, compiler.host)
570 // Build libstd docs so that we generate relative links
571 builder.ensure(Std { stage, target });
573 builder.ensure(compile::Test { compiler, target });
574 let out_dir = builder.stage_out(compiler, Mode::Test)
575 .join(target).join("doc");
577 // See docs in std above for why we symlink
578 let my_out = builder.crate_doc_out(target);
579 t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
581 let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc");
582 compile::test_cargo(builder, &compiler, target, &mut cargo);
584 cargo.arg("--no-deps").arg("-p").arg("test");
586 builder.run(&mut cargo);
587 builder.cp_r(&my_out, &out);
591 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
592 pub struct WhitelistedRustc {
594 target: Interned<String>,
597 impl Step for WhitelistedRustc {
599 const DEFAULT: bool = true;
600 const ONLY_HOSTS: bool = true;
602 fn should_run(run: ShouldRun) -> ShouldRun {
603 let builder = run.builder;
604 run.krate("rustc-main").default_condition(builder.config.docs)
607 fn make_run(run: RunConfig) {
608 run.builder.ensure(WhitelistedRustc {
609 stage: run.builder.top_stage,
614 /// Generate whitelisted compiler crate documentation.
616 /// This will generate all documentation for crates that are whitelisted
617 /// to be included in the standard documentation. This documentation is
618 /// included in the standard Rust documentation, so we should always
619 /// document it and symlink to merge with the rest of the std and test
620 /// documentation. We don't build other compiler documentation
621 /// here as we want to be able to keep it separate from the standard
622 /// documentation. This is largely just a wrapper around `cargo doc`.
623 fn run(self, builder: &Builder) {
624 let stage = self.stage;
625 let target = self.target;
626 builder.info(&format!("Documenting stage{} whitelisted compiler ({})", stage, target));
627 let out = builder.doc_out(target);
628 t!(fs::create_dir_all(&out));
629 let compiler = builder.compiler(stage, builder.config.build);
630 let compiler = if builder.force_use_stage1(compiler, target) {
631 builder.compiler(1, compiler.host)
636 // Build libstd docs so that we generate relative links
637 builder.ensure(Std { stage, target });
639 builder.ensure(compile::Rustc { compiler, target });
640 let out_dir = builder.stage_out(compiler, Mode::Rustc)
641 .join(target).join("doc");
643 // See docs in std above for why we symlink
644 let my_out = builder.crate_doc_out(target);
645 t!(symlink_dir_force(&builder.config, &my_out, &out_dir));
647 let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
648 compile::rustc_cargo(builder, &mut cargo);
650 // We don't want to build docs for internal compiler dependencies in this
651 // step (there is another step for that). Therefore, we whitelist the crates
652 // for which docs must be built.
653 cargo.arg("--no-deps");
654 for krate in &["proc_macro"] {
655 cargo.arg("-p").arg(krate);
658 builder.run(&mut cargo);
659 builder.cp_r(&my_out, &out);
663 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
666 target: Interned<String>,
669 impl Step for Rustc {
671 const DEFAULT: bool = true;
672 const ONLY_HOSTS: bool = true;
674 fn should_run(run: ShouldRun) -> ShouldRun {
675 let builder = run.builder;
676 run.krate("rustc-main").default_condition(builder.config.docs)
679 fn make_run(run: RunConfig) {
680 run.builder.ensure(Rustc {
681 stage: run.builder.top_stage,
686 /// Generate compiler documentation.
688 /// This will generate all documentation for compiler and dependencies.
689 /// Compiler documentation is distributed separately, so we make sure
690 /// we do not merge it with the other documentation from std, test and
691 /// proc_macros. This is largely just a wrapper around `cargo doc`.
692 fn run(self, builder: &Builder) {
693 let stage = self.stage;
694 let target = self.target;
695 builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
697 // This is the intended out directory for compiler documentation.
698 let out = builder.compiler_doc_out(target);
699 t!(fs::create_dir_all(&out));
701 // Get the correct compiler for this stage.
702 let compiler = builder.compiler(stage, builder.config.build);
703 let compiler = if builder.force_use_stage1(compiler, target) {
704 builder.compiler(1, compiler.host)
709 if !builder.config.compiler_docs {
710 builder.info("\tskipping - compiler/librustdoc docs disabled");
715 builder.ensure(compile::Rustc { compiler, target });
717 // We do not symlink to the same shared folder that already contains std library
718 // documentation from previous steps as we do not want to include that.
719 let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc");
720 t!(symlink_dir_force(&builder.config, &out, &out_dir));
722 // Build cargo command.
723 let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc");
724 cargo.env("RUSTDOCFLAGS", "--document-private-items");
725 compile::rustc_cargo(builder, &mut cargo);
727 // Only include compiler crates, no dependencies of those, such as `libc`.
728 cargo.arg("--no-deps");
730 // Find dependencies for top level crates.
731 let mut compiler_crates = HashSet::new();
732 for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
733 let interned_root_crate = INTERNER.intern_str(root_crate);
734 find_compiler_crates(builder, &interned_root_crate, &mut compiler_crates);
737 for krate in &compiler_crates {
738 // Create all crate output directories first to make sure rustdoc uses
740 // FIXME: Cargo should probably do this itself.
741 t!(fs::create_dir_all(out_dir.join(krate)));
742 cargo.arg("-p").arg(krate);
745 builder.run(&mut cargo);
749 fn find_compiler_crates(
751 name: &Interned<String>,
752 crates: &mut HashSet<Interned<String>>
754 // Add current crate.
755 crates.insert(*name);
757 // Look for dependencies.
758 for dep in builder.crates.get(name).unwrap().deps.iter() {
759 if builder.crates.get(dep).unwrap().is_local(builder) {
760 find_compiler_crates(builder, dep, crates);
765 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
768 target: Interned<String>,
771 impl Step for Rustdoc {
773 const DEFAULT: bool = true;
774 const ONLY_HOSTS: bool = true;
776 fn should_run(run: ShouldRun) -> ShouldRun {
777 run.krate("rustdoc-tool")
780 fn make_run(run: RunConfig) {
781 run.builder.ensure(Rustdoc {
782 stage: run.builder.top_stage,
787 /// Generate compiler documentation.
789 /// This will generate all documentation for compiler and dependencies.
790 /// Compiler documentation is distributed separately, so we make sure
791 /// we do not merge it with the other documentation from std, test and
792 /// proc_macros. This is largely just a wrapper around `cargo doc`.
793 fn run(self, builder: &Builder) {
794 let stage = self.stage;
795 let target = self.target;
796 builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target));
798 // This is the intended out directory for compiler documentation.
799 let out = builder.compiler_doc_out(target);
800 t!(fs::create_dir_all(&out));
802 // Get the correct compiler for this stage.
803 let compiler = builder.compiler(stage, builder.config.build);
804 let compiler = if builder.force_use_stage1(compiler, target) {
805 builder.compiler(1, compiler.host)
810 if !builder.config.compiler_docs {
811 builder.info("\tskipping - compiler/librustdoc docs disabled");
815 // Build rustc docs so that we generate relative links.
816 builder.ensure(Rustc { stage, target });
819 builder.ensure(tool::Rustdoc { host: compiler.host });
821 // Symlink compiler docs to the output directory of rustdoc documentation.
822 let out_dir = builder.stage_out(compiler, Mode::ToolRustc)
825 t!(fs::create_dir_all(&out_dir));
826 t!(symlink_dir_force(&builder.config, &out, &out_dir));
828 // Build cargo command.
829 let mut cargo = prepare_tool_cargo(
840 // Only include compiler crates, no dependencies of those, such as `libc`.
841 cargo.arg("--no-deps");
842 cargo.arg("-p").arg("rustdoc");
844 cargo.env("RUSTDOCFLAGS", "--document-private-items");
845 builder.run(&mut cargo);
849 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
850 pub struct ErrorIndex {
851 target: Interned<String>,
854 impl Step for ErrorIndex {
856 const DEFAULT: bool = true;
857 const ONLY_HOSTS: bool = true;
859 fn should_run(run: ShouldRun) -> ShouldRun {
860 let builder = run.builder;
861 run.path("src/tools/error_index_generator").default_condition(builder.config.docs)
864 fn make_run(run: RunConfig) {
865 run.builder.ensure(ErrorIndex {
870 /// Generates the HTML rendered error-index by running the
871 /// `error_index_generator` tool.
872 fn run(self, builder: &Builder) {
873 let target = self.target;
875 builder.info(&format!("Documenting error index ({})", target));
876 let out = builder.doc_out(target);
877 t!(fs::create_dir_all(&out));
878 let mut index = builder.tool_cmd(Tool::ErrorIndex);
880 index.arg(out.join("error-index.html"));
882 // FIXME: shouldn't have to pass this env var
883 index.env("CFG_BUILD", &builder.config.build)
884 .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir());
886 builder.run(&mut index);
890 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
891 pub struct UnstableBookGen {
892 target: Interned<String>,
895 impl Step for UnstableBookGen {
897 const DEFAULT: bool = true;
898 const ONLY_HOSTS: bool = true;
900 fn should_run(run: ShouldRun) -> ShouldRun {
901 let builder = run.builder;
902 run.path("src/tools/unstable-book-gen").default_condition(builder.config.docs)
905 fn make_run(run: RunConfig) {
906 run.builder.ensure(UnstableBookGen {
911 fn run(self, builder: &Builder) {
912 let target = self.target;
914 builder.ensure(compile::Std {
915 compiler: builder.compiler(builder.top_stage, builder.config.build),
919 builder.info(&format!("Generating unstable book md files ({})", target));
920 let out = builder.md_doc_out(target).join("unstable-book");
921 builder.create_dir(&out);
922 builder.remove_dir(&out);
923 let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
924 cmd.arg(builder.src.join("src"));
927 builder.run(&mut cmd);
931 fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> {
935 if let Ok(m) = fs::symlink_metadata(dst) {
936 if m.file_type().is_dir() {
937 fs::remove_dir_all(dst)?;
939 // handle directory junctions on windows by falling back to
941 fs::remove_file(dst).or_else(|_| {
947 symlink_dir(config, src, dst)