From 220fbca724f7ba31be3f0926fd9227324940d83a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 23 Jul 2026 12:36:44 +0200 Subject: [PATCH] Avoid spurious rebuilds of JSON docs in bootstrap --- src/bootstrap/src/core/build_steps/doc.rs | 67 ++++++++++++++++------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index df3fb001e5bc5..99e2c61e442ff 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -721,7 +721,7 @@ impl Step for Std { DocumentationFormat::Html => { vec!["--markdown-css", "rust.css", "--markdown-no-toc", "--index-page", &index_page] } - DocumentationFormat::Json => vec!["--output-format", "json"], + DocumentationFormat::Json => vec![], }; if !builder.config.docs_minification { @@ -730,7 +730,47 @@ impl Step for Std { // For `--index-page` and `--output-format=json`. extra_args.push("-Zunstable-options"); - doc_std(builder, self.format, self.build_compiler, target, &out, &extra_args, &crates); + let target_doc_dir_name = + if self.format == DocumentationFormat::Json { "json-doc" } else { "doc" }; + let target_dir = builder + .stage_out(self.build_compiler, Mode::Std) + .join(target) + .join(target_doc_dir_name); + + // This is directory where the compiler will place the output of the command. + // We will then copy the files from this directory into the final `out` directory, the specified + // as a function parameter. + let out_dir = target_dir.join(target).join("doc"); + + let mut cargo = doc_std( + builder, + self.format, + self.build_compiler, + target, + &target_dir, + &extra_args, + &crates, + ); + match self.format { + DocumentationFormat::Html => {} + DocumentationFormat::Json => { + // We have to pass these directly to cargo, rather than through RUSTDOCFLAGS, + // otherwise Cargo will not detect freshness of the output correctly, and keep + // rebuilding the docs on every invocation. + cargo.args(["-Zunstable-options", "--output-format", "json"]); + } + } + + let description = + format!("library{} in {} format", crate_description(&crates), self.format.as_str()); + + { + let _guard = + builder.msg(Kind::Doc, description, Mode::Std, self.build_compiler, target); + + cargo.into_cmd().run(builder); + builder.cp_link_r(&out_dir, &out); + } // Open if the format is HTML if let DocumentationFormat::Html = self.format { @@ -787,25 +827,16 @@ impl DocumentationFormat { } } -/// Build the documentation for public standard library crates. +/// Prepare a Cargo command for building the documentation for public standard library crates. fn doc_std( builder: &Builder<'_>, format: DocumentationFormat, build_compiler: Compiler, target: TargetSelection, - out: &Path, + target_dir: &Path, extra_args: &[&str], requested_crates: &[String], -) { - let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" }; - let target_dir = - builder.stage_out(build_compiler, Mode::Std).join(target).join(target_doc_dir_name); - - // This is directory where the compiler will place the output of the command. - // We will then copy the files from this directory into the final `out` directory, the specified - // as a function parameter. - let out_dir = target_dir.join(target).join("doc"); - +) -> builder::Cargo { let mut cargo = builder::Cargo::new( builder, build_compiler, @@ -836,13 +867,7 @@ fn doc_std( if format == DocumentationFormat::Json || builder.config.library_docs_private_items { cargo.rustdocflag("--document-private-items").rustdocflag("--document-hidden-items"); } - - let description = - format!("library{} in {} format", crate_description(requested_crates), format.as_str()); - let _guard = builder.msg(Kind::Doc, description, Mode::Std, build_compiler, target); - - cargo.into_cmd().run(builder); - builder.cp_link_r(&out_dir, out); + cargo } /// Prepare a compiler that will be able to document something for `target` at `stage`.