1use std::collections::HashSet;
11use std::io::{self, Write};
12use std::path::{Path, PathBuf};
13use std::{env, fs, mem};
14
15use crate::core::build_steps::compile;
16use crate::core::build_steps::compile::{CargoMessage, stream_cargo};
17use crate::core::build_steps::tool::{
18 self, RustcPrivateCompilers, SourceType, Tool, prepare_tool_cargo,
19};
20use crate::core::builder::{
21 self, Builder, CommandLineStep, Kind, RunConfig, ShouldRun, Step, StepMetadata,
22 crate_description,
23};
24use crate::core::compiler::Compiler;
25use crate::core::config::TargetSelection;
26use crate::core::session::{FileType, Mode};
27use crate::utils::helpers::{exit_process, submodule_path_of, symlink_dir, t, up_to_date};
28
29macro_rules! book {
30 ($($name:ident, $path:expr, $book_name:expr, $lang:expr ;)+) => {
31 $(
32 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
33 pub struct $name {
34 target: TargetSelection,
35 }
36
37 impl CommandLineStep for $name {
38 type Output = ();
39
40 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
41 run.path($path)
42 }
43
44 fn is_default_step(builder: &Builder<'_>) -> bool {
45 builder.config.docs
46 }
47
48 fn make_run(run: RunConfig<'_>) {
49 run.builder.ensure($name {
50 target: run.target,
51 });
52 }
53
54 fn run(self, builder: &Builder<'_>) {
55 if let Some(submodule_path) = submodule_path_of(&builder, $path) {
56 builder.require_submodule(&submodule_path, None)
57 }
58
59 builder.ensure(RustbookSrc {
60 target: self.target,
61 name: $book_name.to_owned(),
62 src: builder.src.join($path),
63 parent: Some(self),
64 languages: $lang.into(),
65 build_compiler: None,
66 })
67 }
68 }
69 )+
70 }
71}
72
73book!(
77 CargoBook, "src/tools/cargo/doc/book", "cargo", &[];
78 ClippyBook, "src/tools/clippy/book", "clippy", &[];
79 EditionGuide, "src/doc/edition-guide", "edition-guide", &[];
80 EmbeddedBook, "src/doc/embedded-book", "embedded-book", &[];
81 Nomicon, "src/doc/nomicon", "nomicon", &[];
82 RustByExample, "src/doc/rust-by-example", "rust-by-example", &["es", "ja", "zh", "ko"];
83 RustdocBook, "src/doc/rustdoc", "rustdoc", &[];
84 StyleGuide, "src/doc/style-guide", "style-guide", &[];
85);
86
87#[derive(Debug, Clone, Hash, PartialEq, Eq)]
88pub struct UnstableBook {
89 build_compiler: Compiler,
90 target: TargetSelection,
91}
92
93impl CommandLineStep for UnstableBook {
94 type Output = ();
95
96 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
97 run.path("src/doc/unstable-book")
98 }
99
100 fn is_default_step(builder: &Builder<'_>) -> bool {
101 builder.config.docs
102 }
103
104 fn make_run(run: RunConfig<'_>) {
105 let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
109 run.builder.top_stage
110 } else {
111 2
112 };
113
114 run.builder.ensure(UnstableBook {
115 build_compiler: prepare_doc_compiler(run.builder, run.target, stage),
116 target: run.target,
117 });
118 }
119
120 fn run(self, builder: &Builder<'_>) {
121 let unstable_book_md_dir = builder
122 .ensure(UnstableBookGen { build_compiler: self.build_compiler, target: self.target });
123 builder.ensure(RustbookSrc {
124 target: self.target,
125 name: "unstable-book".to_owned(),
126 src: unstable_book_md_dir,
127 parent: Some(self),
128 languages: vec![],
129 build_compiler: None,
130 })
131 }
132}
133
134#[derive(Debug, Clone, Hash, PartialEq, Eq)]
135struct RustbookSrc<P: CommandLineStep> {
136 target: TargetSelection,
137 name: String,
138 src: PathBuf,
139 parent: Option<P>,
140 languages: Vec<&'static str>,
141 build_compiler: Option<Compiler>,
143}
144
145impl<P: CommandLineStep> Step for RustbookSrc<P> {
146 type Output = ();
147
148 fn run(self, builder: &Builder<'_>) {
153 let target = self.target;
154 let name = self.name;
155 let src = self.src;
156 let out = builder.doc_out(target);
157 t!(fs::create_dir_all(&out));
158
159 let out = out.join(&name);
160 let index = out.join("index.html");
161 let rustbook = builder.tool_exe(Tool::Rustbook);
162
163 if !builder.config.dry_run()
164 && (!up_to_date(&src, &index) || !up_to_date(&rustbook, &index))
165 {
166 builder.info(&format!("Rustbook ({target}) - {name}"));
167 let _ = fs::remove_dir_all(&out);
168
169 let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
170
171 if let Some(compiler) = self.build_compiler {
172 let mut rustdoc = builder.rustdoc_for_compiler(compiler);
173 rustdoc.pop();
174 let old_path = env::var_os("PATH").unwrap_or_default();
175 let new_path =
176 env::join_paths(std::iter::once(rustdoc).chain(env::split_paths(&old_path)))
177 .expect("could not add rustdoc to PATH");
178
179 rustbook_cmd.env("PATH", new_path);
180 builder.add_rustc_lib_path(compiler, &mut rustbook_cmd);
181 }
182
183 rustbook_cmd
184 .arg("build")
185 .arg(&src)
186 .arg("-d")
187 .arg(&out)
188 .arg("--rust-root")
189 .arg(&builder.src)
190 .run(builder);
191
192 for lang in &self.languages {
193 let out = out.join(lang);
194
195 builder.info(&format!("Rustbook ({target}) - {name} - {lang}"));
196 let _ = fs::remove_dir_all(&out);
197
198 builder
199 .tool_cmd(Tool::Rustbook)
200 .arg("build")
201 .arg(&src)
202 .arg("-d")
203 .arg(&out)
204 .arg("-l")
205 .arg(lang)
206 .run(builder);
207 }
208 }
209
210 if self.parent.is_some() {
211 builder.maybe_open_in_browser::<P>(index)
212 }
213 }
214
215 fn metadata(&self) -> Option<StepMetadata> {
216 let mut metadata = StepMetadata::doc(&format!("{} (book)", self.name), self.target);
217 if let Some(compiler) = self.build_compiler {
218 metadata = metadata.built_by(compiler);
219 }
220
221 Some(metadata)
222 }
223}
224
225#[derive(Debug, Clone, Hash, PartialEq, Eq)]
226pub struct TheBook {
227 build_compiler: Compiler,
229 target: TargetSelection,
230}
231
232impl CommandLineStep for TheBook {
233 type Output = ();
234
235 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
236 run.path("src/doc/book")
237 }
238
239 fn is_default_step(builder: &Builder<'_>) -> bool {
240 builder.config.docs
241 }
242
243 fn make_run(run: RunConfig<'_>) {
244 run.builder.ensure(TheBook {
245 build_compiler: prepare_doc_compiler(run.builder, run.target, run.builder.top_stage),
246 target: run.target,
247 });
248 }
249
250 fn run(self, builder: &Builder<'_>) {
260 builder.require_submodule("src/doc/book", None);
261
262 let build_compiler = self.build_compiler;
263 let target = self.target;
264
265 let absolute_path = builder.src.join("src/doc/book");
266 let redirect_path = absolute_path.join("redirects");
267
268 builder.ensure(RustbookSrc {
270 target,
271 name: "book".to_owned(),
272 src: absolute_path.clone(),
273 parent: Some(self),
274 languages: vec![],
275 build_compiler: None,
276 });
277
278 for edition in &["first-edition", "second-edition", "2018-edition"] {
280 builder.ensure(RustbookSrc {
281 target,
282 name: format!("book/{edition}"),
283 src: absolute_path.join(edition),
284 parent: Option::<Self>::None,
287 languages: vec![],
288 build_compiler: None,
289 });
290 }
291
292 let shared_assets = builder.ensure(SharedAssets { target });
294
295 let _guard = builder.msg(Kind::Doc, "book redirect pages", None, build_compiler, target);
297 if builder.config.dry_run() {
298 return;
299 }
300
301 for file in t!(fs::read_dir(redirect_path)) {
302 let file = t!(file);
303 let path = file.path();
304 let path = path.to_str().unwrap();
305
306 invoke_rustdoc(builder, build_compiler, &shared_assets, target, path);
307 }
308 }
309}
310
311fn invoke_rustdoc(
312 builder: &Builder<'_>,
313 build_compiler: Compiler,
314 shared_assets: &SharedAssetsPaths,
315 target: TargetSelection,
316 markdown: &str,
317) {
318 let out = builder.doc_out(target);
319
320 let path = builder.src.join("src/doc").join(markdown);
321
322 let header = builder.src.join("src/doc/redirect.inc");
323 let footer = builder.src.join("src/doc/footer.inc");
324
325 let mut cmd = builder.rustdoc_cmd(build_compiler);
326
327 let out = out.join("book");
328
329 cmd.arg("--html-after-content")
330 .arg(&footer)
331 .arg("--html-before-content")
332 .arg(&shared_assets.version_info)
333 .arg("--html-in-header")
334 .arg(&header)
335 .arg("--markdown-no-toc")
336 .arg("--markdown-playground-url")
337 .arg("https://play.rust-lang.org/")
338 .arg("-o")
339 .arg(&out)
340 .arg(&path)
341 .arg("--markdown-css")
342 .arg("../rust.css")
343 .arg("-Zunstable-options");
344
345 if !builder.config.docs_minification {
346 cmd.arg("--disable-minification");
347 }
348
349 cmd.run(builder);
350}
351
352#[derive(Debug, Clone, Hash, PartialEq, Eq)]
353pub struct Standalone {
354 build_compiler: Compiler,
355 target: TargetSelection,
356}
357
358impl CommandLineStep for Standalone {
359 type Output = ();
360
361 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
362 run.path("src/doc").alias("standalone")
363 }
364
365 fn is_default_step(builder: &Builder<'_>) -> bool {
366 builder.config.docs
367 }
368
369 fn make_run(run: RunConfig<'_>) {
370 run.builder.ensure(Standalone {
371 build_compiler: prepare_doc_compiler(
372 run.builder,
373 run.builder.host_target,
374 run.builder.top_stage,
375 ),
376 target: run.target,
377 });
378 }
379
380 fn run(self, builder: &Builder<'_>) {
389 let target = self.target;
390 let build_compiler = self.build_compiler;
391 let _guard = builder.msg(Kind::Doc, "standalone", None, build_compiler, target);
392 let out = builder.doc_out(target);
393 t!(fs::create_dir_all(&out));
394
395 let version_info = builder.ensure(SharedAssets { target: self.target }).version_info;
396
397 let favicon = builder.src.join("src/doc/favicon.inc");
398 let footer = builder.src.join("src/doc/footer.inc");
399 let full_toc = builder.src.join("src/doc/full-toc.inc");
400
401 for file in t!(fs::read_dir(builder.src.join("src/doc"))) {
402 let file = t!(file);
403 let path = file.path();
404 let filename = path.file_name().unwrap().to_str().unwrap();
405 if !filename.ends_with(".md") || filename == "README.md" {
406 continue;
407 }
408
409 let html = out.join(filename).with_extension("html");
410 let rustdoc = builder.rustdoc_for_compiler(build_compiler);
411 if up_to_date(&path, &html)
412 && up_to_date(&footer, &html)
413 && up_to_date(&favicon, &html)
414 && up_to_date(&full_toc, &html)
415 && (builder.config.dry_run() || up_to_date(&version_info, &html))
416 && (builder.config.dry_run() || up_to_date(&rustdoc, &html))
417 {
418 continue;
419 }
420
421 let mut cmd = builder.rustdoc_cmd(build_compiler);
422
423 cmd.arg("--html-after-content")
424 .arg(&footer)
425 .arg("--html-before-content")
426 .arg(&version_info)
427 .arg("--html-in-header")
428 .arg(&favicon)
429 .arg("--markdown-no-toc")
430 .arg("-Zunstable-options")
431 .arg("--index-page")
432 .arg(builder.src.join("src/doc/index.md"))
433 .arg("--markdown-playground-url")
434 .arg("https://play.rust-lang.org/")
435 .arg("-o")
436 .arg(&out)
437 .arg(&path);
438
439 if !builder.config.docs_minification {
440 cmd.arg("--disable-minification");
441 }
442
443 if filename == "not_found.md" {
444 cmd.arg("--markdown-css").arg("https://doc.rust-lang.org/rust.css");
445 } else {
446 cmd.arg("--markdown-css").arg("rust.css");
447 }
448 cmd.run(builder);
449 }
450
451 if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>(Kind::Doc) {
454 let index = out.join("index.html");
455 builder.open_in_browser(index);
456 }
457 }
458
459 fn metadata(&self) -> Option<StepMetadata> {
460 Some(StepMetadata::doc("standalone", self.target).built_by(self.build_compiler))
461 }
462}
463
464#[derive(Debug, Clone, Hash, PartialEq, Eq)]
465pub struct Releases {
466 build_compiler: Compiler,
467 target: TargetSelection,
468}
469
470impl CommandLineStep for Releases {
471 type Output = ();
472
473 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
474 run.path("RELEASES.md").alias("releases")
475 }
476
477 fn is_default_step(builder: &Builder<'_>) -> bool {
478 builder.config.docs
479 }
480
481 fn make_run(run: RunConfig<'_>) {
482 run.builder.ensure(Releases {
483 build_compiler: prepare_doc_compiler(
484 run.builder,
485 run.builder.host_target,
486 run.builder.top_stage,
487 ),
488 target: run.target,
489 });
490 }
491
492 fn run(self, builder: &Builder<'_>) {
498 let target = self.target;
499 let build_compiler = self.build_compiler;
500 let _guard = builder.msg(Kind::Doc, "releases", None, build_compiler, target);
501 let out = builder.doc_out(target);
502 t!(fs::create_dir_all(&out));
503
504 builder.ensure(Standalone { build_compiler, target });
505
506 let version_info = builder.ensure(SharedAssets { target: self.target }).version_info;
507
508 let favicon = builder.src.join("src/doc/favicon.inc");
509 let footer = builder.src.join("src/doc/footer.inc");
510 let full_toc = builder.src.join("src/doc/full-toc.inc");
511
512 let html = out.join("releases.html");
513 let tmppath = out.join("releases.md");
514 let inpath = builder.src.join("RELEASES.md");
515 let rustdoc = builder.rustdoc_for_compiler(build_compiler);
516 if !up_to_date(&inpath, &html)
517 || !up_to_date(&footer, &html)
518 || !up_to_date(&favicon, &html)
519 || !up_to_date(&full_toc, &html)
520 || !(builder.config.dry_run()
521 || up_to_date(&version_info, &html)
522 || up_to_date(&rustdoc, &html))
523 {
524 let mut tmpfile = t!(fs::File::create(&tmppath));
525 t!(tmpfile.write_all(b"% Rust Release Notes\n\n"));
526 t!(io::copy(&mut t!(fs::File::open(&inpath)), &mut tmpfile));
527 mem::drop(tmpfile);
528 let mut cmd = builder.rustdoc_cmd(build_compiler);
529
530 cmd.arg("--html-after-content")
531 .arg(&footer)
532 .arg("--html-before-content")
533 .arg(&version_info)
534 .arg("--html-in-header")
535 .arg(&favicon)
536 .arg("--markdown-no-toc")
537 .arg("--markdown-css")
538 .arg("rust.css")
539 .arg("-Zunstable-options")
540 .arg("--index-page")
541 .arg(builder.src.join("src/doc/index.md"))
542 .arg("--markdown-playground-url")
543 .arg("https://play.rust-lang.org/")
544 .arg("-o")
545 .arg(&out)
546 .arg(&tmppath);
547
548 if !builder.config.docs_minification {
549 cmd.arg("--disable-minification");
550 }
551
552 cmd.run(builder);
553 }
554
555 if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
558 builder.open_in_browser(&html);
559 }
560 }
561
562 fn metadata(&self) -> Option<StepMetadata> {
563 Some(StepMetadata::doc("releases", self.target).built_by(self.build_compiler))
564 }
565}
566
567#[derive(Debug, Clone)]
568pub struct SharedAssetsPaths {
569 pub version_info: PathBuf,
570}
571
572#[derive(Debug, Clone, Hash, PartialEq, Eq)]
573pub struct SharedAssets {
574 target: TargetSelection,
575}
576
577impl Step for SharedAssets {
578 type Output = SharedAssetsPaths;
579
580 fn run(self, builder: &Builder<'_>) -> Self::Output {
582 let out = builder.doc_out(self.target);
583
584 let version_input = builder.src.join("src").join("doc").join("version_info.html.template");
585 let version_info = out.join("version_info.html");
586 if !builder.config.dry_run() && !up_to_date(&version_input, &version_info) {
587 let info = t!(fs::read_to_string(&version_input))
588 .replace("VERSION", &builder.rust_release())
589 .replace("SHORT_HASH", builder.rust_info().sha_short().unwrap_or(""))
590 .replace("STAMP", builder.rust_info().sha().unwrap_or(""));
591 t!(fs::write(&version_info, info));
592 }
593
594 builder.copy_link(
595 &builder.src.join("src").join("doc").join("rust.css"),
596 &out.join("rust.css"),
597 FileType::Regular,
598 );
599
600 builder.copy_link(
601 &builder
602 .src
603 .join("src")
604 .join("librustdoc")
605 .join("html")
606 .join("static")
607 .join("images")
608 .join("favicon.svg"),
609 &out.join("favicon.svg"),
610 FileType::Regular,
611 );
612 builder.copy_link(
613 &builder
614 .src
615 .join("src")
616 .join("librustdoc")
617 .join("html")
618 .join("static")
619 .join("images")
620 .join("favicon-32x32.png"),
621 &out.join("favicon-32x32.png"),
622 FileType::Regular,
623 );
624
625 SharedAssetsPaths { version_info }
626 }
627}
628
629#[derive(Debug, Clone, Hash, PartialEq, Eq)]
631pub struct Std {
632 build_compiler: Compiler,
633 target: TargetSelection,
634 format: DocumentationFormat,
635 crates: Vec<String>,
636}
637
638impl Std {
639 pub(crate) fn from_build_compiler(
640 build_compiler: Compiler,
641 target: TargetSelection,
642 format: DocumentationFormat,
643 ) -> Self {
644 Std { build_compiler, target, format, crates: vec![] }
645 }
646}
647
648impl CommandLineStep for Std {
649 type Output = PathBuf;
651
652 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
653 run.crate_or_deps("sysroot").path("library")
654 }
655
656 fn is_default_step(builder: &Builder<'_>) -> bool {
657 builder.config.docs
658 }
659
660 fn make_run(run: RunConfig<'_>) {
661 let crates = compile::std_crates_for_make_run(&run);
662 let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false);
663 if crates.is_empty() && target_is_no_std {
664 return;
665 }
666 run.builder.ensure(Std {
667 build_compiler: run.builder.compiler_for_std(run.builder.top_stage),
668 target: run.target,
669 format: if run.builder.config.cmd.json() {
670 DocumentationFormat::Json
671 } else {
672 DocumentationFormat::Html
673 },
674 crates,
675 });
676 }
677
678 fn run(self, builder: &Builder<'_>) -> Self::Output {
683 let target = self.target;
684 let crates = if self.crates.is_empty() {
685 builder
686 .in_tree_crates("sysroot", Some(target))
687 .iter()
688 .map(|c| c.name.to_string())
689 .collect()
690 } else {
691 self.crates
692 };
693
694 let out = match self.format {
695 DocumentationFormat::Html => builder.doc_out(target),
696 DocumentationFormat::Json => builder.json_doc_out(target),
697 };
698
699 t!(fs::create_dir_all(&out));
700
701 if self.format == DocumentationFormat::Html {
702 builder.ensure(SharedAssets { target: self.target });
703 }
704
705 let index_page = builder
706 .src
707 .join("src/doc/index.md")
708 .into_os_string()
709 .into_string()
710 .expect("non-utf8 paths are unsupported");
711 let mut extra_args = match self.format {
712 DocumentationFormat::Html => {
713 vec![
714 "--markdown-css",
715 "rust.css",
716 "--markdown-no-toc",
717 "--index-page",
718 &index_page,
719 "--generate-link-to-definition",
720 ]
721 }
722 DocumentationFormat::Json => vec![],
723 };
724
725 if !builder.config.docs_minification {
726 extra_args.push("--disable-minification");
727 }
728 extra_args.push("-Zunstable-options");
730
731 let target_doc_dir_name =
732 if self.format == DocumentationFormat::Json { "json-doc" } else { "doc" };
733 let target_dir = builder
734 .stage_out(self.build_compiler, Mode::Std)
735 .join(target)
736 .join(target_doc_dir_name);
737
738 let out_dir = target_dir.join(target).join("doc");
742
743 let mut cargo = doc_std(
744 builder,
745 self.format,
746 self.build_compiler,
747 target,
748 &target_dir,
749 &extra_args,
750 &crates,
751 );
752 match self.format {
753 DocumentationFormat::Html => {}
754 DocumentationFormat::Json => {
755 cargo.args(["-Zunstable-options", "--output-format", "json"]);
759 }
760 }
761
762 let description =
763 format!("library{} in {} format", crate_description(&crates), self.format.as_str());
764
765 {
766 let _guard =
767 builder.msg(Kind::Doc, description, Mode::Std, self.build_compiler, target);
768
769 cargo.into_cmd().run(builder);
770 builder.cp_link_r(&out_dir, &out);
771 }
772
773 if let DocumentationFormat::Html = self.format {
775 if builder.paths.iter().any(|path| path.ends_with("library")) {
776 let index = out.join("std").join("index.html");
778 builder.maybe_open_in_browser::<Self>(index);
779 } else {
780 for requested_crate in crates {
781 if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
782 let index = out.join(requested_crate).join("index.html");
783 builder.maybe_open_in_browser::<Self>(index);
784 break;
785 }
786 }
787 }
788 }
789
790 out
791 }
792
793 fn metadata(&self) -> Option<StepMetadata> {
794 Some(
795 StepMetadata::doc("std", self.target)
796 .built_by(self.build_compiler)
797 .with_metadata(format!("crates=[{}]", self.crates.join(","))),
798 )
799 }
800}
801
802const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"];
812
813#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
814pub enum DocumentationFormat {
815 Html,
816 Json,
817}
818
819impl DocumentationFormat {
820 fn as_str(&self) -> &str {
821 match self {
822 DocumentationFormat::Html => "HTML",
823 DocumentationFormat::Json => "JSON",
824 }
825 }
826}
827
828fn doc_std(
830 builder: &Builder<'_>,
831 format: DocumentationFormat,
832 build_compiler: Compiler,
833 target: TargetSelection,
834 target_dir: &Path,
835 extra_args: &[&str],
836 requested_crates: &[String],
837) -> builder::Cargo {
838 let mut cargo = builder::Cargo::new(
839 builder,
840 build_compiler,
841 Mode::Std,
842 SourceType::InTree,
843 target,
844 Kind::Doc,
845 );
846
847 compile::std_cargo(builder, target, &mut cargo, requested_crates);
848 cargo
849 .arg("--no-deps")
850 .arg("--target-dir")
851 .arg(&*target_dir.to_string_lossy())
852 .arg("-Zrustdoc-map")
853 .rustdocflag("--extern-html-root-url")
854 .rustdocflag("std_detect=https://docs.rs/std_detect/latest/")
855 .rustdocflag("--extern-html-root-takes-precedence")
856 .rustdocflag("--resource-suffix")
857 .rustdocflag(&builder.version);
858 for arg in extra_args {
859 cargo.rustdocflag(arg);
860 }
861
862 if format == DocumentationFormat::Json || builder.config.library_docs_private_items {
865 cargo.rustdocflag("--document-private-items").rustdocflag("--document-hidden-items");
866 }
867 cargo
868}
869
870pub fn prepare_doc_compiler(
872 builder: &Builder<'_>,
873 target: TargetSelection,
874 stage: u32,
875) -> Compiler {
876 assert!(stage > 0, "Cannot document anything in stage 0");
877 let build_compiler = builder.compiler(stage - 1, builder.host_target);
878 builder.std(build_compiler, target);
879 build_compiler
880}
881
882fn merge_rustdoc_cci(
887 builder: &Builder<'_>,
888 build_compiler: Compiler,
889 json_files: &[PathBuf],
890 out_dir: &Path,
891) {
892 let mut cmd = builder.rustdoc_cmd(build_compiler);
893
894 cmd.arg("--enable-index-page").arg("-Zunstable-options").arg("-o").arg(out_dir);
895
896 if !builder.config.docs_minification {
897 cmd.arg("--disable-minification");
898 }
899
900 for json_file in json_files {
901 cmd.arg("--read-doc-meta-dir").arg(json_file.parent().unwrap());
902 }
903
904 cmd.run(builder);
905}
906
907#[derive(Debug, Clone, Hash, PartialEq, Eq)]
919pub struct CompilerWithTools {
920 build_compiler: Compiler,
921 target: TargetSelection,
922 stage: u32,
923}
924
925impl CompilerWithTools {
926 pub(crate) fn for_stage(builder: &Builder<'_>, stage: u32, target: TargetSelection) -> Self {
928 let build_compiler = prepare_doc_compiler(builder, target, stage);
929 Self { build_compiler, target, stage }
930 }
931}
932
933impl CommandLineStep for CompilerWithTools {
934 type Output = PathBuf;
935 const IS_HOST: bool = true;
936
937 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
938 run.alias("compiler-with-tools")
939 }
940
941 fn is_default_step(builder: &Builder<'_>) -> bool {
942 builder.config.compiler_docs
943 }
944
945 fn make_run(run: RunConfig<'_>) {
946 run.builder.ensure(CompilerWithTools::for_stage(
947 run.builder,
948 run.builder.top_stage,
949 run.target,
950 ));
951 }
952
953 fn run(self, builder: &Builder<'_>) -> Self::Output {
954 let CompilerWithTools { target, build_compiler, stage } = self;
955
956 let out = builder.compiler_doc_out(target);
958 let _ = fs::remove_dir_all(&out);
959
960 let _guard =
961 builder.msg(Kind::Doc, "compiler-with-tools", Mode::Rustc, build_compiler, target);
962
963 let combined_docs = vec![
964 builder.ensure(Rustc::for_stage(builder, stage, target)),
965 builder.ensure(Rustdoc::new(builder, target)),
966 builder.ensure(Rustfmt::new(builder, target)),
967 builder.ensure(Clippy::new(builder, target)),
968 builder.ensure(Miri::new(builder, target)),
969 builder.ensure(Cargo::new(builder, target)),
970 builder.ensure(Tidy::new(builder, target)),
971 builder.ensure(Bootstrap::new(builder, target)),
972 builder.ensure(BuildHelper::new(builder, target)),
973 builder.ensure(Compiletest::new(builder, target)),
974 builder.ensure(RunMakeSupport::new(builder, target)),
975 ];
976
977 if !builder.config.dry_run() {
978 let mut json_files = vec![];
980 for docs in combined_docs {
981 json_files.extend(docs.artifacts.json_files);
982
983 let dirs_to_copy: Vec<_> = docs
987 .artifacts
988 .target_dirs
989 .iter()
990 .chain(docs.artifacts.host_dirs.iter())
991 .map(|d| d.file_name().unwrap().to_str().unwrap())
992 .collect();
993 for dir in dirs_to_copy {
994 let docs_dir = docs.out_dir.join(dir);
996 assert!(docs_dir.exists(), "Docs directory {docs_dir:?} does not exist.");
997 let out_docs_dir = out.join(dir);
998 builder.create_dir(&out_docs_dir);
999 builder.cp_link_r(&docs_dir, &out_docs_dir);
1000
1001 let src_dir = docs.out_dir.join("src").join(dir);
1003 assert!(src_dir.exists(), "Docs source directory {src_dir:?} does not exist.");
1004 let out_src_dir = out.join("src").join(dir);
1005 builder.create_dir(&out_src_dir);
1006 builder.cp_link_r(&src_dir, &out_src_dir);
1007 }
1008 }
1009 merge_rustdoc_cci(builder, build_compiler, &json_files, &out);
1011 }
1012
1013 builder.open_in_browser(out.join("index.html"));
1015 out
1016 }
1017
1018 fn metadata(&self) -> Option<StepMetadata> {
1019 Some(StepMetadata::doc("CompilerWithTools", self.target).built_by(self.build_compiler))
1020 }
1021}
1022
1023#[derive(Clone)]
1025pub struct BuiltDocs {
1026 out_dir: PathBuf,
1028 artifacts: DocArtifacts,
1030}
1031
1032#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1036pub struct Rustc {
1037 build_compiler: Compiler,
1038 target: TargetSelection,
1039 crates: Vec<String>,
1040}
1041
1042impl Rustc {
1043 pub(crate) fn for_stage(builder: &Builder<'_>, stage: u32, target: TargetSelection) -> Self {
1045 let build_compiler = prepare_doc_compiler(builder, target, stage);
1046 Self::from_build_compiler(builder, build_compiler, target)
1047 }
1048
1049 fn from_build_compiler(
1050 builder: &Builder<'_>,
1051 build_compiler: Compiler,
1052 target: TargetSelection,
1053 ) -> Self {
1054 let crates = builder
1055 .in_tree_crates("rustc-main", Some(target))
1056 .into_iter()
1057 .map(|krate| krate.name.to_string())
1058 .collect();
1059 Self { build_compiler, target, crates }
1060 }
1061}
1062
1063impl CommandLineStep for Rustc {
1064 type Output = BuiltDocs;
1065 const IS_HOST: bool = true;
1066
1067 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1068 run.crate_or_deps("rustc-main").path("compiler")
1069 }
1070
1071 fn is_default_step(builder: &Builder<'_>) -> bool {
1072 builder.config.compiler_docs
1073 }
1074
1075 fn make_run(run: RunConfig<'_>) {
1076 run.builder.ensure(Rustc::for_stage(run.builder, run.builder.top_stage, run.target));
1077 }
1078
1079 fn run(self, builder: &Builder<'_>) -> Self::Output {
1086 let target = self.target;
1087
1088 let build_compiler = self.build_compiler;
1091 builder.std(build_compiler, builder.config.host_target);
1092
1093 let _guard = builder.msg(
1094 Kind::Doc,
1095 format!("compiler{}", crate_description(&self.crates)),
1096 Mode::Rustc,
1097 build_compiler,
1098 target,
1099 );
1100
1101 let mut cargo = builder::Cargo::new(
1103 builder,
1104 build_compiler,
1105 Mode::Rustc,
1106 SourceType::InTree,
1107 target,
1108 Kind::Doc,
1109 );
1110
1111 cargo.rustdocflag("--document-private-items");
1112 cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
1114 cargo.rustdocflag("--enable-index-page");
1115 cargo.rustdocflag("-Znormalize-docs");
1116 cargo.rustdocflag("--show-type-layout");
1117 cargo.rustdocflag("--generate-link-to-definition");
1121 cargo.rustdocflag("--generate-macro-expansion");
1122
1123 compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
1124
1125 cargo.arg("--no-deps");
1128 cargo.arg("-Zrustdoc-map");
1129
1130 cargo.rustdocflag("--extern-html-root-url");
1133 cargo.rustdocflag("ena=https://docs.rs/ena/latest/");
1134
1135 let cargo_target_dir = builder.stage_out(build_compiler, Mode::Rustc);
1136 let target_doc_dir = cargo_target_dir.join(target).join("doc");
1137 let host_doc_dir = cargo_target_dir.join("doc");
1138 for krate in &*self.crates {
1139 let dir_name = normalize_doc_crate_name(krate);
1143 t!(fs::create_dir_all(target_doc_dir.join(&*dir_name)));
1144 cargo.arg("-p").arg(krate);
1145 }
1146
1147 let artifacts = create_docs_and_gather_artifacts(builder, cargo);
1148 artifacts.sanity_check_crates(builder, self.crates.iter());
1149
1150 if !builder.config.dry_run() {
1151 merge_host_and_target_docs(builder, &artifacts, &host_doc_dir, &target_doc_dir);
1152 merge_rustdoc_cci(builder, build_compiler, &artifacts.json_files, &target_doc_dir);
1153 }
1154
1155 if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
1158 let index = if builder.paths.iter().any(|path| path.ends_with("compiler")) {
1159 target_doc_dir.join("rustc_middle").join("index.html")
1161 } else if let Some(krate) = self.crates.first() {
1162 target_doc_dir.join(normalize_doc_crate_name(krate)).join("index.html")
1164 } else {
1165 target_doc_dir.clone()
1166 };
1167 builder.open_in_browser(index);
1168 }
1169
1170 BuiltDocs { out_dir: target_doc_dir, artifacts }
1171 }
1172
1173 fn metadata(&self) -> Option<StepMetadata> {
1174 Some(StepMetadata::doc("rustc", self.target).built_by(self.build_compiler))
1175 }
1176}
1177
1178#[derive(Clone, Debug)]
1180struct DocArtifacts {
1181 host_dirs: Vec<PathBuf>,
1183 target_dirs: Vec<PathBuf>,
1185 json_files: Vec<PathBuf>,
1187}
1188
1189impl DocArtifacts {
1190 fn sanity_check_crates<S>(&self, builder: &Builder<'_>, crates: impl Iterator<Item = S>)
1192 where
1193 S: AsRef<str>,
1194 {
1195 if builder.config.dry_run() {
1196 return;
1197 }
1198 let crate_names: HashSet<&str> = self
1199 .host_dirs
1200 .iter()
1201 .chain(self.target_dirs.iter())
1202 .filter_map(|d| d.file_name().and_then(|d| d.to_str()))
1203 .collect();
1204 for krate in crates {
1205 let krate = krate.as_ref();
1206 let krate = normalize_doc_crate_name(krate);
1207 if !crate_names.contains(krate.as_str()) {
1208 eprintln!("ERROR: crate {krate} was not documented!");
1209 exit_process(1);
1210 }
1211 }
1212 }
1213}
1214
1215fn create_docs_and_gather_artifacts(builder: &Builder<'_>, cargo: builder::Cargo) -> DocArtifacts {
1217 let mut json_files = vec![];
1218 let mut host_dirs = vec![];
1219 let mut target_dirs = vec![];
1220 stream_cargo(builder, cargo, vec![], &mut |msg| {
1221 let CargoMessage::CompilerArtifact { filenames, target } = msg else {
1222 return;
1223 };
1224 if !target.doc {
1225 return;
1226 }
1227 let is_host = target.crate_types.iter().any(|t| t == "proc-macro");
1231 for filename in filenames {
1232 let path = Path::new(filename.as_ref());
1233 let Some(extension) = path.extension().and_then(|ext| ext.to_str()) else {
1234 continue;
1235 };
1236 let path = path.to_path_buf();
1237 if extension == "json" {
1238 json_files.push(path.to_path_buf());
1239 } else if extension == "html" {
1240 if is_host {
1241 host_dirs.push(path.parent().unwrap().to_path_buf());
1243 } else {
1244 target_dirs.push(path.parent().unwrap().to_path_buf());
1245 }
1246 }
1247 }
1248 });
1249 DocArtifacts { host_dirs, target_dirs, json_files }
1250}
1251
1252fn merge_host_and_target_docs(
1264 builder: &Builder<'_>,
1265 docs: &DocArtifacts,
1266 host_doc_dir: &Path,
1267 target_doc_dir: &Path,
1268) {
1269 for dir in &docs.host_dirs {
1271 let name = dir.file_name().and_then(|d| d.to_str()).unwrap();
1272 if let Some(target_dir) = docs.target_dirs.iter().find_map(|d| {
1273 let dirname = d.file_name().and_then(|d| d.to_str())?;
1274 if dirname == name { Some(d) } else { None }
1275 }) {
1276 eprintln!(
1277 "ERROR: host docs directory `{name}` ({dir:?}) is also contained in target doc directory ({target_dir:?})"
1278 );
1279 exit_process(1);
1280 }
1281 }
1282
1283 let target_src_dir = target_doc_dir.join("src");
1284 let host_src_dir = host_doc_dir.join("src");
1285
1286 for host_docs_crate in &docs.host_dirs {
1291 let dir_name = host_docs_crate.file_name().unwrap().to_str().unwrap();
1292 let dir_name = normalize_doc_crate_name(dir_name);
1294
1295 t!(symlink_dir(&builder.config, host_docs_crate, &target_doc_dir.join(&dir_name)));
1296
1297 let target_src_out = target_src_dir.join(&dir_name);
1299 let host_src_out = host_src_dir.join(&dir_name);
1300 t!(symlink_dir(&builder.config, &host_src_out, &target_src_out));
1301 }
1302
1303 for dir in docs.target_dirs.iter().chain(docs.host_dirs.iter()) {
1305 assert!(dir.exists(), "Doc directory {dir:?} does not exist");
1307 assert!(t!(dir.read_dir()).next().is_some(), "Doc directory {dir:?} is empty");
1308 }
1309}
1310
1311fn normalize_doc_crate_name(name: &str) -> String {
1314 name.replace("-", "_")
1315}
1316
1317macro_rules! tool_doc {
1318 (
1319 $tool: ident,
1320 $path: literal,
1321 mode = $mode:expr
1322 $(, is_library = $is_library:expr )?
1323 $(, crates = $crates:expr )?
1324 $(, allow_features: $allow_features:expr )?
1326 ) => {
1327 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
1328 pub struct $tool {
1329 build_compiler: Compiler,
1330 mode: Mode,
1331 target: TargetSelection,
1332 }
1333
1334 impl $tool {
1335 fn new(builder: &Builder<'_>, target: TargetSelection) -> $tool {
1336 let build_compiler = match $mode {
1337 Mode::ToolRustcPrivate => {
1338 let compilers = RustcPrivateCompilers::new(builder, builder.top_stage, target);
1340
1341 builder.ensure(Rustc::from_build_compiler(builder, compilers.build_compiler(), target));
1343 compilers.build_compiler()
1344 }
1345 Mode::ToolTarget => {
1346 prepare_doc_compiler(builder, builder.host_target, builder.top_stage)
1349 }
1350 _ => {
1351 panic!("Unexpected tool mode for documenting: {:?}", $mode);
1352 }
1353 };
1354 $tool { build_compiler, mode: $mode, target }
1355 }
1356 fn crates() -> &'static [&'static str] {
1357 &$($crates)?[..]
1358 }
1359 }
1360
1361 impl CommandLineStep for $tool {
1362 type Output = BuiltDocs;
1363 const IS_HOST: bool = true;
1364
1365 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1366 run.path($path)
1367 }
1368
1369 fn is_default_step(builder: &Builder<'_>) -> bool {
1370 builder.config.compiler_docs
1371 }
1372
1373 fn make_run(run: RunConfig<'_>) {
1374 run.builder.ensure($tool::new(run.builder, run.target));
1375 }
1376
1377 fn run(self, builder: &Builder<'_>) -> Self::Output {
1381 let mut source_type = SourceType::InTree;
1382
1383 if let Some(submodule_path) = submodule_path_of(&builder, $path) {
1384 source_type = SourceType::Submodule;
1385 builder.require_submodule(&submodule_path, None);
1386 }
1387
1388 let $tool { build_compiler, mode, target } = self;
1389
1390 let mut cargo = prepare_tool_cargo(
1392 builder,
1393 build_compiler,
1394 mode,
1395 target,
1396 Kind::Doc,
1397 $path,
1398 source_type,
1399 &[],
1400 );
1401 let allow_features = {
1402 let mut _value = "";
1403 $( _value = $allow_features; )?
1404 _value
1405 };
1406
1407 if !allow_features.is_empty() {
1408 cargo.allow_features(allow_features);
1409 }
1410
1411 cargo.arg("--no-deps");
1413
1414 if false $(|| $is_library)? {
1415 cargo.arg("--lib");
1416 }
1417
1418 for krate in $tool::crates() {
1419 cargo.arg("-p").arg(krate);
1420 }
1421
1422 cargo.rustdocflag("--document-private-items");
1423 cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
1425 cargo.rustdocflag("--enable-index-page");
1426 cargo.rustdocflag("--show-type-layout");
1427 cargo.rustdocflag("--generate-link-to-definition");
1428
1429 let cargo_target_dir = builder.stage_out(build_compiler, mode);
1430 let target_doc_dir = cargo_target_dir.join(target).join("doc");
1431 let host_doc_dir = cargo_target_dir.join("doc");
1432 for krate in $tool::crates() {
1433 let dir_name = normalize_doc_crate_name(krate);
1434 t!(fs::create_dir_all(target_doc_dir.join(&*dir_name)));
1435 }
1436
1437 let _guard = builder.msg(Kind::Doc, stringify!($tool).to_lowercase(), None, build_compiler, target);
1438 let artifacts = create_docs_and_gather_artifacts(builder, cargo);
1439 artifacts.sanity_check_crates(builder, $tool::crates().iter());
1440
1441 if !builder.config.dry_run() {
1442 merge_host_and_target_docs(builder, &artifacts, &host_doc_dir, &target_doc_dir);
1443 merge_rustdoc_cci(builder, build_compiler, &artifacts.json_files, &target_doc_dir);
1444 }
1445 BuiltDocs { out_dir: target_doc_dir, artifacts }
1446 }
1447
1448 fn metadata(&self) -> Option<StepMetadata> {
1449 Some(StepMetadata::doc(stringify!($tool), self.target).built_by(self.build_compiler))
1450 }
1451 }
1452 }
1453}
1454
1455tool_doc!(
1457 BuildHelper,
1458 "src/build_helper",
1459 mode = Mode::ToolTarget,
1464 is_library = true,
1465 crates = ["build_helper"]
1466);
1467tool_doc!(
1468 Rustdoc,
1469 "src/tools/rustdoc",
1470 mode = Mode::ToolRustcPrivate,
1471 crates = ["rustdoc", "rustdoc-json-types"]
1472);
1473tool_doc!(
1474 Rustfmt,
1475 "src/tools/rustfmt",
1476 mode = Mode::ToolRustcPrivate,
1477 crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]
1478);
1479tool_doc!(
1480 Clippy,
1481 "src/tools/clippy",
1482 mode = Mode::ToolRustcPrivate,
1483 crates = ["clippy_config", "clippy_utils"]
1484);
1485tool_doc!(Miri, "src/tools/miri", mode = Mode::ToolRustcPrivate, crates = ["miri"]);
1486tool_doc!(
1487 Cargo,
1488 "src/tools/cargo",
1489 mode = Mode::ToolTarget,
1490 crates = [
1491 "cargo",
1492 "cargo-credential",
1493 "cargo-platform",
1494 "cargo-test-macro",
1495 "cargo-test-support",
1496 "cargo-util",
1497 "cargo-util-schemas",
1498 "crates-io",
1499 "mdman",
1500 "rustfix",
1501 ],
1502 allow_features: "specialization"
1505);
1506tool_doc!(Tidy, "src/tools/tidy", mode = Mode::ToolTarget, crates = ["tidy"]);
1507tool_doc!(
1508 Bootstrap,
1509 "src/bootstrap",
1510 mode = Mode::ToolTarget,
1511 is_library = true,
1512 crates = ["bootstrap"]
1513);
1514tool_doc!(
1515 RunMakeSupport,
1516 "src/tools/run-make-support",
1517 mode = Mode::ToolTarget,
1518 is_library = true,
1519 crates = ["run_make_support"]
1520);
1521tool_doc!(
1522 Compiletest,
1523 "src/tools/compiletest",
1524 mode = Mode::ToolTarget,
1525 is_library = true,
1526 crates = ["compiletest"]
1527);
1528
1529#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1530pub struct ErrorIndex {
1531 compilers: RustcPrivateCompilers,
1532}
1533
1534impl CommandLineStep for ErrorIndex {
1535 type Output = ();
1536 const IS_HOST: bool = true;
1537
1538 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1539 run.path("src/tools/error_index_generator")
1540 }
1541
1542 fn is_default_step(builder: &Builder<'_>) -> bool {
1543 builder.config.docs
1544 }
1545
1546 fn make_run(run: RunConfig<'_>) {
1547 run.builder.ensure(ErrorIndex {
1548 compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1549 });
1550 }
1551
1552 fn run(self, builder: &Builder<'_>) {
1555 builder.info(&format!("Documenting error index ({})", self.compilers.target()));
1556 let out = builder.doc_out(self.compilers.target());
1557 t!(fs::create_dir_all(&out));
1558 tool::ErrorIndex::command(builder, self.compilers)
1559 .arg("html")
1560 .arg(&out)
1561 .arg(&builder.version)
1562 .run(builder);
1563
1564 let index = out.join("error-index.html");
1565 builder.maybe_open_in_browser::<Self>(index);
1566 }
1567
1568 fn metadata(&self) -> Option<StepMetadata> {
1569 Some(
1570 StepMetadata::doc("error-index", self.compilers.target())
1571 .built_by(self.compilers.build_compiler()),
1572 )
1573 }
1574}
1575
1576#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1579pub struct UnstableBookGen {
1580 build_compiler: Compiler,
1581 target: TargetSelection,
1582}
1583
1584impl CommandLineStep for UnstableBookGen {
1585 type Output = PathBuf;
1586 const IS_HOST: bool = true;
1587
1588 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1589 run.path("src/tools/unstable-book-gen")
1590 }
1591
1592 fn is_default_step(builder: &Builder<'_>) -> bool {
1593 builder.config.docs
1594 }
1595
1596 fn make_run(run: RunConfig<'_>) {
1597 run.builder.ensure(UnstableBookGen {
1598 build_compiler: prepare_doc_compiler(run.builder, run.target, run.builder.top_stage),
1599 target: run.target,
1600 });
1601 }
1602
1603 fn run(self, builder: &Builder<'_>) -> Self::Output {
1604 let target = self.target;
1605 let rustc_path = builder.rustc(self.build_compiler);
1606
1607 builder.info(&format!("Generating unstable book md files ({target})"));
1608 let out = builder.out.join(target).join("md-doc").join("unstable-book");
1609 builder.create_dir(&out);
1610 builder.remove_dir(&out);
1611 let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
1612 cmd.arg(builder.src.join("library"));
1613 cmd.arg(builder.src.join("compiler"));
1614 cmd.arg(builder.src.join("src"));
1615 cmd.arg(rustc_path);
1616 cmd.arg(&out);
1617
1618 builder.add_rustc_lib_path(self.build_compiler, &mut cmd);
1621
1622 cmd.run(builder);
1623 out
1624 }
1625}
1626
1627#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1629pub struct RustcBook {
1630 build_compiler: Compiler,
1631 target: TargetSelection,
1632 validate: bool,
1635}
1636
1637impl RustcBook {
1638 pub fn validate(build_compiler: Compiler, target: TargetSelection) -> Self {
1639 Self { build_compiler, target, validate: true }
1640 }
1641}
1642
1643impl CommandLineStep for RustcBook {
1644 type Output = ();
1645 const IS_HOST: bool = true;
1646
1647 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1648 run.path("src/doc/rustc")
1649 }
1650
1651 fn is_default_step(builder: &Builder<'_>) -> bool {
1652 builder.config.docs
1653 }
1654
1655 fn make_run(run: RunConfig<'_>) {
1656 let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
1660 run.builder.top_stage
1661 } else {
1662 2
1663 };
1664
1665 run.builder.ensure(RustcBook {
1666 build_compiler: prepare_doc_compiler(run.builder, run.target, stage),
1667 target: run.target,
1668 validate: false,
1669 });
1670 }
1671
1672 fn run(self, builder: &Builder<'_>) {
1678 let out_base = builder.out.join(self.target).join("md-doc").join("rustc");
1679 t!(fs::create_dir_all(&out_base));
1680 let out_listing = out_base.join("src/lints");
1681 builder.cp_link_r(&builder.src.join("src/doc/rustc"), &out_base);
1682 builder.info(&format!("Generating lint docs ({})", self.target));
1683
1684 let rustc = builder.rustc(self.build_compiler);
1685 builder.std(self.build_compiler, self.target);
1688 let mut cmd = builder.tool_cmd(Tool::LintDocs);
1689 cmd.arg("--build-rustc-stage");
1690 cmd.arg(self.build_compiler.stage.to_string());
1691 cmd.arg("--src");
1692 cmd.arg(builder.src.join("compiler"));
1693 cmd.arg("--out");
1694 cmd.arg(&out_listing);
1695 cmd.arg("--rustc");
1696 cmd.arg(&rustc);
1697 cmd.arg("--rustc-target").arg(self.target.rustc_target_arg());
1698 if let Some(target_linker) = builder.linker(self.target) {
1699 cmd.arg("--rustc-linker").arg(target_linker);
1700 }
1701 if builder.is_verbose() {
1702 cmd.arg("--verbose");
1703 }
1704 if self.validate {
1705 cmd.arg("--validate");
1706 }
1707 cmd.env("RUSTC_BOOTSTRAP", "1");
1711
1712 builder.add_rustc_lib_path(self.build_compiler, &mut cmd);
1716 let doc_generator_guard =
1717 builder.msg(Kind::Run, "lint-docs", None, self.build_compiler, self.target);
1718 cmd.run(builder);
1719 drop(doc_generator_guard);
1720
1721 builder.ensure(RustbookSrc {
1723 target: self.target,
1724 name: "rustc".to_owned(),
1725 src: out_base,
1726 parent: Some(self),
1727 languages: vec![],
1728 build_compiler: None,
1729 });
1730 }
1731}
1732
1733#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1737pub struct Reference {
1738 build_compiler: Compiler,
1739 target: TargetSelection,
1740}
1741
1742impl CommandLineStep for Reference {
1743 type Output = ();
1744
1745 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1746 run.path("src/doc/reference")
1747 }
1748
1749 fn is_default_step(builder: &Builder<'_>) -> bool {
1750 builder.config.docs
1751 }
1752
1753 fn make_run(run: RunConfig<'_>) {
1754 let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
1760 run.builder.top_stage
1761 } else {
1762 2
1763 };
1764
1765 run.builder.ensure(Reference {
1766 build_compiler: prepare_doc_compiler(run.builder, run.target, stage),
1767 target: run.target,
1768 });
1769 }
1770
1771 fn run(self, builder: &Builder<'_>) {
1773 builder.require_submodule("src/doc/reference", None);
1774
1775 builder.std(self.build_compiler, builder.config.host_target);
1778
1779 builder.ensure(RustbookSrc {
1781 target: self.target,
1782 name: "reference".to_owned(),
1783 src: builder.src.join("src/doc/reference"),
1784 build_compiler: Some(self.build_compiler),
1785 parent: Some(self),
1786 languages: vec![],
1787 });
1788 }
1789}