Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 32 additions & 15 deletions src/bootstrap/src/core/build_steps/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

use std::path::PathBuf;

use build_helper::exit;
use clap_complete::{Generator, shells};

use crate::core::build_steps::dist::distdir;
use crate::core::build_steps::test;
use crate::core::build_steps::tool::{self, RustcPrivateCompilers, SourceType, Tool};
use crate::core::build_steps::vendor::{Vendor, default_paths_to_vendor};
use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step, StepMetadata};
use crate::core::config::TargetSelection;
use crate::core::config::flags::get_completion;
use crate::utils::exec::command;
Expand Down Expand Up @@ -100,8 +101,17 @@ impl Step for ReplaceVersionPlaceholder {
}
}

/// Invoke the Miri tool on a specified file.
///
/// Note that Miri always executed on the host, as it is an interpreter.
/// That means that `x run miri --target FOO` will build miri for the host,
/// prepare a miri sysroot for the target `FOO` and then execute miri with
/// the target `FOO`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Miri {
/// The build compiler that will build miri and the target compiler to which miri links.
compilers: RustcPrivateCompilers,
/// The target which will miri interpret.
target: TargetSelection,
}

Expand All @@ -113,14 +123,9 @@ impl Step for Miri {
}

fn make_run(run: RunConfig<'_>) {
run.builder.ensure(Miri { target: run.target });
}

fn run(self, builder: &Builder<'_>) {
let host = builder.build.host_target;
let target = self.target;
let builder = run.builder;

// `x run` uses stage 0 by default but miri does not work well with stage 0.
// `x run` uses stage 0 by default, but miri does not work well with stage 0.
// Change the stage to 1 if it's not set explicitly.
let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 {
builder.top_stage
Expand All @@ -129,14 +134,22 @@ impl Step for Miri {
};

if stage == 0 {
eprintln!("miri cannot be run at stage 0");
std::process::exit(1);
eprintln!("ERROR: miri cannot be run at stage 0");
exit!(1);
}

// This compiler runs on the host, we'll just use it for the target.
let compilers = RustcPrivateCompilers::new(builder, stage, target);
let miri_build = builder.ensure(tool::Miri::from_compilers(compilers));
let host_compiler = miri_build.build_compiler;
// Miri always runs on the host, because it can interpret code for any target
let compilers = RustcPrivateCompilers::new(builder, stage, builder.host_target);

run.builder.ensure(Miri { compilers, target: run.target });
}

fn run(self, builder: &Builder<'_>) {
let host = builder.build.host_target;
let compilers = self.compilers;
let target = self.target;

builder.ensure(tool::Miri::from_compilers(compilers));

// Get a target sysroot for Miri.
let miri_sysroot =
Expand All @@ -147,7 +160,7 @@ impl Step for Miri {
// add_rustc_lib_path does not add the path that contains librustc_driver-<...>.so.
let mut miri = tool::prepare_tool_cargo(
builder,
host_compiler,
compilers.build_compiler(),
Mode::ToolRustc,
host,
Kind::Run,
Expand All @@ -167,6 +180,10 @@ impl Step for Miri {

miri.into_cmd().run(builder);
}

fn metadata(&self) -> Option<StepMetadata> {
Some(StepMetadata::run("miri", self.target).built_by(self.compilers.build_compiler()))
}
}

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
Expand Down
4 changes: 4 additions & 0 deletions src/bootstrap/src/core/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ impl StepMetadata {
Self::new(name, target, Kind::Test)
}

pub fn run(name: &str, target: TargetSelection) -> Self {
Self::new(name, target, Kind::Run)
}

fn new(name: &str, target: TargetSelection, kind: Kind) -> Self {
Self { name: name.to_string(), kind, target, built_by: None, stage: None, metadata: None }
}
Expand Down
18 changes: 18 additions & 0 deletions src/bootstrap/src/core/builder/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2372,6 +2372,24 @@ mod snapshot {
[dist] src <>
");
}

// Check that `x run miri --target FOO` actually builds miri for the host.
#[test]
fn run_miri() {
let ctx = TestCtx::new();
insta::assert_snapshot!(
ctx.config("run")
.path("miri")
.stage(1)
.targets(&[TEST_TRIPLE_1])
.render_steps(), @r"
[build] llvm <host>
[build] rustc 0 <host> -> rustc 1 <host>
[build] rustc 0 <host> -> miri 1 <host>
[build] rustc 0 <host> -> cargo-miri 1 <host>
[run] rustc 0 <host> -> miri 1 <target1>
");
}
}

struct ExecutedSteps {
Expand Down
4 changes: 2 additions & 2 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -961,8 +961,8 @@ impl Config {
Subcommand::Dist => flags_stage.or(build_dist_stage).unwrap_or(2),
Subcommand::Install => flags_stage.or(build_install_stage).unwrap_or(2),
Subcommand::Perf { .. } => flags_stage.unwrap_or(1),
// 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.
// Most of the run commands execute bootstrap tools, which don't depend on the compiler.
// Other commands listed here should always use bootstrap tools.
Subcommand::Clean { .. }
| Subcommand::Run { .. }
| Subcommand::Setup { .. }
Expand Down
Loading