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!["--markdown-css", "rust.css", "--markdown-no-toc", "--index-page", &index_page]
714 }
715 DocumentationFormat::Json => vec![],
716 };
717
718 if !builder.config.docs_minification {
719 extra_args.push("--disable-minification");
720 }
721 extra_args.push("-Zunstable-options");
723
724 let target_doc_dir_name =
725 if self.format == DocumentationFormat::Json { "json-doc" } else { "doc" };
726 let target_dir = builder
727 .stage_out(self.build_compiler, Mode::Std)
728 .join(target)
729 .join(target_doc_dir_name);
730
731 let out_dir = target_dir.join(target).join("doc");
735
736 let mut cargo = doc_std(
737 builder,
738 self.format,
739 self.build_compiler,
740 target,
741 &target_dir,
742 &extra_args,
743 &crates,
744 );
745 match self.format {
746 DocumentationFormat::Html => {}
747 DocumentationFormat::Json => {
748 cargo.args(["-Zunstable-options", "--output-format", "json"]);
752 }
753 }
754
755 let description =
756 format!("library{} in {} format", crate_description(&crates), self.format.as_str());
757
758 {
759 let _guard =
760 builder.msg(Kind::Doc, description, Mode::Std, self.build_compiler, target);
761
762 cargo.into_cmd().run(builder);
763 builder.cp_link_r(&out_dir, &out);
764 }
765
766 if let DocumentationFormat::Html = self.format {
768 if builder.paths.iter().any(|path| path.ends_with("library")) {
769 let index = out.join("std").join("index.html");
771 builder.maybe_open_in_browser::<Self>(index);
772 } else {
773 for requested_crate in crates {
774 if STD_PUBLIC_CRATES.iter().any(|&k| k == requested_crate) {
775 let index = out.join(requested_crate).join("index.html");
776 builder.maybe_open_in_browser::<Self>(index);
777 break;
778 }
779 }
780 }
781 }
782
783 out
784 }
785
786 fn metadata(&self) -> Option<StepMetadata> {
787 Some(
788 StepMetadata::doc("std", self.target)
789 .built_by(self.build_compiler)
790 .with_metadata(format!("crates=[{}]", self.crates.join(","))),
791 )
792 }
793}
794
795const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"];
805
806#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
807pub enum DocumentationFormat {
808 Html,
809 Json,
810}
811
812impl DocumentationFormat {
813 fn as_str(&self) -> &str {
814 match self {
815 DocumentationFormat::Html => "HTML",
816 DocumentationFormat::Json => "JSON",
817 }
818 }
819}
820
821fn doc_std(
823 builder: &Builder<'_>,
824 format: DocumentationFormat,
825 build_compiler: Compiler,
826 target: TargetSelection,
827 target_dir: &Path,
828 extra_args: &[&str],
829 requested_crates: &[String],
830) -> builder::Cargo {
831 let mut cargo = builder::Cargo::new(
832 builder,
833 build_compiler,
834 Mode::Std,
835 SourceType::InTree,
836 target,
837 Kind::Doc,
838 );
839
840 compile::std_cargo(builder, target, &mut cargo, requested_crates);
841 cargo
842 .arg("--no-deps")
843 .arg("--target-dir")
844 .arg(&*target_dir.to_string_lossy())
845 .arg("-Zrustdoc-map")
846 .rustdocflag("--extern-html-root-url")
847 .rustdocflag("std_detect=https://docs.rs/std_detect/latest/")
848 .rustdocflag("--extern-html-root-takes-precedence")
849 .rustdocflag("--resource-suffix")
850 .rustdocflag(&builder.version);
851 for arg in extra_args {
852 cargo.rustdocflag(arg);
853 }
854
855 if format == DocumentationFormat::Json || builder.config.library_docs_private_items {
858 cargo.rustdocflag("--document-private-items").rustdocflag("--document-hidden-items");
859 }
860 cargo
861}
862
863pub fn prepare_doc_compiler(
865 builder: &Builder<'_>,
866 target: TargetSelection,
867 stage: u32,
868) -> Compiler {
869 assert!(stage > 0, "Cannot document anything in stage 0");
870 let build_compiler = builder.compiler(stage - 1, builder.host_target);
871 builder.std(build_compiler, target);
872 build_compiler
873}
874
875fn merge_rustdoc_cci(
880 builder: &Builder<'_>,
881 build_compiler: Compiler,
882 json_files: &[PathBuf],
883 out_dir: &Path,
884) {
885 let mut cmd = builder.rustdoc_cmd(build_compiler);
886
887 cmd.arg("--enable-index-page").arg("-Zunstable-options").arg("-o").arg(out_dir);
888
889 if !builder.config.docs_minification {
890 cmd.arg("--disable-minification");
891 }
892
893 for json_file in json_files {
894 cmd.arg("--read-doc-meta-dir").arg(json_file.parent().unwrap());
895 }
896
897 cmd.run(builder);
898}
899
900#[derive(Debug, Clone, Hash, PartialEq, Eq)]
912pub struct CompilerWithTools {
913 build_compiler: Compiler,
914 target: TargetSelection,
915 stage: u32,
916}
917
918impl CompilerWithTools {
919 pub(crate) fn for_stage(builder: &Builder<'_>, stage: u32, target: TargetSelection) -> Self {
921 let build_compiler = prepare_doc_compiler(builder, target, stage);
922 Self { build_compiler, target, stage }
923 }
924}
925
926impl CommandLineStep for CompilerWithTools {
927 type Output = PathBuf;
928 const IS_HOST: bool = true;
929
930 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
931 run.alias("compiler-with-tools")
932 }
933
934 fn is_default_step(builder: &Builder<'_>) -> bool {
935 builder.config.compiler_docs
936 }
937
938 fn make_run(run: RunConfig<'_>) {
939 run.builder.ensure(CompilerWithTools::for_stage(
940 run.builder,
941 run.builder.top_stage,
942 run.target,
943 ));
944 }
945
946 fn run(self, builder: &Builder<'_>) -> Self::Output {
947 let CompilerWithTools { target, build_compiler, stage } = self;
948
949 let out = builder.compiler_doc_out(target);
951 let _ = fs::remove_dir_all(&out);
952
953 let _guard =
954 builder.msg(Kind::Doc, "compiler-with-tools", Mode::Rustc, build_compiler, target);
955
956 let combined_docs = vec![
957 builder.ensure(Rustc::for_stage(builder, stage, target)),
958 builder.ensure(Rustdoc::new(builder, target)),
959 builder.ensure(Rustfmt::new(builder, target)),
960 builder.ensure(Clippy::new(builder, target)),
961 builder.ensure(Miri::new(builder, target)),
962 builder.ensure(Cargo::new(builder, target)),
963 builder.ensure(Tidy::new(builder, target)),
964 builder.ensure(Bootstrap::new(builder, target)),
965 builder.ensure(BuildHelper::new(builder, target)),
966 builder.ensure(Compiletest::new(builder, target)),
967 builder.ensure(RunMakeSupport::new(builder, target)),
968 ];
969
970 if !builder.config.dry_run() {
971 let mut json_files = vec![];
973 for docs in combined_docs {
974 json_files.extend(docs.artifacts.json_files);
975
976 let dirs_to_copy: Vec<_> = docs
980 .artifacts
981 .target_dirs
982 .iter()
983 .chain(docs.artifacts.host_dirs.iter())
984 .map(|d| d.file_name().unwrap().to_str().unwrap())
985 .collect();
986 for dir in dirs_to_copy {
987 let docs_dir = docs.out_dir.join(dir);
989 assert!(docs_dir.exists(), "Docs directory {docs_dir:?} does not exist.");
990 let out_docs_dir = out.join(dir);
991 builder.create_dir(&out_docs_dir);
992 builder.cp_link_r(&docs_dir, &out_docs_dir);
993
994 let src_dir = docs.out_dir.join("src").join(dir);
996 assert!(src_dir.exists(), "Docs source directory {src_dir:?} does not exist.");
997 let out_src_dir = out.join("src").join(dir);
998 builder.create_dir(&out_src_dir);
999 builder.cp_link_r(&src_dir, &out_src_dir);
1000 }
1001 }
1002 merge_rustdoc_cci(builder, build_compiler, &json_files, &out);
1004 }
1005
1006 builder.open_in_browser(out.join("index.html"));
1008 out
1009 }
1010
1011 fn metadata(&self) -> Option<StepMetadata> {
1012 Some(StepMetadata::doc("CompilerWithTools", self.target).built_by(self.build_compiler))
1013 }
1014}
1015
1016#[derive(Clone)]
1018pub struct BuiltDocs {
1019 out_dir: PathBuf,
1021 artifacts: DocArtifacts,
1023}
1024
1025#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1029pub struct Rustc {
1030 build_compiler: Compiler,
1031 target: TargetSelection,
1032 crates: Vec<String>,
1033}
1034
1035impl Rustc {
1036 pub(crate) fn for_stage(builder: &Builder<'_>, stage: u32, target: TargetSelection) -> Self {
1038 let build_compiler = prepare_doc_compiler(builder, target, stage);
1039 Self::from_build_compiler(builder, build_compiler, target)
1040 }
1041
1042 fn from_build_compiler(
1043 builder: &Builder<'_>,
1044 build_compiler: Compiler,
1045 target: TargetSelection,
1046 ) -> Self {
1047 let crates = builder
1048 .in_tree_crates("rustc-main", Some(target))
1049 .into_iter()
1050 .map(|krate| krate.name.to_string())
1051 .collect();
1052 Self { build_compiler, target, crates }
1053 }
1054}
1055
1056impl CommandLineStep for Rustc {
1057 type Output = BuiltDocs;
1058 const IS_HOST: bool = true;
1059
1060 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1061 run.crate_or_deps("rustc-main").path("compiler")
1062 }
1063
1064 fn is_default_step(builder: &Builder<'_>) -> bool {
1065 builder.config.compiler_docs
1066 }
1067
1068 fn make_run(run: RunConfig<'_>) {
1069 run.builder.ensure(Rustc::for_stage(run.builder, run.builder.top_stage, run.target));
1070 }
1071
1072 fn run(self, builder: &Builder<'_>) -> Self::Output {
1079 let target = self.target;
1080
1081 let build_compiler = self.build_compiler;
1084 builder.std(build_compiler, builder.config.host_target);
1085
1086 let _guard = builder.msg(
1087 Kind::Doc,
1088 format!("compiler{}", crate_description(&self.crates)),
1089 Mode::Rustc,
1090 build_compiler,
1091 target,
1092 );
1093
1094 let mut cargo = builder::Cargo::new(
1096 builder,
1097 build_compiler,
1098 Mode::Rustc,
1099 SourceType::InTree,
1100 target,
1101 Kind::Doc,
1102 );
1103
1104 cargo.rustdocflag("--document-private-items");
1105 cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
1107 cargo.rustdocflag("--enable-index-page");
1108 cargo.rustdocflag("-Znormalize-docs");
1109 cargo.rustdocflag("--show-type-layout");
1110 cargo.rustdocflag("--generate-link-to-definition");
1114 cargo.rustdocflag("--generate-macro-expansion");
1115
1116 compile::rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
1117
1118 cargo.arg("--no-deps");
1121 cargo.arg("-Zrustdoc-map");
1122
1123 cargo.rustdocflag("--extern-html-root-url");
1126 cargo.rustdocflag("ena=https://docs.rs/ena/latest/");
1127
1128 let cargo_target_dir = builder.stage_out(build_compiler, Mode::Rustc);
1129 let target_doc_dir = cargo_target_dir.join(target).join("doc");
1130 let host_doc_dir = cargo_target_dir.join("doc");
1131 for krate in &*self.crates {
1132 let dir_name = normalize_doc_crate_name(krate);
1136 t!(fs::create_dir_all(target_doc_dir.join(&*dir_name)));
1137 cargo.arg("-p").arg(krate);
1138 }
1139
1140 let artifacts = create_docs_and_gather_artifacts(builder, cargo);
1141 artifacts.sanity_check_crates(builder, self.crates.iter());
1142
1143 if !builder.config.dry_run() {
1144 merge_host_and_target_docs(builder, &artifacts, &host_doc_dir, &target_doc_dir);
1145 merge_rustdoc_cci(builder, build_compiler, &artifacts.json_files, &target_doc_dir);
1146 }
1147
1148 if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
1151 let index = if builder.paths.iter().any(|path| path.ends_with("compiler")) {
1152 target_doc_dir.join("rustc_middle").join("index.html")
1154 } else if let Some(krate) = self.crates.first() {
1155 target_doc_dir.join(normalize_doc_crate_name(krate)).join("index.html")
1157 } else {
1158 target_doc_dir.clone()
1159 };
1160 builder.open_in_browser(index);
1161 }
1162
1163 BuiltDocs { out_dir: target_doc_dir, artifacts }
1164 }
1165
1166 fn metadata(&self) -> Option<StepMetadata> {
1167 Some(StepMetadata::doc("rustc", self.target).built_by(self.build_compiler))
1168 }
1169}
1170
1171#[derive(Clone, Debug)]
1173struct DocArtifacts {
1174 host_dirs: Vec<PathBuf>,
1176 target_dirs: Vec<PathBuf>,
1178 json_files: Vec<PathBuf>,
1180}
1181
1182impl DocArtifacts {
1183 fn sanity_check_crates<S>(&self, builder: &Builder<'_>, crates: impl Iterator<Item = S>)
1185 where
1186 S: AsRef<str>,
1187 {
1188 if builder.config.dry_run() {
1189 return;
1190 }
1191 let crate_names: HashSet<&str> = self
1192 .host_dirs
1193 .iter()
1194 .chain(self.target_dirs.iter())
1195 .filter_map(|d| d.file_name().and_then(|d| d.to_str()))
1196 .collect();
1197 for krate in crates {
1198 let krate = krate.as_ref();
1199 let krate = normalize_doc_crate_name(krate);
1200 if !crate_names.contains(krate.as_str()) {
1201 eprintln!("ERROR: crate {krate} was not documented!");
1202 exit_process(1);
1203 }
1204 }
1205 }
1206}
1207
1208fn create_docs_and_gather_artifacts(builder: &Builder<'_>, cargo: builder::Cargo) -> DocArtifacts {
1210 let mut json_files = vec![];
1211 let mut host_dirs = vec![];
1212 let mut target_dirs = vec![];
1213 stream_cargo(builder, cargo, vec![], &mut |msg| {
1214 let CargoMessage::CompilerArtifact { filenames, target } = msg else {
1215 return;
1216 };
1217 if !target.doc {
1218 return;
1219 }
1220 let is_host = target.crate_types.iter().any(|t| t == "proc-macro");
1224 for filename in filenames {
1225 let path = Path::new(filename.as_ref());
1226 let Some(extension) = path.extension().and_then(|ext| ext.to_str()) else {
1227 continue;
1228 };
1229 let path = path.to_path_buf();
1230 if extension == "json" {
1231 json_files.push(path.to_path_buf());
1232 } else if extension == "html" {
1233 if is_host {
1234 host_dirs.push(path.parent().unwrap().to_path_buf());
1236 } else {
1237 target_dirs.push(path.parent().unwrap().to_path_buf());
1238 }
1239 }
1240 }
1241 });
1242 DocArtifacts { host_dirs, target_dirs, json_files }
1243}
1244
1245fn merge_host_and_target_docs(
1257 builder: &Builder<'_>,
1258 docs: &DocArtifacts,
1259 host_doc_dir: &Path,
1260 target_doc_dir: &Path,
1261) {
1262 for dir in &docs.host_dirs {
1264 let name = dir.file_name().and_then(|d| d.to_str()).unwrap();
1265 if let Some(target_dir) = docs.target_dirs.iter().find_map(|d| {
1266 let dirname = d.file_name().and_then(|d| d.to_str())?;
1267 if dirname == name { Some(d) } else { None }
1268 }) {
1269 eprintln!(
1270 "ERROR: host docs directory `{name}` ({dir:?}) is also contained in target doc directory ({target_dir:?})"
1271 );
1272 exit_process(1);
1273 }
1274 }
1275
1276 let target_src_dir = target_doc_dir.join("src");
1277 let host_src_dir = host_doc_dir.join("src");
1278
1279 for host_docs_crate in &docs.host_dirs {
1284 let dir_name = host_docs_crate.file_name().unwrap().to_str().unwrap();
1285 let dir_name = normalize_doc_crate_name(dir_name);
1287
1288 t!(symlink_dir(&builder.config, host_docs_crate, &target_doc_dir.join(&dir_name)));
1289
1290 let target_src_out = target_src_dir.join(&dir_name);
1292 let host_src_out = host_src_dir.join(&dir_name);
1293 t!(symlink_dir(&builder.config, &host_src_out, &target_src_out));
1294 }
1295
1296 for dir in docs.target_dirs.iter().chain(docs.host_dirs.iter()) {
1298 assert!(dir.exists(), "Doc directory {dir:?} does not exist");
1300 assert!(t!(dir.read_dir()).next().is_some(), "Doc directory {dir:?} is empty");
1301 }
1302}
1303
1304fn normalize_doc_crate_name(name: &str) -> String {
1307 name.replace("-", "_")
1308}
1309
1310macro_rules! tool_doc {
1311 (
1312 $tool: ident,
1313 $path: literal,
1314 mode = $mode:expr
1315 $(, is_library = $is_library:expr )?
1316 $(, crates = $crates:expr )?
1317 $(, allow_features: $allow_features:expr )?
1319 ) => {
1320 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
1321 pub struct $tool {
1322 build_compiler: Compiler,
1323 mode: Mode,
1324 target: TargetSelection,
1325 }
1326
1327 impl $tool {
1328 fn new(builder: &Builder<'_>, target: TargetSelection) -> $tool {
1329 let build_compiler = match $mode {
1330 Mode::ToolRustcPrivate => {
1331 let compilers = RustcPrivateCompilers::new(builder, builder.top_stage, target);
1333
1334 builder.ensure(Rustc::from_build_compiler(builder, compilers.build_compiler(), target));
1336 compilers.build_compiler()
1337 }
1338 Mode::ToolTarget => {
1339 prepare_doc_compiler(builder, builder.host_target, builder.top_stage)
1342 }
1343 _ => {
1344 panic!("Unexpected tool mode for documenting: {:?}", $mode);
1345 }
1346 };
1347 $tool { build_compiler, mode: $mode, target }
1348 }
1349 fn crates() -> &'static [&'static str] {
1350 &$($crates)?[..]
1351 }
1352 }
1353
1354 impl CommandLineStep for $tool {
1355 type Output = BuiltDocs;
1356 const IS_HOST: bool = true;
1357
1358 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1359 run.path($path)
1360 }
1361
1362 fn is_default_step(builder: &Builder<'_>) -> bool {
1363 builder.config.compiler_docs
1364 }
1365
1366 fn make_run(run: RunConfig<'_>) {
1367 run.builder.ensure($tool::new(run.builder, run.target));
1368 }
1369
1370 fn run(self, builder: &Builder<'_>) -> Self::Output {
1374 let mut source_type = SourceType::InTree;
1375
1376 if let Some(submodule_path) = submodule_path_of(&builder, $path) {
1377 source_type = SourceType::Submodule;
1378 builder.require_submodule(&submodule_path, None);
1379 }
1380
1381 let $tool { build_compiler, mode, target } = self;
1382
1383 let mut cargo = prepare_tool_cargo(
1385 builder,
1386 build_compiler,
1387 mode,
1388 target,
1389 Kind::Doc,
1390 $path,
1391 source_type,
1392 &[],
1393 );
1394 let allow_features = {
1395 let mut _value = "";
1396 $( _value = $allow_features; )?
1397 _value
1398 };
1399
1400 if !allow_features.is_empty() {
1401 cargo.allow_features(allow_features);
1402 }
1403
1404 cargo.arg("--no-deps");
1406
1407 if false $(|| $is_library)? {
1408 cargo.arg("--lib");
1409 }
1410
1411 for krate in $tool::crates() {
1412 cargo.arg("-p").arg(krate);
1413 }
1414
1415 cargo.rustdocflag("--document-private-items");
1416 cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
1418 cargo.rustdocflag("--enable-index-page");
1419 cargo.rustdocflag("--show-type-layout");
1420 cargo.rustdocflag("--generate-link-to-definition");
1421
1422 let cargo_target_dir = builder.stage_out(build_compiler, mode);
1423 let target_doc_dir = cargo_target_dir.join(target).join("doc");
1424 let host_doc_dir = cargo_target_dir.join("doc");
1425 for krate in $tool::crates() {
1426 let dir_name = normalize_doc_crate_name(krate);
1427 t!(fs::create_dir_all(target_doc_dir.join(&*dir_name)));
1428 }
1429
1430 let _guard = builder.msg(Kind::Doc, stringify!($tool).to_lowercase(), None, build_compiler, target);
1431 let artifacts = create_docs_and_gather_artifacts(builder, cargo);
1432 artifacts.sanity_check_crates(builder, $tool::crates().iter());
1433
1434 if !builder.config.dry_run() {
1435 merge_host_and_target_docs(builder, &artifacts, &host_doc_dir, &target_doc_dir);
1436 merge_rustdoc_cci(builder, build_compiler, &artifacts.json_files, &target_doc_dir);
1437 }
1438 BuiltDocs { out_dir: target_doc_dir, artifacts }
1439 }
1440
1441 fn metadata(&self) -> Option<StepMetadata> {
1442 Some(StepMetadata::doc(stringify!($tool), self.target).built_by(self.build_compiler))
1443 }
1444 }
1445 }
1446}
1447
1448tool_doc!(
1450 BuildHelper,
1451 "src/build_helper",
1452 mode = Mode::ToolTarget,
1457 is_library = true,
1458 crates = ["build_helper"]
1459);
1460tool_doc!(
1461 Rustdoc,
1462 "src/tools/rustdoc",
1463 mode = Mode::ToolRustcPrivate,
1464 crates = ["rustdoc", "rustdoc-json-types"]
1465);
1466tool_doc!(
1467 Rustfmt,
1468 "src/tools/rustfmt",
1469 mode = Mode::ToolRustcPrivate,
1470 crates = ["rustfmt-nightly", "rustfmt-config_proc_macro"]
1471);
1472tool_doc!(
1473 Clippy,
1474 "src/tools/clippy",
1475 mode = Mode::ToolRustcPrivate,
1476 crates = ["clippy_config", "clippy_utils"]
1477);
1478tool_doc!(Miri, "src/tools/miri", mode = Mode::ToolRustcPrivate, crates = ["miri"]);
1479tool_doc!(
1480 Cargo,
1481 "src/tools/cargo",
1482 mode = Mode::ToolTarget,
1483 crates = [
1484 "cargo",
1485 "cargo-credential",
1486 "cargo-platform",
1487 "cargo-test-macro",
1488 "cargo-test-support",
1489 "cargo-util",
1490 "cargo-util-schemas",
1491 "crates-io",
1492 "mdman",
1493 "rustfix",
1494 ],
1495 allow_features: "specialization"
1498);
1499tool_doc!(Tidy, "src/tools/tidy", mode = Mode::ToolTarget, crates = ["tidy"]);
1500tool_doc!(
1501 Bootstrap,
1502 "src/bootstrap",
1503 mode = Mode::ToolTarget,
1504 is_library = true,
1505 crates = ["bootstrap"]
1506);
1507tool_doc!(
1508 RunMakeSupport,
1509 "src/tools/run-make-support",
1510 mode = Mode::ToolTarget,
1511 is_library = true,
1512 crates = ["run_make_support"]
1513);
1514tool_doc!(
1515 Compiletest,
1516 "src/tools/compiletest",
1517 mode = Mode::ToolTarget,
1518 is_library = true,
1519 crates = ["compiletest"]
1520);
1521
1522#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1523pub struct ErrorIndex {
1524 compilers: RustcPrivateCompilers,
1525}
1526
1527impl CommandLineStep for ErrorIndex {
1528 type Output = ();
1529 const IS_HOST: bool = true;
1530
1531 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1532 run.path("src/tools/error_index_generator")
1533 }
1534
1535 fn is_default_step(builder: &Builder<'_>) -> bool {
1536 builder.config.docs
1537 }
1538
1539 fn make_run(run: RunConfig<'_>) {
1540 run.builder.ensure(ErrorIndex {
1541 compilers: RustcPrivateCompilers::new(run.builder, run.builder.top_stage, run.target),
1542 });
1543 }
1544
1545 fn run(self, builder: &Builder<'_>) {
1548 builder.info(&format!("Documenting error index ({})", self.compilers.target()));
1549 let out = builder.doc_out(self.compilers.target());
1550 t!(fs::create_dir_all(&out));
1551 tool::ErrorIndex::command(builder, self.compilers)
1552 .arg("html")
1553 .arg(&out)
1554 .arg(&builder.version)
1555 .run(builder);
1556
1557 let index = out.join("error-index.html");
1558 builder.maybe_open_in_browser::<Self>(index);
1559 }
1560
1561 fn metadata(&self) -> Option<StepMetadata> {
1562 Some(
1563 StepMetadata::doc("error-index", self.compilers.target())
1564 .built_by(self.compilers.build_compiler()),
1565 )
1566 }
1567}
1568
1569#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1572pub struct UnstableBookGen {
1573 build_compiler: Compiler,
1574 target: TargetSelection,
1575}
1576
1577impl CommandLineStep for UnstableBookGen {
1578 type Output = PathBuf;
1579 const IS_HOST: bool = true;
1580
1581 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1582 run.path("src/tools/unstable-book-gen")
1583 }
1584
1585 fn is_default_step(builder: &Builder<'_>) -> bool {
1586 builder.config.docs
1587 }
1588
1589 fn make_run(run: RunConfig<'_>) {
1590 run.builder.ensure(UnstableBookGen {
1591 build_compiler: prepare_doc_compiler(run.builder, run.target, run.builder.top_stage),
1592 target: run.target,
1593 });
1594 }
1595
1596 fn run(self, builder: &Builder<'_>) -> Self::Output {
1597 let target = self.target;
1598 let rustc_path = builder.rustc(self.build_compiler);
1599
1600 builder.info(&format!("Generating unstable book md files ({target})"));
1601 let out = builder.out.join(target).join("md-doc").join("unstable-book");
1602 builder.create_dir(&out);
1603 builder.remove_dir(&out);
1604 let mut cmd = builder.tool_cmd(Tool::UnstableBookGen);
1605 cmd.arg(builder.src.join("library"));
1606 cmd.arg(builder.src.join("compiler"));
1607 cmd.arg(builder.src.join("src"));
1608 cmd.arg(rustc_path);
1609 cmd.arg(&out);
1610
1611 builder.add_rustc_lib_path(self.build_compiler, &mut cmd);
1614
1615 cmd.run(builder);
1616 out
1617 }
1618}
1619
1620#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1622pub struct RustcBook {
1623 build_compiler: Compiler,
1624 target: TargetSelection,
1625 validate: bool,
1628}
1629
1630impl RustcBook {
1631 pub fn validate(build_compiler: Compiler, target: TargetSelection) -> Self {
1632 Self { build_compiler, target, validate: true }
1633 }
1634}
1635
1636impl CommandLineStep for RustcBook {
1637 type Output = ();
1638 const IS_HOST: bool = true;
1639
1640 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1641 run.path("src/doc/rustc")
1642 }
1643
1644 fn is_default_step(builder: &Builder<'_>) -> bool {
1645 builder.config.docs
1646 }
1647
1648 fn make_run(run: RunConfig<'_>) {
1649 let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
1653 run.builder.top_stage
1654 } else {
1655 2
1656 };
1657
1658 run.builder.ensure(RustcBook {
1659 build_compiler: prepare_doc_compiler(run.builder, run.target, stage),
1660 target: run.target,
1661 validate: false,
1662 });
1663 }
1664
1665 fn run(self, builder: &Builder<'_>) {
1671 let out_base = builder.out.join(self.target).join("md-doc").join("rustc");
1672 t!(fs::create_dir_all(&out_base));
1673 let out_listing = out_base.join("src/lints");
1674 builder.cp_link_r(&builder.src.join("src/doc/rustc"), &out_base);
1675 builder.info(&format!("Generating lint docs ({})", self.target));
1676
1677 let rustc = builder.rustc(self.build_compiler);
1678 builder.std(self.build_compiler, self.target);
1681 let mut cmd = builder.tool_cmd(Tool::LintDocs);
1682 cmd.arg("--build-rustc-stage");
1683 cmd.arg(self.build_compiler.stage.to_string());
1684 cmd.arg("--src");
1685 cmd.arg(builder.src.join("compiler"));
1686 cmd.arg("--out");
1687 cmd.arg(&out_listing);
1688 cmd.arg("--rustc");
1689 cmd.arg(&rustc);
1690 cmd.arg("--rustc-target").arg(self.target.rustc_target_arg());
1691 if let Some(target_linker) = builder.linker(self.target) {
1692 cmd.arg("--rustc-linker").arg(target_linker);
1693 }
1694 if builder.is_verbose() {
1695 cmd.arg("--verbose");
1696 }
1697 if self.validate {
1698 cmd.arg("--validate");
1699 }
1700 cmd.env("RUSTC_BOOTSTRAP", "1");
1704
1705 builder.add_rustc_lib_path(self.build_compiler, &mut cmd);
1709 let doc_generator_guard =
1710 builder.msg(Kind::Run, "lint-docs", None, self.build_compiler, self.target);
1711 cmd.run(builder);
1712 drop(doc_generator_guard);
1713
1714 builder.ensure(RustbookSrc {
1716 target: self.target,
1717 name: "rustc".to_owned(),
1718 src: out_base,
1719 parent: Some(self),
1720 languages: vec![],
1721 build_compiler: None,
1722 });
1723 }
1724}
1725
1726#[derive(Debug, Clone, Hash, PartialEq, Eq)]
1730pub struct Reference {
1731 build_compiler: Compiler,
1732 target: TargetSelection,
1733}
1734
1735impl CommandLineStep for Reference {
1736 type Output = ();
1737
1738 fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1739 run.path("src/doc/reference")
1740 }
1741
1742 fn is_default_step(builder: &Builder<'_>) -> bool {
1743 builder.config.docs
1744 }
1745
1746 fn make_run(run: RunConfig<'_>) {
1747 let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 {
1753 run.builder.top_stage
1754 } else {
1755 2
1756 };
1757
1758 run.builder.ensure(Reference {
1759 build_compiler: prepare_doc_compiler(run.builder, run.target, stage),
1760 target: run.target,
1761 });
1762 }
1763
1764 fn run(self, builder: &Builder<'_>) {
1766 builder.require_submodule("src/doc/reference", None);
1767
1768 builder.std(self.build_compiler, builder.config.host_target);
1771
1772 builder.ensure(RustbookSrc {
1774 target: self.target,
1775 name: "reference".to_owned(),
1776 src: builder.src.join("src/doc/reference"),
1777 build_compiler: Some(self.build_compiler),
1778 parent: Some(self),
1779 languages: vec![],
1780 });
1781 }
1782}