Skip to content

Commit 2a93942

Browse files
committed
prepare_tool_cargo: add support for a miri-test mode, and use it in the cargo-miri smoke test and Miri sysroot build
1 parent fd7909a commit 2a93942

File tree

4 files changed

+85
-77
lines changed

4 files changed

+85
-77
lines changed

src/bootstrap/src/core/build_steps/run.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ impl Step for ReplaceVersionPlaceholder {
121121

122122
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
123123
pub struct Miri {
124-
stage: u32,
125124
host: TargetSelection,
126125
target: TargetSelection,
127126
}
@@ -135,22 +134,17 @@ impl Step for Miri {
135134
}
136135

137136
fn make_run(run: RunConfig<'_>) {
138-
run.builder.ensure(Miri {
139-
stage: run.builder.top_stage,
140-
host: run.build_triple(),
141-
target: run.target,
142-
});
137+
run.builder.ensure(Miri { host: run.build_triple(), target: run.target });
143138
}
144139

145140
fn run(self, builder: &Builder<'_>) {
146-
let stage = self.stage;
141+
let stage = builder.top_stage;
147142
let host = self.host;
148143
let target = self.target;
149144
let compiler = builder.compiler(stage, host);
150145

151-
let miri =
152-
builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
153-
let miri_sysroot = test::Miri::build_miri_sysroot(builder, compiler, &miri, target);
146+
let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
147+
let miri_sysroot = test::Miri::build_miri_sysroot(builder, compiler_std, target);
154148

155149
// # Run miri.
156150
// Running it via `cargo run` as that figures out the right dylib path.

src/bootstrap/src/core/build_steps/test.rs

+40-60
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,6 @@ impl Step for RustDemangler {
493493

494494
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
495495
pub struct Miri {
496-
stage: u32,
497496
host: TargetSelection,
498497
target: TargetSelection,
499498
}
@@ -502,41 +501,31 @@ impl Miri {
502501
/// Run `cargo miri setup` for the given target, return where the Miri sysroot was put.
503502
pub fn build_miri_sysroot(
504503
builder: &Builder<'_>,
505-
compiler: Compiler,
506-
miri: &Path,
504+
compiler_std: Compiler,
507505
target: TargetSelection,
508506
) -> String {
509-
let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysroot");
510-
let mut cargo = tool::prepare_tool_cargo(
507+
let miri_sysroot = builder.out.join(compiler_std.host.triple).join("miri-sysroot");
508+
let mut cargo = builder::Cargo::new(
511509
builder,
512-
compiler,
513-
Mode::ToolRustc,
514-
compiler.host,
515-
"run",
516-
"src/tools/miri/cargo-miri",
517-
SourceType::InTree,
518-
&[],
510+
compiler_std, // this is compiler+1; cargo_miri_cmd will do -1 again
511+
Mode::Std,
512+
SourceType::Submodule,
513+
target,
514+
"miri-setup",
519515
);
520-
cargo.add_rustc_lib_path(builder);
521-
cargo.arg("--").arg("miri").arg("setup");
522-
cargo.arg("--target").arg(target.rustc_target_arg());
523516

524517
// Tell `cargo miri setup` where to find the sources.
525518
cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
526-
// Tell it where to find Miri.
527-
cargo.env("MIRI", miri);
528519
// Tell it where to put the sysroot.
529520
cargo.env("MIRI_SYSROOT", &miri_sysroot);
530-
// Debug things.
531-
cargo.env("RUST_BACKTRACE", "1");
532521

533522
let mut cargo = Command::from(cargo);
534523
let _guard = builder.msg(
535524
Kind::Build,
536-
compiler.stage + 1,
525+
compiler_std.stage,
537526
"miri sysroot",
538-
compiler.host,
539-
compiler.host,
527+
compiler_std.host,
528+
compiler_std.host,
540529
);
541530
builder.run(&mut cargo);
542531

@@ -574,16 +563,12 @@ impl Step for Miri {
574563
}
575564

576565
fn make_run(run: RunConfig<'_>) {
577-
run.builder.ensure(Miri {
578-
stage: run.builder.top_stage,
579-
host: run.build_triple(),
580-
target: run.target,
581-
});
566+
run.builder.ensure(Miri { host: run.build_triple(), target: run.target });
582567
}
583568

584569
/// Runs `cargo test` for miri.
585570
fn run(self, builder: &Builder<'_>) {
586-
let stage = self.stage;
571+
let stage = builder.top_stage;
587572
let host = self.host;
588573
let target = self.target;
589574
let compiler = builder.compiler(stage, host);
@@ -592,18 +577,15 @@ impl Step for Miri {
592577
let compiler_std = builder.compiler(if stage < 2 { stage + 1 } else { stage }, host);
593578

594579
let miri =
595-
builder.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() });
596-
let _cargo_miri = builder.ensure(tool::CargoMiri {
597-
compiler,
598-
target: self.host,
599-
extra_features: Vec::new(),
600-
});
580+
builder.ensure(tool::Miri { compiler, target: host, extra_features: Vec::new() });
581+
// the ui tests also assume cargo-miri has been built
582+
builder.ensure(tool::CargoMiri { compiler, target: host, extra_features: Vec::new() });
601583
// The stdlib we need might be at a different stage. And just asking for the
602584
// sysroot does not seem to populate it, so we do that first.
603585
builder.ensure(compile::Std::new(compiler_std, host));
604586
let sysroot = builder.sysroot(compiler_std);
605587
// We also need a Miri sysroot.
606-
let miri_sysroot = Miri::build_miri_sysroot(builder, compiler, &miri, target);
588+
let miri_sysroot = Miri::build_miri_sysroot(builder, compiler_std, target);
607589

608590
// # Run `cargo test`.
609591
let mut cargo = tool::prepare_tool_cargo(
@@ -616,10 +598,13 @@ impl Step for Miri {
616598
SourceType::InTree,
617599
&[],
618600
);
619-
let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, target);
620601

621602
cargo.add_rustc_lib_path(builder);
622603

604+
// We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test
605+
// harness and therefore do not understand the flags added by `add_flags_and_try_run_test`.
606+
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
607+
623608
// miri tests need to know about the stage sysroot
624609
cargo.env("MIRI_SYSROOT", &miri_sysroot);
625610
cargo.env("MIRI_HOST_SYSROOT", &sysroot);
@@ -632,10 +617,8 @@ impl Step for Miri {
632617
// Set the target.
633618
cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
634619

635-
// This can NOT be `run_cargo_test` since the Miri test runner
636-
// does not understand the flags added by `add_flags_and_try_run_test`.
637-
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
638620
{
621+
let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, target);
639622
let _time = helpers::timeit(builder);
640623
builder.run(&mut cargo);
641624
}
@@ -650,8 +633,14 @@ impl Step for Miri {
650633
// Optimizations can change error locations and remove UB so don't run `fail` tests.
651634
cargo.args(["tests/pass", "tests/panic"]);
652635

653-
let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder);
654636
{
637+
let _guard = builder.msg_sysroot_tool(
638+
Kind::Test,
639+
compiler.stage,
640+
"miri (mir-opt-level 4)",
641+
host,
642+
target,
643+
);
655644
let _time = helpers::timeit(builder);
656645
builder.run(&mut cargo);
657646
}
@@ -660,28 +649,20 @@ impl Step for Miri {
660649
// # Run `cargo miri test`.
661650
// This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures
662651
// that we get the desired output), but that is sufficient to make sure that the libtest harness
663-
// itself executes properly under Miri.
652+
// itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode.
653+
// Everything here needs `compiler_std` to be actually testing the Miri in the current stage.
664654
let mut cargo = tool::prepare_tool_cargo(
665655
builder,
666-
compiler,
667-
Mode::ToolRustc,
668-
host,
669-
"run",
670-
"src/tools/miri/cargo-miri",
656+
compiler_std, // this is compiler+1; cargo_miri_cmd will do -1 again
657+
Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test!
658+
target,
659+
"miri-test",
660+
"src/tools/miri/test-cargo-miri",
671661
SourceType::Submodule,
672662
&[],
673663
);
674-
cargo.add_rustc_lib_path(builder);
675-
cargo.arg("--").arg("miri").arg("test");
676-
if builder.config.locked_deps {
677-
cargo.arg("--locked");
678-
}
679-
cargo
680-
.arg("--manifest-path")
681-
.arg(builder.src.join("src/tools/miri/test-cargo-miri/Cargo.toml"));
682-
cargo.arg("--target").arg(target.rustc_target_arg());
683664

684-
// `prepare_tool_cargo` sets RUSTDOC to the bootstrap wrapper and RUSTDOC_REAL to a dummy path as this is a "run", not a "test".
665+
// `prepare_tool_cargo` sets RUSTDOC to the bootstrap wrapper and RUSTDOC_REAL to a dummy path as this is a "miri", not a "test".
685666
// Also, we want the rustdoc from the "next" stage for the same reason that we build a std from the next stage.
686667
// So let's just set that here, and bypass bootstrap's RUSTDOC (just like cargo-miri already ignores bootstrap's RUSTC_WRAPPER).
687668
if builder.doc_tests != DocTests::No {
@@ -697,17 +678,16 @@ impl Step for Miri {
697678
}
698679
}
699680

700-
// Tell `cargo miri` where to find things.
681+
// Tell `cargo miri` where to find the sysroots.
701682
cargo.env("MIRI_SYSROOT", &miri_sysroot);
702683
cargo.env("MIRI_HOST_SYSROOT", sysroot);
703-
cargo.env("MIRI", &miri);
704-
// Debug things.
705-
cargo.env("RUST_BACKTRACE", "1");
706684

707685
// Finally, pass test-args and run everything.
708686
cargo.arg("--").args(builder.config.test_args());
709687
let mut cargo = Command::from(cargo);
710688
{
689+
let _guard =
690+
builder.msg_sysroot_tool(Kind::Test, compiler.stage, "cargo-miri", host, target);
711691
let _time = helpers::timeit(builder);
712692
builder.run(&mut cargo);
713693
}

src/bootstrap/src/core/builder.rs

+39-7
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,30 @@ impl<'a> Builder<'a> {
12531253
cmd
12541254
}
12551255

1256+
pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> Command {
1257+
assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0");
1258+
let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build);
1259+
1260+
let miri = self.ensure(tool::Miri {
1261+
compiler: build_compiler,
1262+
target: self.build.build,
1263+
extra_features: Vec::new(),
1264+
});
1265+
let cargo_miri = self.ensure(tool::CargoMiri {
1266+
compiler: build_compiler,
1267+
target: self.build.build,
1268+
extra_features: Vec::new(),
1269+
});
1270+
// Invoke cargo-miri, make sure we can find miri and cargo.
1271+
let mut cmd = Command::new(cargo_miri);
1272+
cmd.env("MIRI", &miri);
1273+
cmd.env("CARGO", &self.initial_cargo);
1274+
// Need to add the run_compiler libs. Not entirely sure why that has to be one stage up from
1275+
// what Miri was built for.
1276+
self.add_rustc_lib_path(run_compiler, &mut cmd);
1277+
cmd
1278+
}
1279+
12561280
pub fn rustdoc_cmd(&self, compiler: Compiler) -> Command {
12571281
let mut cmd = Command::new(self.bootstrap_out.join("rustdoc"));
12581282
cmd.env("RUSTC_STAGE", compiler.stage.to_string())
@@ -1296,18 +1320,24 @@ impl<'a> Builder<'a> {
12961320
target: TargetSelection,
12971321
cmd: &str,
12981322
) -> Command {
1299-
let mut cargo = if cmd == "clippy" {
1300-
self.cargo_clippy_cmd(compiler)
1323+
let mut cargo;
1324+
if cmd == "clippy" {
1325+
cargo = self.cargo_clippy_cmd(compiler);
1326+
cargo.arg(cmd);
1327+
} else if let Some(subcmd) = cmd.strip_prefix("miri-") {
1328+
cargo = self.cargo_miri_cmd(compiler);
1329+
cargo.arg("miri").arg(subcmd);
13011330
} else {
1302-
Command::new(&self.initial_cargo)
1303-
};
1331+
cargo = Command::new(&self.initial_cargo);
1332+
cargo.arg(cmd);
1333+
}
13041334

13051335
// Run cargo from the source root so it can find .cargo/config.
13061336
// This matters when using vendoring and the working directory is outside the repository.
13071337
cargo.current_dir(&self.src);
13081338

13091339
let out_dir = self.stage_out(compiler, mode);
1310-
cargo.env("CARGO_TARGET_DIR", &out_dir).arg(cmd);
1340+
cargo.env("CARGO_TARGET_DIR", &out_dir);
13111341

13121342
// Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
13131343
// from out of tree it shouldn't matter, since x.py is only used for
@@ -1337,7 +1367,8 @@ impl<'a> Builder<'a> {
13371367

13381368
if self.config.rust_optimize.is_release() {
13391369
// FIXME: cargo bench/install do not accept `--release`
1340-
if cmd != "bench" && cmd != "install" {
1370+
// and miri doesn't want it
1371+
if cmd != "bench" && cmd != "install" && !cmd.starts_with("miri-") {
13411372
cargo.arg("--release");
13421373
}
13431374
}
@@ -1353,7 +1384,8 @@ impl<'a> Builder<'a> {
13531384
/// Cargo. This cargo will be configured to use `compiler` as the actual
13541385
/// rustc compiler, its output will be scoped by `mode`'s output directory,
13551386
/// it will pass the `--target` flag for the specified `target`, and will be
1356-
/// executing the Cargo command `cmd`.
1387+
/// executing the Cargo command `cmd`. `cmd` can be `miri-cmd` for commands
1388+
/// to be run with Miri.
13571389
fn cargo(
13581390
&self,
13591391
compiler: Compiler,

src/bootstrap/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ pub enum Mode {
250250
/// directory. This is for miscellaneous sets of tools that are built
251251
/// using the bootstrap stage0 compiler in its entirety (target libraries
252252
/// and all). Typically these tools compile with stable Rust.
253+
///
254+
/// Only works for stage 0.
253255
ToolBootstrap,
254256

255257
/// Build a tool which uses the locally built std, placing output in the

0 commit comments

Comments
 (0)