diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index b2e9ba144d6..b16e34c0b93 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -430,25 +430,6 @@ impl<'a> ShouldRun<'a> { } } - /// Indicates it should run if the command-line selects the given crate or - /// any of its (local) dependencies. - /// - /// Compared to `krate`, this treats the dependencies as aliases for the - /// same job. Generally it is preferred to use `krate`, and treat each - /// individual path separately. For example `./x.py test src/liballoc` - /// (which uses `krate`) will test just `liballoc`. However, `./x.py check - /// src/liballoc` (which uses `all_krates`) will check all of `libtest`. - /// `all_krates` should probably be removed at some point. - pub fn all_krates(mut self, name: &str) -> Self { - let mut set = BTreeSet::new(); - for krate in self.builder.in_tree_crates(name, None) { - let path = krate.local_path(self.builder); - set.insert(TaskPath { path, kind: Some(self.kind) }); - } - self.paths.insert(PathSet::Set(set)); - self - } - /// Indicates it should run if the command-line selects the given crate or /// any of its (local) dependencies. /// diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index edca8fe9b13..d76b830b0e5 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -1,5 +1,6 @@ use super::*; use crate::config::{Config, DryRun, TargetSelection}; +use crate::doc::DocumentationFormat; use std::thread; fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { @@ -66,6 +67,16 @@ macro_rules! std { }; } +macro_rules! doc_std { + ($host:ident => $target:ident, stage = $stage:literal) => { + doc::Std::new( + $stage, + TargetSelection::from_user(stringify!($target)), + DocumentationFormat::HTML, + ) + }; +} + macro_rules! rustc { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Rustc::new( @@ -144,6 +155,9 @@ fn alias_and_path_for_library() { first(cache.all::()), &[std!(A => A, stage = 0), std!(A => A, stage = 1)] ); + + let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A"], &["A"])); + assert_eq!(first(cache.all::()), &[doc_std!(A => A, stage = 0)]); } #[test] diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index b49845386da..46fc5b80e99 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -106,11 +106,7 @@ impl Step for JsonDocs { /// Builds the `rust-docs-json` installer component. fn run(self, builder: &Builder<'_>) -> Option { let host = self.host; - builder.ensure(crate::doc::Std { - stage: builder.top_stage, - target: host, - format: DocumentationFormat::JSON, - }); + builder.ensure(crate::doc::Std::new(builder.top_stage, host, DocumentationFormat::JSON)); let dest = "share/doc/rust/json"; diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index b52c3b68cc4..357cd778b6c 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -16,6 +16,7 @@ use crate::builder::crate_description; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; use crate::compile; +use crate::compile::make_run_crates; use crate::config::{Config, TargetSelection}; use crate::tool::{self, prepare_tool_cargo, SourceType, Tool}; use crate::util::{symlink_dir, t, up_to_date}; @@ -87,15 +88,6 @@ book!( StyleGuide, "src/doc/style-guide", "style-guide"; ); -// "library/std" -> ["library", "std"] -// -// Used for deciding whether a particular step is one requested by the user on -// the `x.py doc` command line, which determines whether `--open` will open that -// page. -pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> { - path.iter().map(|component| component.to_str().unwrap_or("???")).collect() -} - #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct UnstableBook { target: TargetSelection, @@ -425,11 +417,18 @@ impl Step for SharedAssets { } } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub struct Std { pub stage: u32, pub target: TargetSelection, pub format: DocumentationFormat, + crates: Interned>, +} + +impl Std { + pub(crate) fn new(stage: u32, target: TargetSelection, format: DocumentationFormat) -> Self { + Std { stage, target, format, crates: INTERNER.intern_list(vec![]) } + } } impl Step for Std { @@ -438,7 +437,7 @@ impl Step for Std { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.all_krates("sysroot").path("library").default_condition(builder.config.docs) + run.crate_or_deps("sysroot").path("library").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -450,6 +449,7 @@ impl Step for Std { } else { DocumentationFormat::HTML }, + crates: make_run_crates(&run, "library"), }); } @@ -457,7 +457,7 @@ impl Step for Std { /// /// This will generate all documentation for the standard library and its /// dependencies. This is largely just a wrapper around `cargo doc`. - fn run(self, builder: &Builder<'_>) { + fn run(mut self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; let out = match self.format { @@ -487,25 +487,7 @@ impl Step for Std { extra_args.push(OsStr::new("--disable-minification")); } - let requested_crates = builder - .paths - .iter() - .map(components_simplified) - .filter_map(|path| { - if path.len() >= 2 && path.get(0) == Some(&"library") { - // single crate - Some(path[1].to_owned()) - } else if !path.is_empty() { - // ?? - Some(path[0].to_owned()) - } else { - // all library crates - None - } - }) - .collect::>(); - - doc_std(builder, self.format, stage, target, &out, &extra_args, &requested_crates); + doc_std(builder, self.format, stage, target, &out, &extra_args, &self.crates); // Don't open if the format is json if let DocumentationFormat::JSON = self.format { @@ -514,7 +496,11 @@ impl Step for Std { // Look for library/std, library/core etc in the `x.py doc` arguments and // open the corresponding rendered docs. - for requested_crate in requested_crates { + if self.crates.is_empty() { + self.crates = INTERNER.intern_list(vec!["library".to_owned()]); + }; + + for requested_crate in &*self.crates { if requested_crate == "library" { // For `x.py doc library --open`, open `std` by default. let index = out.join("std").join("index.html"); @@ -538,7 +524,7 @@ impl Step for Std { /// or remote link. const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"]; -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum DocumentationFormat { HTML, JSON, @@ -566,21 +552,19 @@ fn doc_std( extra_args: &[&OsStr], requested_crates: &[String], ) { - builder.info(&format!( - "Documenting{} stage{} library ({}) in {} format", - crate_description(requested_crates), - stage, - target, - format.as_str() - )); if builder.no_std(target) == Some(true) { panic!( "building std documentation for no_std target {target} is not supported\n\ - Set `docs = false` in the config to disable documentation." + Set `docs = false` in the config to disable documentation, or pass `--exclude doc::library`." ); } + let compiler = builder.compiler(stage, builder.config.build); + let description = + format!("library{} in {} format", crate_description(&requested_crates), format.as_str()); + let _guard = builder.msg(Kind::Doc, stage, &description, compiler.host, target); + let target_doc_dir_name = if format == DocumentationFormat::JSON { "json-doc" } else { "doc" }; let target_dir = builder.stage_out(compiler, Mode::Std).join(target.triple).join(target_doc_dir_name); @@ -590,35 +574,27 @@ fn doc_std( // as a function parameter. let out_dir = target_dir.join(target.triple).join("doc"); - let run_cargo_rustdoc_for = |package: &str| { - let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); - compile::std_cargo(builder, target, compiler.stage, &mut cargo); - cargo - .arg("--target-dir") - .arg(&*target_dir.to_string_lossy()) - .arg("-p") - .arg(package) - .arg("-Zskip-rustdoc-fingerprint") - .arg("--") - .arg("-Z") - .arg("unstable-options") - .arg("--resource-suffix") - .arg(&builder.version) - .args(extra_args); - if builder.config.library_docs_private_items { - cargo.arg("--document-private-items").arg("--document-hidden-items"); - } - builder.run(&mut cargo.into()); - }; + let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "rustdoc"); + compile::std_cargo(builder, target, compiler.stage, &mut cargo); + cargo.arg("--target-dir").arg(&*target_dir.to_string_lossy()).arg("-Zskip-rustdoc-fingerprint"); - for krate in STD_PUBLIC_CRATES { - run_cargo_rustdoc_for(krate); - if requested_crates.iter().any(|p| p == krate) { - // No need to document more of the libraries if we have the one we want. - break; - } + for krate in requested_crates { + cargo.arg("-p").arg(krate); } + cargo + .arg("--") + .arg("-Z") + .arg("unstable-options") + .arg("--resource-suffix") + .arg(&builder.version) + .args(extra_args); + + if builder.config.library_docs_private_items { + cargo.arg("--document-private-items").arg("--document-hidden-items"); + } + + builder.run(&mut cargo.into()); builder.cp_r(&out_dir, &out); } @@ -626,6 +602,28 @@ fn doc_std( pub struct Rustc { pub stage: u32, pub target: TargetSelection, + crates: Interned>, +} + +impl Rustc { + pub(crate) fn new(stage: u32, target: TargetSelection, builder: &Builder<'_>) -> Self { + // Find dependencies for top level crates. + let root_crates = vec![ + INTERNER.intern_str("rustc_driver"), + INTERNER.intern_str("rustc_codegen_llvm"), + INTERNER.intern_str("rustc_codegen_ssa"), + ]; + let crates: Vec<_> = root_crates + .iter() + .flat_map(|krate| { + builder + .in_tree_crates(krate, Some(target)) + .into_iter() + .map(|krate| krate.name.to_string()) + }) + .collect(); + Self { stage, target, crates: INTERNER.intern_list(crates) } + } } impl Step for Rustc { @@ -641,7 +639,11 @@ impl Step for Rustc { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustc { stage: run.builder.top_stage, target: run.target }); + run.builder.ensure(Rustc { + stage: run.builder.top_stage, + target: run.target, + crates: make_run_crates(&run, "compiler"), + }); } /// Generates compiler documentation. @@ -654,15 +656,6 @@ impl Step for Rustc { let stage = self.stage; let target = self.target; - let paths = builder - .paths - .iter() - .filter(|path| { - let components = components_simplified(path); - components.len() >= 2 && components[0] == "compiler" - }) - .collect::>(); - // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); @@ -672,7 +665,13 @@ impl Step for Rustc { let compiler = builder.compiler(stage, builder.config.build); builder.ensure(compile::Std::new(compiler, builder.config.build)); - builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); + let _guard = builder.msg( + Kind::Doc, + stage, + &format!("compiler{}", crate_description(&self.crates)), + compiler.host, + target, + ); // This uses a shared directory so that librustdoc documentation gets // correctly built and merged with the rustc documentation. This is @@ -710,22 +709,8 @@ impl Step for Rustc { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - let root_crates = if paths.is_empty() { - vec![ - INTERNER.intern_str("rustc_driver"), - INTERNER.intern_str("rustc_codegen_llvm"), - INTERNER.intern_str("rustc_codegen_ssa"), - ] - } else { - paths.into_iter().map(|p| builder.crate_paths[p]).collect() - }; - // Find dependencies for top level crates. - let compiler_crates = root_crates.iter().flat_map(|krate| { - builder.in_tree_crates(krate, Some(target)).into_iter().map(|krate| krate.name) - }); - let mut to_open = None; - for krate in compiler_crates { + for krate in &*self.crates { // Create all crate output directories first to make sure rustdoc uses // relative links. // FIXME: Cargo should probably do this itself. @@ -785,7 +770,7 @@ macro_rules! tool_doc { if true $(&& $rustc_tool)? { // Build rustc docs so that we generate relative links. - builder.ensure(Rustc { stage, target }); + builder.ensure(Rustc::new(stage, target, builder)); // Rustdoc needs the rustc sysroot available to build. // FIXME: is there a way to only ensure `check::Rustc` here? Last time I tried it failed diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 25941fc64c5..960abb31b20 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -220,7 +220,7 @@ impl Step for HtmlCheck { } // Ensure that a few different kinds of documentation are available. builder.default_doc(&[]); - builder.ensure(crate::doc::Rustc { target: self.target, stage: builder.top_stage }); + builder.ensure(crate::doc::Rustc::new(builder.top_stage, self.target, builder)); try_run(builder, builder.tool_cmd(Tool::HtmlChecker).arg(builder.doc_out(self.target))); } @@ -886,11 +886,11 @@ impl Step for RustdocJSStd { command.arg("--test-file").arg(path); } } - builder.ensure(crate::doc::Std { - target: self.target, - stage: builder.top_stage, - format: DocumentationFormat::HTML, - }); + builder.ensure(crate::doc::Std::new( + builder.top_stage, + self.target, + DocumentationFormat::HTML, + )); builder.run(&mut command); } else { builder.info("No nodejs found, skipping \"tests/rustdoc-js-std\" tests");