Skip to content

Commit 65833ed

Browse files
authored
Rollup merge of #111955 - jyn514:step-refactors, r=clubby789
bootstrap: Various Step refactors This ended up being a bunch of only somewhat related changes, sorry 😓 on the bright side, they're all fairly small and well-commented in the commit messages. - Document `ShouldRun::crates` - Switch Steps from crates to crate_or_deps where possible and document why the single remaining place can't switch - Switch doc::{Std, Rustc} to `crate_or_deps` Previously they were using `all_krates` and various hacks to determine which crates to document. Switch them to `crate_or_deps` so `ShouldRun` tells them which crate to document instead of having to guess. This also makes a few other refactors: - Remove the now unused `all_krates`; new code should only use `crate_or_deps`. - Add tests for documenting Std - Remove the unnecessary `run_cargo_rustdoc_for` closure so that we only run cargo once - Give a more helpful error message when documenting a no_std target - Use `builder.msg` in the Steps instead of `builder.info` - Extend `msg` and `description` to work with any subcommand Previously `description` only supported `Testing` and `Benchmarking`, and `msg` gave weird results for `doc` (it would say `Docing`). - Add a `make_run_crates` function and use it Rustc and Std This fixes the panic from the previous commit. - Allow checking individual crates This is useful for profiling metadata generation. This comes very close to removing all_krates, but doesn't quite - there's one last usage left in `doc`. This is fixed in a later commit. - Give a more helpful error when calling `cargo_crates_in_set` for an alias Before: ``` thread 'main' panicked at 'no entry found for key', builder.rs:110:30 ``` After: ``` thread 'main' panicked at 'missing crate for path library', check.rs:89:26 ```
2 parents 0c9f87c + c28ee60 commit 65833ed

File tree

8 files changed

+225
-167
lines changed

8 files changed

+225
-167
lines changed

src/bootstrap/builder.rs

+21-23
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,14 @@ impl RunConfig<'_> {
103103
}
104104

105105
/// Return a list of crate names selected by `run.paths`.
106+
#[track_caller]
106107
pub fn cargo_crates_in_set(&self) -> Interned<Vec<String>> {
107108
let mut crates = Vec::new();
108109
for krate in &self.paths {
109110
let path = krate.assert_single_path();
110-
let crate_name = self.builder.crate_paths[&path.path];
111+
let Some(crate_name) = self.builder.crate_paths.get(&path.path) else {
112+
panic!("missing crate for path {}", path.path.display())
113+
};
111114
crates.push(crate_name.to_string());
112115
}
113116
INTERNER.intern_list(crates)
@@ -427,25 +430,6 @@ impl<'a> ShouldRun<'a> {
427430
}
428431
}
429432

430-
/// Indicates it should run if the command-line selects the given crate or
431-
/// any of its (local) dependencies.
432-
///
433-
/// Compared to `krate`, this treats the dependencies as aliases for the
434-
/// same job. Generally it is preferred to use `krate`, and treat each
435-
/// individual path separately. For example `./x.py test src/liballoc`
436-
/// (which uses `krate`) will test just `liballoc`. However, `./x.py check
437-
/// src/liballoc` (which uses `all_krates`) will check all of `libtest`.
438-
/// `all_krates` should probably be removed at some point.
439-
pub fn all_krates(mut self, name: &str) -> Self {
440-
let mut set = BTreeSet::new();
441-
for krate in self.builder.in_tree_crates(name, None) {
442-
let path = krate.local_path(self.builder);
443-
set.insert(TaskPath { path, kind: Some(self.kind) });
444-
}
445-
self.paths.insert(PathSet::Set(set));
446-
self
447-
}
448-
449433
/// Indicates it should run if the command-line selects the given crate or
450434
/// any of its (local) dependencies.
451435
///
@@ -458,6 +442,8 @@ impl<'a> ShouldRun<'a> {
458442
/// Indicates it should run if the command-line selects any of the given crates.
459443
///
460444
/// `make_run` will be called a single time with all matching command-line paths.
445+
///
446+
/// Prefer [`ShouldRun::crate_or_deps`] to this function where possible.
461447
pub(crate) fn crates(mut self, crates: Vec<&Crate>) -> Self {
462448
for krate in crates {
463449
let path = krate.local_path(self.builder);
@@ -487,7 +473,15 @@ impl<'a> ShouldRun<'a> {
487473
self.paths(&[path])
488474
}
489475

490-
// multiple aliases for the same job
476+
/// Multiple aliases for the same job.
477+
///
478+
/// This differs from [`path`] in that multiple calls to path will end up calling `make_run`
479+
/// multiple times, whereas a single call to `paths` will only ever generate a single call to
480+
/// `paths`.
481+
///
482+
/// This is analogous to `all_krates`, although `all_krates` is gone now. Prefer [`path`] where possible.
483+
///
484+
/// [`path`]: ShouldRun::path
491485
pub fn paths(mut self, paths: &[&str]) -> Self {
492486
static SUBMODULES_PATHS: OnceCell<Vec<String>> = OnceCell::new();
493487

@@ -641,12 +635,16 @@ impl Kind {
641635
}
642636
}
643637

644-
pub fn test_description(&self) -> &'static str {
638+
pub fn description(&self) -> String {
645639
match self {
646640
Kind::Test => "Testing",
647641
Kind::Bench => "Benchmarking",
648-
_ => panic!("not a test command: {}!", self.as_str()),
642+
Kind::Doc => "Documenting",
643+
Kind::Run => "Running",
644+
Kind::Suggest => "Suggesting",
645+
_ => return format!("{self:?}"),
649646
}
647+
.to_owned()
650648
}
651649
}
652650

src/bootstrap/builder/tests.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::*;
22
use crate::config::{Config, DryRun, TargetSelection};
3+
use crate::doc::DocumentationFormat;
34
use std::thread;
45

56
fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
@@ -66,6 +67,16 @@ macro_rules! std {
6667
};
6768
}
6869

70+
macro_rules! doc_std {
71+
($host:ident => $target:ident, stage = $stage:literal) => {
72+
doc::Std::new(
73+
$stage,
74+
TargetSelection::from_user(stringify!($target)),
75+
DocumentationFormat::HTML,
76+
)
77+
};
78+
}
79+
6980
macro_rules! rustc {
7081
($host:ident => $target:ident, stage = $stage:literal) => {
7182
compile::Rustc::new(
@@ -144,6 +155,9 @@ fn alias_and_path_for_library() {
144155
first(cache.all::<compile::Std>()),
145156
&[std!(A => A, stage = 0), std!(A => A, stage = 1)]
146157
);
158+
159+
let mut cache = run_build(&["library".into(), "core".into()], configure("doc", &["A"], &["A"]));
160+
assert_eq!(first(cache.all::<doc::Std>()), &[doc_std!(A => A, stage = 0)]);
147161
}
148162

149163
#[test]

src/bootstrap/check.rs

+61-18
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
//! Implementation of compiling the compiler and standard library, in "check"-based modes.
22
3-
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
3+
use crate::builder::{crate_description, Builder, Kind, RunConfig, ShouldRun, Step};
44
use crate::cache::Interned;
5-
use crate::compile::{add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo};
5+
use crate::compile::{
6+
add_to_sysroot, make_run_crates, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
7+
};
68
use crate::config::TargetSelection;
79
use crate::tool::{prepare_tool_cargo, SourceType};
810
use crate::INTERNER;
@@ -12,6 +14,12 @@ use std::path::{Path, PathBuf};
1214
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
1315
pub struct Std {
1416
pub target: TargetSelection,
17+
/// Whether to build only a subset of crates.
18+
///
19+
/// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
20+
///
21+
/// [`compile::Rustc`]: crate::compile::Rustc
22+
crates: Interned<Vec<String>>,
1523
}
1624

1725
/// Returns args for the subcommand itself (not for cargo)
@@ -66,16 +74,23 @@ fn cargo_subcommand(kind: Kind) -> &'static str {
6674
}
6775
}
6876

77+
impl Std {
78+
pub fn new(target: TargetSelection) -> Self {
79+
Self { target, crates: INTERNER.intern_list(vec![]) }
80+
}
81+
}
82+
6983
impl Step for Std {
7084
type Output = ();
7185
const DEFAULT: bool = true;
7286

7387
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
74-
run.all_krates("sysroot").path("library")
88+
run.crate_or_deps("sysroot").path("library")
7589
}
7690

7791
fn make_run(run: RunConfig<'_>) {
78-
run.builder.ensure(Std { target: run.target });
92+
let crates = make_run_crates(&run, "library");
93+
run.builder.ensure(Std { target: run.target, crates });
7994
}
8095

8196
fn run(self, builder: &Builder<'_>) {
@@ -97,7 +112,14 @@ impl Step for Std {
97112
cargo.arg("--lib");
98113
}
99114

100-
let _guard = builder.msg_check("library artifacts", target);
115+
for krate in &*self.crates {
116+
cargo.arg("-p").arg(krate);
117+
}
118+
119+
let _guard = builder.msg_check(
120+
format_args!("library artifacts{}", crate_description(&self.crates)),
121+
target,
122+
);
101123
run_cargo(
102124
builder,
103125
cargo,
@@ -117,7 +139,8 @@ impl Step for Std {
117139
}
118140

119141
// don't run on std twice with x.py clippy
120-
if builder.kind == Kind::Clippy {
142+
// don't check test dependencies if we haven't built libtest
143+
if builder.kind == Kind::Clippy || !self.crates.is_empty() {
121144
return;
122145
}
123146

@@ -147,8 +170,8 @@ impl Step for Std {
147170
// Explicitly pass -p for all dependencies krates -- this will force cargo
148171
// to also check the tests/benches/examples for these crates, rather
149172
// than just the leaf crate.
150-
for krate in builder.in_tree_crates("test", Some(target)) {
151-
cargo.arg("-p").arg(krate.name);
173+
for krate in &*self.crates {
174+
cargo.arg("-p").arg(krate);
152175
}
153176

154177
let _guard = builder.msg_check("library test/bench/example targets", target);
@@ -167,6 +190,22 @@ impl Step for Std {
167190
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
168191
pub struct Rustc {
169192
pub target: TargetSelection,
193+
/// Whether to build only a subset of crates.
194+
///
195+
/// This shouldn't be used from other steps; see the comment on [`compile::Rustc`].
196+
///
197+
/// [`compile::Rustc`]: crate::compile::Rustc
198+
crates: Interned<Vec<String>>,
199+
}
200+
201+
impl Rustc {
202+
pub fn new(target: TargetSelection, builder: &Builder<'_>) -> Self {
203+
let mut crates = vec![];
204+
for krate in builder.in_tree_crates("rustc-main", None) {
205+
crates.push(krate.name.to_string());
206+
}
207+
Self { target, crates: INTERNER.intern_list(crates) }
208+
}
170209
}
171210

172211
impl Step for Rustc {
@@ -175,11 +214,12 @@ impl Step for Rustc {
175214
const DEFAULT: bool = true;
176215

177216
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
178-
run.all_krates("rustc-main").path("compiler")
217+
run.crate_or_deps("rustc-main").path("compiler")
179218
}
180219

181220
fn make_run(run: RunConfig<'_>) {
182-
run.builder.ensure(Rustc { target: run.target });
221+
let crates = make_run_crates(&run, "compiler");
222+
run.builder.ensure(Rustc { target: run.target, crates });
183223
}
184224

185225
/// Builds the compiler.
@@ -200,7 +240,7 @@ impl Step for Rustc {
200240
builder.ensure(crate::compile::Std::new(compiler, compiler.host));
201241
builder.ensure(crate::compile::Std::new(compiler, target));
202242
} else {
203-
builder.ensure(Std { target });
243+
builder.ensure(Std::new(target));
204244
}
205245

206246
let mut cargo = builder.cargo(
@@ -218,14 +258,17 @@ impl Step for Rustc {
218258
cargo.arg("--all-targets");
219259
}
220260

221-
// Explicitly pass -p for all compiler krates -- this will force cargo
261+
// Explicitly pass -p for all compiler crates -- this will force cargo
222262
// to also check the tests/benches/examples for these crates, rather
223263
// than just the leaf crate.
224-
for krate in builder.in_tree_crates("rustc-main", Some(target)) {
225-
cargo.arg("-p").arg(krate.name);
264+
for krate in &*self.crates {
265+
cargo.arg("-p").arg(krate);
226266
}
227267

228-
let _guard = builder.msg_check("compiler artifacts", target);
268+
let _guard = builder.msg_check(
269+
format_args!("compiler artifacts{}", crate_description(&self.crates)),
270+
target,
271+
);
229272
run_cargo(
230273
builder,
231274
cargo,
@@ -268,7 +311,7 @@ impl Step for CodegenBackend {
268311
let target = self.target;
269312
let backend = self.backend;
270313

271-
builder.ensure(Rustc { target });
314+
builder.ensure(Rustc::new(target, builder));
272315

273316
let mut cargo = builder.cargo(
274317
compiler,
@@ -318,7 +361,7 @@ impl Step for RustAnalyzer {
318361
let compiler = builder.compiler(builder.top_stage, builder.config.build);
319362
let target = self.target;
320363

321-
builder.ensure(Std { target });
364+
builder.ensure(Std::new(target));
322365

323366
let mut cargo = prepare_tool_cargo(
324367
builder,
@@ -386,7 +429,7 @@ macro_rules! tool_check_step {
386429
let compiler = builder.compiler(builder.top_stage, builder.config.build);
387430
let target = self.target;
388431

389-
builder.ensure(Rustc { target });
432+
builder.ensure(Rustc::new(target, builder));
390433

391434
let mut cargo = prepare_tool_cargo(
392435
builder,

src/bootstrap/compile.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ impl Std {
4848
}
4949
}
5050

51+
/// Given an `alias` selected by the `Step` and the paths passed on the command line,
52+
/// return a list of the crates that should be built.
53+
///
54+
/// Normally, people will pass *just* `library` if they pass it.
55+
/// But it's possible (although strange) to pass something like `library std core`.
56+
/// Build all crates anyway, as if they hadn't passed the other args.
57+
pub(crate) fn make_run_crates(run: &RunConfig<'_>, alias: &str) -> Interned<Vec<String>> {
58+
let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with(alias));
59+
if has_alias { Default::default() } else { run.cargo_crates_in_set() }
60+
}
61+
5162
impl Step for Std {
5263
type Output = ();
5364
const DEFAULT: bool = true;
@@ -62,16 +73,10 @@ impl Step for Std {
6273
}
6374

6475
fn make_run(run: RunConfig<'_>) {
65-
// Normally, people will pass *just* library if they pass it.
66-
// But it's possible (although strange) to pass something like `library std core`.
67-
// Build all crates anyway, as if they hadn't passed the other args.
68-
let has_library =
69-
run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library"));
70-
let crates = if has_library { Default::default() } else { run.cargo_crates_in_set() };
7176
run.builder.ensure(Std {
7277
compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()),
7378
target: run.target,
74-
crates,
79+
crates: make_run_crates(&run, "library"),
7580
});
7681
}
7782

@@ -615,6 +620,8 @@ impl Step for Rustc {
615620
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
616621
let mut crates = run.builder.in_tree_crates("rustc-main", None);
617622
for (i, krate) in crates.iter().enumerate() {
623+
// We can't allow `build rustc` as an alias for this Step, because that's reserved by `Assemble`.
624+
// Ideally Assemble would use `build compiler` instead, but that seems too confusing to be worth the breaking change.
618625
if krate.name == "rustc-main" {
619626
crates.swap_remove(i);
620627
break;

src/bootstrap/dist.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,7 @@ impl Step for JsonDocs {
106106
/// Builds the `rust-docs-json` installer component.
107107
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
108108
let host = self.host;
109-
builder.ensure(crate::doc::Std {
110-
stage: builder.top_stage,
111-
target: host,
112-
format: DocumentationFormat::JSON,
113-
});
109+
builder.ensure(crate::doc::Std::new(builder.top_stage, host, DocumentationFormat::JSON));
114110

115111
let dest = "share/doc/rust/json";
116112

0 commit comments

Comments
 (0)