about summary refs log tree commit diff
path: root/src/bootstrap
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-07-28 13:56:32 +0000
committerbors <bors@rust-lang.org>2020-07-28 13:56:32 +0000
commit7b3a7819371cef92a187e9bac8f7810ccde15216 (patch)
treea67620ed2276657f29e99763d4dd4d94dc14be27 /src/bootstrap
parent2c28244cf0fc9868f55070e55b8f332d196eaf3f (diff)
parentda40cf81e63d04dced9d943743bb2a58801916e7 (diff)
downloadrust-7b3a7819371cef92a187e9bac8f7810ccde15216.tar.gz
rust-7b3a7819371cef92a187e9bac8f7810ccde15216.zip
Auto merge of #73964 - jyn514:sane-defaults, r=Mark-Simulacrum
Improve defaults in x.py

- Make the default stage dependent on the subcommand
- Don't build stage1 rustc artifacts with x.py build --stage 1. If this is what you want, use x.py build --stage 2 instead, which gives you a working libstd.
- Change default debuginfo when debug = true from 2 to 1

I tried to fix CI to use `--stage 2` everywhere it currently has no stage, but I might have missed a spot.
This does not update much of the documentation - most of it is in https://github.com/rust-lang/rustc-dev-guide/ or https://github.com/rust-lang/rust-forge and will need a separate PR.

See individual commits for a detailed rationale of each change.
See also the MCP: https://github.com/rust-lang/compiler-team/issues/326

r? @Mark-Simulacrum , but anyone is free to give an opinion.
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/builder.rs60
-rw-r--r--src/bootstrap/builder/tests.rs1017
-rw-r--r--src/bootstrap/compile.rs4
-rw-r--r--src/bootstrap/config.rs2
-rw-r--r--src/bootstrap/flags.rs2
-rw-r--r--src/bootstrap/mk/Makefile.in34
6 files changed, 620 insertions, 499 deletions
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index c1e56347ab1..144e146685f 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -232,7 +232,7 @@ impl StepDescription {
                 }
 
                 if !attempted_run {
-                    panic!("Error: no rules matched {}.", path.display());
+                    panic!("error: no rules matched {}", path.display());
                 }
             }
         }
@@ -501,16 +501,7 @@ impl<'a> Builder<'a> {
             _ => return None,
         };
 
-        let builder = Builder {
-            build,
-            top_stage: build.config.stage.unwrap_or(2),
-            kind,
-            cache: Cache::new(),
-            stack: RefCell::new(Vec::new()),
-            time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
-            paths: vec![],
-        };
-
+        let builder = Self::new_internal(build, kind, vec![]);
         let builder = &builder;
         let mut should_run = ShouldRun::new(builder);
         for desc in Builder::get_step_descriptions(builder.kind) {
@@ -535,6 +526,32 @@ impl<'a> Builder<'a> {
         Some(help)
     }
 
+    fn new_internal(build: &Build, kind: Kind, paths: Vec<PathBuf>) -> Builder<'_> {
+        let top_stage = if let Some(explicit_stage) = build.config.stage {
+            explicit_stage
+        } else {
+            // See https://github.com/rust-lang/compiler-team/issues/326
+            match kind {
+                Kind::Doc => 0,
+                Kind::Build | Kind::Test => 1,
+                Kind::Bench | Kind::Dist | Kind::Install => 2,
+                // These are all bootstrap tools, which don't depend on the compiler.
+                // The stage we pass shouldn't matter, but use 0 just in case.
+                Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0,
+            }
+        };
+
+        Builder {
+            build,
+            top_stage,
+            kind,
+            cache: Cache::new(),
+            stack: RefCell::new(Vec::new()),
+            time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
+            paths,
+        }
+    }
+
     pub fn new(build: &Build) -> Builder<'_> {
         let (kind, paths) = match build.config.cmd {
             Subcommand::Build { ref paths } => (Kind::Build, &paths[..]),
@@ -550,15 +567,20 @@ impl<'a> Builder<'a> {
             Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(),
         };
 
-        Builder {
-            build,
-            top_stage: build.config.stage.unwrap_or(2),
-            kind,
-            cache: Cache::new(),
-            stack: RefCell::new(Vec::new()),
-            time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
-            paths: paths.to_owned(),
+        let this = Self::new_internal(build, kind, paths.to_owned());
+
+        // CI should always run stage 2 builds, unless it specifically states otherwise
+        #[cfg(not(test))]
+        if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None {
+            match kind {
+                Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => {
+                    assert_eq!(this.top_stage, 2)
+                }
+                Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {}
+            }
         }
+
+        this
     }
 
     pub fn execute_cli(&self) {
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index 6684ca82c27..4293844fcbf 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -2,8 +2,6 @@ use super::*;
 use crate::config::{Config, TargetSelection};
 use std::thread;
 
-use pretty_assertions::assert_eq;
-
 fn configure(host: &[&str], target: &[&str]) -> Config {
     let mut config = Config::default_opts();
     // don't save toolstates
@@ -35,463 +33,564 @@ fn first<A, B>(v: Vec<(A, B)>) -> Vec<A> {
     v.into_iter().map(|(a, _)| a).collect::<Vec<_>>()
 }
 
-#[test]
-fn dist_baseline() {
-    let build = Build::new(configure(&[], &[]));
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-    let a = TargetSelection::from_user("A");
-
-    assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
-    assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
-    assert_eq!(
-        first(builder.cache.all::<dist::Rustc>()),
-        &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Std>()),
-        &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },]
-    );
-    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-    // Make sure rustdoc is only built once.
-    assert_eq!(
-        first(builder.cache.all::<tool::Rustdoc>()),
-        &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
-    );
-}
-
-#[test]
-fn dist_with_targets() {
-    let build = Build::new(configure(&[], &["B"]));
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-
-    assert_eq!(
-        first(builder.cache.all::<dist::Docs>()),
-        &[dist::Docs { host: a }, dist::Docs { host: b },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Mingw>()),
-        &[dist::Mingw { host: a }, dist::Mingw { host: b },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Rustc>()),
-        &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Std>()),
-        &[
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
-        ]
-    );
-    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-}
-
-#[test]
-fn dist_with_hosts() {
-    let build = Build::new(configure(&["B"], &[]));
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-
-    assert_eq!(
-        first(builder.cache.all::<dist::Docs>()),
-        &[dist::Docs { host: a }, dist::Docs { host: b },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Mingw>()),
-        &[dist::Mingw { host: a }, dist::Mingw { host: b },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Rustc>()),
-        &[
-            dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
-            dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
-        ]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Std>()),
-        &[
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-        ]
-    );
-    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-}
-
-#[test]
-fn dist_only_cross_host() {
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-    let mut build = Build::new(configure(&["B"], &[]));
-    build.config.docs = false;
-    build.config.extended = true;
-    build.hosts = vec![b];
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-    assert_eq!(
-        first(builder.cache.all::<dist::Rustc>()),
-        &[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<compile::Rustc>()),
-        &[
-            compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
-            compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
-        ]
-    );
-}
-
-#[test]
-fn dist_with_targets_and_hosts() {
-    let build = Build::new(configure(&["B"], &["C"]));
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-    let c = TargetSelection::from_user("C");
-
-    assert_eq!(
-        first(builder.cache.all::<dist::Docs>()),
-        &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Mingw>()),
-        &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Rustc>()),
-        &[
-            dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
-            dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
-        ]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Std>()),
-        &[
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-            dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
-        ]
-    );
-    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-}
-
-#[test]
-fn dist_with_target_flag() {
-    let mut config = configure(&["B"], &["C"]);
-    config.skip_only_host_steps = true; // as-if --target=C was passed
-    let build = Build::new(config);
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-    let c = TargetSelection::from_user("C");
-
-    assert_eq!(
-        first(builder.cache.all::<dist::Docs>()),
-        &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Mingw>()),
-        &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
-    );
-    assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
-    assert_eq!(
-        first(builder.cache.all::<dist::Std>()),
-        &[
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-            dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
-        ]
-    );
-    assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
-}
-
-#[test]
-fn dist_with_same_targets_and_hosts() {
-    let build = Build::new(configure(&["B"], &["B"]));
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
-
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-
-    assert_eq!(
-        first(builder.cache.all::<dist::Docs>()),
-        &[dist::Docs { host: a }, dist::Docs { host: b },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Mingw>()),
-        &[dist::Mingw { host: a }, dist::Mingw { host: b },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Rustc>()),
-        &[
-            dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
-            dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
-        ]
-    );
-    assert_eq!(
-        first(builder.cache.all::<dist::Std>()),
-        &[
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-        ]
-    );
-    assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
-    assert_eq!(
-        first(builder.cache.all::<compile::Std>()),
-        &[
-            compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
-        ]
-    );
-    assert_eq!(
-        first(builder.cache.all::<compile::Assemble>()),
-        &[
-            compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
-            compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
-            compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
-            compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } },
-        ]
-    );
-}
-
-#[test]
-fn build_default() {
-    let build = Build::new(configure(&["B"], &["C"]));
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
-
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-    let c = TargetSelection::from_user("C");
-
-    assert_eq!(
-        first(builder.cache.all::<compile::Std>()),
-        &[
-            compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
-            compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
-            compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
-            compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c },
-        ]
-    );
-    assert!(!builder.cache.all::<compile::Assemble>().is_empty());
-    assert_eq!(
-        first(builder.cache.all::<compile::Rustc>()),
-        &[
-            compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
-            compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
-            compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a },
-            compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: a },
-            compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
-            compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b },
-            compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: b },
-        ]
-    );
-}
-
-#[test]
-fn build_with_target_flag() {
-    let mut config = configure(&["B"], &["C"]);
-    config.skip_only_host_steps = true;
-    let build = Build::new(config);
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
-
-    let a = TargetSelection::from_user("A");
-    let b = TargetSelection::from_user("B");
-    let c = TargetSelection::from_user("C");
-
-    assert_eq!(
-        first(builder.cache.all::<compile::Std>()),
-        &[
-            compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
-            compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a },
-            compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
-            compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b },
-            compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
-            compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c },
-        ]
-    );
-    assert_eq!(
-        first(builder.cache.all::<compile::Assemble>()),
-        &[
-            compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
-            compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
-            compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
-            compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } },
-        ]
-    );
-    assert_eq!(
-        first(builder.cache.all::<compile::Rustc>()),
-        &[
-            compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
-            compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
-            compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
-        ]
-    );
-}
-
-#[test]
-fn test_with_no_doc_stage0() {
-    let mut config = configure(&[], &[]);
-    config.stage = Some(0);
-    config.cmd = Subcommand::Test {
-        paths: vec!["library/std".into()],
-        test_args: vec![],
-        rustc_args: vec![],
-        fail_fast: true,
-        doc_tests: DocTests::No,
-        bless: false,
-        compare_mode: None,
-        rustfix_coverage: false,
-        pass: None,
-    };
-
-    let build = Build::new(config);
-    let mut builder = Builder::new(&build);
-
-    let host = TargetSelection::from_user("A");
-
-    builder
-        .run_step_descriptions(&[StepDescription::from::<test::Crate>()], &["library/std".into()]);
-
-    // Ensure we don't build any compiler artifacts.
-    assert!(!builder.cache.contains::<compile::Rustc>());
-    assert_eq!(
-        first(builder.cache.all::<test::Crate>()),
-        &[test::Crate {
-            compiler: Compiler { host, stage: 0 },
-            target: host,
-            mode: Mode::Std,
-            test_kind: test::TestKind::Test,
-            krate: INTERNER.intern_str("std"),
-        },]
-    );
-}
-
-#[test]
-fn test_exclude() {
-    let mut config = configure(&[], &[]);
-    config.exclude = vec!["src/tools/tidy".into()];
-    config.cmd = Subcommand::Test {
-        paths: Vec::new(),
-        test_args: Vec::new(),
-        rustc_args: Vec::new(),
-        fail_fast: true,
-        doc_tests: DocTests::No,
-        bless: false,
-        compare_mode: None,
-        rustfix_coverage: false,
-        pass: None,
-    };
-
-    let build = Build::new(config);
-    let builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
-
-    // Ensure we have really excluded tidy
-    assert!(!builder.cache.contains::<test::Tidy>());
-
-    // Ensure other tests are not affected.
-    assert!(builder.cache.contains::<test::RustdocUi>());
-}
-
-#[test]
-fn doc_default() {
-    let mut config = configure(&[], &[]);
-    config.compiler_docs = true;
-    config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
-    let build = Build::new(config);
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
-    let a = TargetSelection::from_user("A");
-
-    // error_index_generator uses stage 1 to share rustdoc artifacts with the
-    // rustdoc tool.
-    assert_eq!(
-        first(builder.cache.all::<doc::ErrorIndex>()),
-        &[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<tool::ErrorIndex>()),
-        &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
-    );
-    // This is actually stage 1, but Rustdoc::run swaps out the compiler with
-    // stage minus 1 if --stage is not 0. Very confusing!
-    assert_eq!(
-        first(builder.cache.all::<tool::Rustdoc>()),
-        &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
-    );
+mod defaults {
+    use super::{configure, first};
+    use crate::builder::*;
+    use crate::Config;
+    use pretty_assertions::assert_eq;
+
+    #[test]
+    fn build_default() {
+        let build = Build::new(configure(&[], &[]));
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+
+        let a = TargetSelection::from_user("A");
+        assert_eq!(
+            first(builder.cache.all::<compile::Std>()),
+            &[
+                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+            ]
+        );
+        assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+        // Make sure rustdoc is only built once.
+        assert_eq!(
+            first(builder.cache.all::<tool::Rustdoc>()),
+            // Recall that rustdoc stages are off-by-one
+            // - this is the compiler it's _linked_ to, not built with.
+            &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }],
+        );
+        assert_eq!(
+            first(builder.cache.all::<compile::Rustc>()),
+            &[compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },]
+        );
+    }
+
+    #[test]
+    fn build_stage_0() {
+        let config = Config { stage: Some(0), ..configure(&[], &[]) };
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+
+        let a = TargetSelection::from_user("A");
+        assert_eq!(
+            first(builder.cache.all::<compile::Std>()),
+            &[compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },]
+        );
+        assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+        assert_eq!(
+            first(builder.cache.all::<tool::Rustdoc>()),
+            // This is the beta rustdoc.
+            // Add an assert here to make sure this is the only rustdoc built.
+            &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }],
+        );
+        assert!(builder.cache.all::<compile::Rustc>().is_empty());
+    }
+
+    #[test]
+    fn doc_default() {
+        let mut config = configure(&[], &[]);
+        config.compiler_docs = true;
+        config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
+        let a = TargetSelection::from_user("A");
+
+        // error_index_generator uses stage 0 to share rustdoc artifacts with the
+        // rustdoc tool.
+        assert_eq!(
+            first(builder.cache.all::<doc::ErrorIndex>()),
+            &[doc::ErrorIndex { compiler: Compiler { host: a, stage: 0 }, target: a },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<tool::ErrorIndex>()),
+            &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 0 } }]
+        );
+        // docs should be built with the beta compiler, not with the stage0 artifacts.
+        // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to,
+        // not the one it was built by.
+        assert_eq!(
+            first(builder.cache.all::<tool::Rustdoc>()),
+            &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },]
+        );
+    }
 }
 
-//FIXME(mark-i-m): reinstate this test when things are fixed...
-//#[test]
-#[allow(dead_code)]
-fn test_docs() {
-    // Behavior of `x.py test` doing various documentation tests.
-    let mut config = configure(&[], &[]);
-    config.cmd = Subcommand::Test {
-        paths: vec![],
-        test_args: vec![],
-        rustc_args: vec![],
-        fail_fast: true,
-        doc_tests: DocTests::Yes,
-        bless: false,
-        compare_mode: None,
-        rustfix_coverage: false,
-        pass: None,
-    };
-    let build = Build::new(config);
-    let mut builder = Builder::new(&build);
-    builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
-    let a = TargetSelection::from_user("A");
-
-    // error_index_generator uses stage 1 to share rustdoc artifacts with the
-    // rustdoc tool.
-    assert_eq!(
-        first(builder.cache.all::<doc::ErrorIndex>()),
-        &[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },]
-    );
-    assert_eq!(
-        first(builder.cache.all::<tool::ErrorIndex>()),
-        &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
-    );
-    // Unfortunately rustdoc is built twice. Once from stage1 for compiletest
-    // (and other things), and once from stage0 for std crates. Ideally it
-    // would only be built once. If someone wants to fix this, it might be
-    // worth investigating if it would be possible to test std from stage1.
-    // Note that the stages here are +1 than what they actually are because
-    // Rustdoc::run swaps out the compiler with stage minus 1 if --stage is
-    // not 0.
-    assert_eq!(
-        first(builder.cache.all::<tool::Rustdoc>()),
-        &[
-            tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
-            tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },
-        ]
-    );
+mod dist {
+    use super::{first, Config};
+    use crate::builder::*;
+    use pretty_assertions::assert_eq;
+
+    fn configure(host: &[&str], target: &[&str]) -> Config {
+        Config { stage: Some(2), ..super::configure(host, target) }
+    }
+
+    #[test]
+    fn dist_baseline() {
+        let build = Build::new(configure(&[], &[]));
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+        let a = TargetSelection::from_user("A");
+
+        assert_eq!(first(builder.cache.all::<dist::Docs>()), &[dist::Docs { host: a },]);
+        assert_eq!(first(builder.cache.all::<dist::Mingw>()), &[dist::Mingw { host: a },]);
+        assert_eq!(
+            first(builder.cache.all::<dist::Rustc>()),
+            &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Std>()),
+            &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },]
+        );
+        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+        // Make sure rustdoc is only built once.
+        assert_eq!(
+            first(builder.cache.all::<tool::Rustdoc>()),
+            &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
+        );
+    }
+
+    #[test]
+    fn dist_with_targets() {
+        let build = Build::new(configure(&[], &["B"]));
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+
+        assert_eq!(
+            first(builder.cache.all::<dist::Docs>()),
+            &[dist::Docs { host: a }, dist::Docs { host: b },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Mingw>()),
+            &[dist::Mingw { host: a }, dist::Mingw { host: b },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Rustc>()),
+            &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Std>()),
+            &[
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
+            ]
+        );
+        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+    }
+
+    #[test]
+    fn dist_with_hosts() {
+        let build = Build::new(configure(&["B"], &[]));
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+
+        assert_eq!(
+            first(builder.cache.all::<dist::Docs>()),
+            &[dist::Docs { host: a }, dist::Docs { host: b },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Mingw>()),
+            &[dist::Mingw { host: a }, dist::Mingw { host: b },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Rustc>()),
+            &[
+                dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
+                dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
+            ]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Std>()),
+            &[
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+            ]
+        );
+        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+    }
+
+    #[test]
+    fn dist_only_cross_host() {
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+        let mut build = Build::new(configure(&["B"], &[]));
+        build.config.docs = false;
+        build.config.extended = true;
+        build.hosts = vec![b];
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+        assert_eq!(
+            first(builder.cache.all::<dist::Rustc>()),
+            &[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<compile::Rustc>()),
+            &[
+                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
+                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
+            ]
+        );
+    }
+
+    #[test]
+    fn dist_with_targets_and_hosts() {
+        let build = Build::new(configure(&["B"], &["C"]));
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+        let c = TargetSelection::from_user("C");
+
+        assert_eq!(
+            first(builder.cache.all::<dist::Docs>()),
+            &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Mingw>()),
+            &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Rustc>()),
+            &[
+                dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
+                dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
+            ]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Std>()),
+            &[
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+                dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
+            ]
+        );
+        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+    }
+
+    #[test]
+    fn dist_with_target_flag() {
+        let mut config = configure(&["B"], &["C"]);
+        config.skip_only_host_steps = true; // as-if --target=C was passed
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+        let c = TargetSelection::from_user("C");
+
+        assert_eq!(
+            first(builder.cache.all::<dist::Docs>()),
+            &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Mingw>()),
+            &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },]
+        );
+        assert_eq!(first(builder.cache.all::<dist::Rustc>()), &[]);
+        assert_eq!(
+            first(builder.cache.all::<dist::Std>()),
+            &[
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+                dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
+            ]
+        );
+        assert_eq!(first(builder.cache.all::<dist::Src>()), &[]);
+    }
+
+    #[test]
+    fn dist_with_same_targets_and_hosts() {
+        let build = Build::new(configure(&["B"], &["B"]));
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]);
+
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+
+        assert_eq!(
+            first(builder.cache.all::<dist::Docs>()),
+            &[dist::Docs { host: a }, dist::Docs { host: b },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Mingw>()),
+            &[dist::Mingw { host: a }, dist::Mingw { host: b },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Rustc>()),
+            &[
+                dist::Rustc { compiler: Compiler { host: a, stage: 2 } },
+                dist::Rustc { compiler: Compiler { host: b, stage: 2 } },
+            ]
+        );
+        assert_eq!(
+            first(builder.cache.all::<dist::Std>()),
+            &[
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+            ]
+        );
+        assert_eq!(first(builder.cache.all::<dist::Src>()), &[dist::Src]);
+        assert_eq!(
+            first(builder.cache.all::<compile::Std>()),
+            &[
+                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
+            ]
+        );
+        assert_eq!(
+            first(builder.cache.all::<compile::Assemble>()),
+            &[
+                compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
+                compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
+                compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
+                compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } },
+            ]
+        );
+    }
+
+    #[test]
+    fn build_all() {
+        let build = Build::new(configure(&["B"], &["C"]));
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(
+            &Builder::get_step_descriptions(Kind::Build),
+            &["src/rustc".into(), "library/std".into()],
+        );
+
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+        let c = TargetSelection::from_user("C");
+
+        assert_eq!(
+            first(builder.cache.all::<compile::Std>()),
+            &[
+                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
+                compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
+                compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
+                compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c },
+            ]
+        );
+        assert!(!builder.cache.all::<compile::Assemble>().is_empty());
+        assert_eq!(
+            first(builder.cache.all::<compile::Rustc>()),
+            &[
+                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
+                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
+                compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a },
+                compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: a },
+                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
+                compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b },
+                compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: b },
+            ]
+        );
+    }
+
+    #[test]
+    fn build_with_target_flag() {
+        let mut config = configure(&["B"], &["C"]);
+        config.skip_only_host_steps = true;
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
+
+        let a = TargetSelection::from_user("A");
+        let b = TargetSelection::from_user("B");
+        let c = TargetSelection::from_user("C");
+
+        assert_eq!(
+            first(builder.cache.all::<compile::Std>()),
+            &[
+                compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a },
+                compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a },
+                compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b },
+                compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b },
+                compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c },
+                compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c },
+            ]
+        );
+        assert_eq!(
+            first(builder.cache.all::<compile::Assemble>()),
+            &[
+                compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } },
+                compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } },
+                compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } },
+                compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } },
+            ]
+        );
+        assert_eq!(
+            first(builder.cache.all::<compile::Rustc>()),
+            &[
+                compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a },
+                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a },
+                compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b },
+            ]
+        );
+    }
+
+    #[test]
+    fn test_with_no_doc_stage0() {
+        let mut config = configure(&[], &[]);
+        config.stage = Some(0);
+        config.cmd = Subcommand::Test {
+            paths: vec!["library/std".into()],
+            test_args: vec![],
+            rustc_args: vec![],
+            fail_fast: true,
+            doc_tests: DocTests::No,
+            bless: false,
+            compare_mode: None,
+            rustfix_coverage: false,
+            pass: None,
+        };
+
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+
+        let host = TargetSelection::from_user("A");
+
+        builder.run_step_descriptions(
+            &[StepDescription::from::<test::Crate>()],
+            &["library/std".into()],
+        );
+
+        // Ensure we don't build any compiler artifacts.
+        assert!(!builder.cache.contains::<compile::Rustc>());
+        assert_eq!(
+            first(builder.cache.all::<test::Crate>()),
+            &[test::Crate {
+                compiler: Compiler { host, stage: 0 },
+                target: host,
+                mode: Mode::Std,
+                test_kind: test::TestKind::Test,
+                krate: INTERNER.intern_str("std"),
+            },]
+        );
+    }
+
+    #[test]
+    fn test_exclude() {
+        let mut config = configure(&[], &[]);
+        config.exclude = vec!["src/tools/tidy".into()];
+        config.cmd = Subcommand::Test {
+            paths: Vec::new(),
+            test_args: Vec::new(),
+            rustc_args: Vec::new(),
+            fail_fast: true,
+            doc_tests: DocTests::No,
+            bless: false,
+            compare_mode: None,
+            rustfix_coverage: false,
+            pass: None,
+        };
+
+        let build = Build::new(config);
+        let builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
+
+        // Ensure we have really excluded tidy
+        assert!(!builder.cache.contains::<test::Tidy>());
+
+        // Ensure other tests are not affected.
+        assert!(builder.cache.contains::<test::RustdocUi>());
+    }
+
+    #[test]
+    fn doc_ci() {
+        let mut config = configure(&[], &[]);
+        config.compiler_docs = true;
+        config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), &[]);
+        let a = TargetSelection::from_user("A");
+
+        // error_index_generator uses stage 1 to share rustdoc artifacts with the
+        // rustdoc tool.
+        assert_eq!(
+            first(builder.cache.all::<doc::ErrorIndex>()),
+            &[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<tool::ErrorIndex>()),
+            &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
+        );
+        // This is actually stage 1, but Rustdoc::run swaps out the compiler with
+        // stage minus 1 if --stage is not 0. Very confusing!
+        assert_eq!(
+            first(builder.cache.all::<tool::Rustdoc>()),
+            &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },]
+        );
+    }
+
+    //FIXME(mark-i-m): reinstate this test when things are fixed...
+    //#[test]
+    #[allow(dead_code)]
+    fn test_docs() {
+        // Behavior of `x.py test` doing various documentation tests.
+        let mut config = configure(&[], &[]);
+        config.cmd = Subcommand::Test {
+            paths: vec![],
+            test_args: vec![],
+            rustc_args: vec![],
+            fail_fast: true,
+            doc_tests: DocTests::Yes,
+            bless: false,
+            compare_mode: None,
+            rustfix_coverage: false,
+            pass: None,
+        };
+        let build = Build::new(config);
+        let mut builder = Builder::new(&build);
+        builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Test), &[]);
+        let a = TargetSelection::from_user("A");
+
+        // error_index_generator uses stage 1 to share rustdoc artifacts with the
+        // rustdoc tool.
+        assert_eq!(
+            first(builder.cache.all::<doc::ErrorIndex>()),
+            &[doc::ErrorIndex { compiler: Compiler { host: a, stage: 1 }, target: a },]
+        );
+        assert_eq!(
+            first(builder.cache.all::<tool::ErrorIndex>()),
+            &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }]
+        );
+        // Unfortunately rustdoc is built twice. Once from stage1 for compiletest
+        // (and other things), and once from stage0 for std crates. Ideally it
+        // would only be built once. If someone wants to fix this, it might be
+        // worth investigating if it would be possible to test std from stage1.
+        // Note that the stages here are +1 than what they actually are because
+        // Rustdoc::run swaps out the compiler with stage minus 1 if --stage is
+        // not 0.
+        assert_eq!(
+            first(builder.cache.all::<tool::Rustdoc>()),
+            &[
+                tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } },
+                tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },
+            ]
+        );
+    }
 }
diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs
index e3d1e005373..373e240cb8e 100644
--- a/src/bootstrap/compile.rs
+++ b/src/bootstrap/compile.rs
@@ -446,10 +446,10 @@ pub struct Rustc {
 impl Step for Rustc {
     type Output = ();
     const ONLY_HOSTS: bool = true;
-    const DEFAULT: bool = true;
+    const DEFAULT: bool = false;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.all_krates("rustc-main")
+        run.path("src/rustc")
     }
 
     fn make_run(run: RunConfig<'_>) {
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index d71f3170420..d64ca95d243 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -734,7 +734,7 @@ impl Config {
 
         let with_defaults = |debuginfo_level_specific: Option<u32>| {
             debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
-                2
+                1
             } else {
                 0
             })
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index a298b299667..56e4f0467cc 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -425,7 +425,7 @@ Arguments:
     This subcommand accepts a number of paths to tools to build and run. For
     example:
 
-        ./x.py run src/tool/expand-yaml-anchors
+        ./x.py run src/tools/expand-yaml-anchors
 
     At least a tool needs to be called.",
                 );
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index e5b9f27c258..1564cfb0619 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -9,8 +9,8 @@ endif
 BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py
 
 all:
-	$(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS)
-	$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) build --stage 2 $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) doc --stage 2 $(BOOTSTRAP_ARGS)
 
 help:
 	$(Q)echo 'Welcome to the rustbuild build system!'
@@ -31,17 +31,17 @@ rustc-stage2:
 
 docs: doc
 doc:
-	$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) doc --stage 2 $(BOOTSTRAP_ARGS)
 nomicon:
-	$(Q)$(BOOTSTRAP) doc src/doc/nomicon $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) doc --stage 2 src/doc/nomicon $(BOOTSTRAP_ARGS)
 book:
-	$(Q)$(BOOTSTRAP) doc src/doc/book $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) doc --stage 2 src/doc/book $(BOOTSTRAP_ARGS)
 standalone-docs:
-	$(Q)$(BOOTSTRAP) doc src/doc $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) doc --stage 2 src/doc $(BOOTSTRAP_ARGS)
 check:
-	$(Q)$(BOOTSTRAP) test $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) test --stage 2 $(BOOTSTRAP_ARGS)
 check-aux:
-	$(Q)$(BOOTSTRAP) test \
+	$(Q)$(BOOTSTRAP) test --stage 2 \
 		src/tools/cargo \
 		src/tools/cargotest \
 		$(BOOTSTRAP_ARGS)
@@ -51,18 +51,18 @@ dist:
 	$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
 distcheck:
 	$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
-	$(Q)$(BOOTSTRAP) test distcheck $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) test --stage 2 distcheck $(BOOTSTRAP_ARGS)
 install:
 	$(Q)$(BOOTSTRAP) install $(BOOTSTRAP_ARGS)
 tidy:
-	$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
+	$(Q)$(BOOTSTRAP) test --stage 2 src/tools/tidy $(BOOTSTRAP_ARGS)
 prepare:
-	$(Q)$(BOOTSTRAP) build nonexistent/path/to/trigger/cargo/metadata
+	$(Q)$(BOOTSTRAP) build --stage 2 nonexistent/path/to/trigger/cargo/metadata
 
 check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
-	$(Q)$(BOOTSTRAP) test --target arm-linux-androideabi
+	$(Q)$(BOOTSTRAP) test --stage 2 --target arm-linux-androideabi
 check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu:
-	$(Q)$(BOOTSTRAP) test --target x86_64-unknown-linux-musl
+	$(Q)$(BOOTSTRAP) test --stage 2 --target x86_64-unknown-linux-musl
 
 TESTS_IN_2 := \
 	src/test/ui \
@@ -70,18 +70,18 @@ TESTS_IN_2 := \
 	src/tools/linkchecker
 
 ci-subset-1:
-	$(Q)$(BOOTSTRAP) test $(TESTS_IN_2:%=--exclude %)
+	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2:%=--exclude %)
 ci-subset-2:
-	$(Q)$(BOOTSTRAP) test $(TESTS_IN_2)
+	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2)
 
 TESTS_IN_MINGW_2 := \
 	src/test/ui \
 	src/test/compile-fail
 
 ci-mingw-subset-1:
-	$(Q)$(BOOTSTRAP) test $(TESTS_IN_MINGW_2:%=--exclude %)
+	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
 ci-mingw-subset-2:
-	$(Q)$(BOOTSTRAP) test $(TESTS_IN_MINGW_2)
+	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2)
 
 
 .PHONY: dist