mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-19 11:07:32 +00:00
Rollup merge of #104046 - RalfJung:run-miri-run, r=oli-obk
bootstrap: add support for running Miri on a file This enables: ``` ./x.py run src/tools/miri --stage 0 --args src/tools/miri/tests/pass/hello.rs ``` That can be super helpful for debugging. Also avoid sharing the Miri sysroot dir with a system-wide (rustup-managed) installation of Miri. Fixes https://github.com/rust-lang/rust/issues/76666
This commit is contained in:
commit
7124590dcc
@ -755,6 +755,7 @@ impl<'a> Builder<'a> {
|
|||||||
run::BuildManifest,
|
run::BuildManifest,
|
||||||
run::BumpStage0,
|
run::BumpStage0,
|
||||||
run::ReplaceVersionPlaceholder,
|
run::ReplaceVersionPlaceholder,
|
||||||
|
run::Miri,
|
||||||
),
|
),
|
||||||
// These commands either don't use paths, or they're special-cased in Build::build()
|
// These commands either don't use paths, or they're special-cased in Build::build()
|
||||||
Kind::Clean | Kind::Format | Kind::Setup => vec![],
|
Kind::Clean | Kind::Format | Kind::Setup => vec![],
|
||||||
@ -818,7 +819,7 @@ impl<'a> Builder<'a> {
|
|||||||
Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
|
Subcommand::Bench { ref paths, .. } => (Kind::Bench, &paths[..]),
|
||||||
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
|
Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]),
|
||||||
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
|
Subcommand::Install { ref paths } => (Kind::Install, &paths[..]),
|
||||||
Subcommand::Run { ref paths } => (Kind::Run, &paths[..]),
|
Subcommand::Run { ref paths, .. } => (Kind::Run, &paths[..]),
|
||||||
Subcommand::Format { .. } => (Kind::Format, &[][..]),
|
Subcommand::Format { .. } => (Kind::Format, &[][..]),
|
||||||
Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
|
Subcommand::Clean { .. } | Subcommand::Setup { .. } => {
|
||||||
panic!()
|
panic!()
|
||||||
|
@ -140,6 +140,7 @@ pub enum Subcommand {
|
|||||||
},
|
},
|
||||||
Run {
|
Run {
|
||||||
paths: Vec<PathBuf>,
|
paths: Vec<PathBuf>,
|
||||||
|
args: Vec<String>,
|
||||||
},
|
},
|
||||||
Setup {
|
Setup {
|
||||||
profile: Profile,
|
profile: Profile,
|
||||||
@ -342,6 +343,9 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`",
|
|||||||
Kind::Format => {
|
Kind::Format => {
|
||||||
opts.optflag("", "check", "check formatting instead of applying.");
|
opts.optflag("", "check", "check formatting instead of applying.");
|
||||||
}
|
}
|
||||||
|
Kind::Run => {
|
||||||
|
opts.optmulti("", "args", "arguments for the tool", "ARGS");
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -613,7 +617,7 @@ Arguments:
|
|||||||
println!("\nrun requires at least a path!\n");
|
println!("\nrun requires at least a path!\n");
|
||||||
usage(1, &opts, verbose, &subcommand_help);
|
usage(1, &opts, verbose, &subcommand_help);
|
||||||
}
|
}
|
||||||
Subcommand::Run { paths }
|
Subcommand::Run { paths, args: matches.opt_strs("args") }
|
||||||
}
|
}
|
||||||
Kind::Setup => {
|
Kind::Setup => {
|
||||||
let profile = if paths.len() > 1 {
|
let profile = if paths.len() > 1 {
|
||||||
@ -721,16 +725,12 @@ impl Subcommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_args(&self) -> Vec<&str> {
|
pub fn test_args(&self) -> Vec<&str> {
|
||||||
let mut args = vec![];
|
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
|
Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
|
||||||
args.extend(test_args.iter().flat_map(|s| s.split_whitespace()))
|
test_args.iter().flat_map(|s| s.split_whitespace()).collect()
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => vec![],
|
||||||
}
|
}
|
||||||
|
|
||||||
args
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rustc_args(&self) -> Vec<&str> {
|
pub fn rustc_args(&self) -> Vec<&str> {
|
||||||
@ -738,7 +738,16 @@ impl Subcommand {
|
|||||||
Subcommand::Test { ref rustc_args, .. } => {
|
Subcommand::Test { ref rustc_args, .. } => {
|
||||||
rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
|
rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
|
||||||
}
|
}
|
||||||
_ => Vec::new(),
|
_ => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args(&self) -> Vec<&str> {
|
||||||
|
match *self {
|
||||||
|
Subcommand::Run { ref args, .. } => {
|
||||||
|
args.iter().flat_map(|s| s.split_whitespace()).collect()
|
||||||
|
}
|
||||||
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
|
|
||||||
use crate::dist::distdir;
|
|
||||||
use crate::tool::Tool;
|
|
||||||
use crate::util::output;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use crate::builder::{Builder, RunConfig, ShouldRun, Step};
|
||||||
|
use crate::config::TargetSelection;
|
||||||
|
use crate::dist::distdir;
|
||||||
|
use crate::test;
|
||||||
|
use crate::tool::{self, SourceType, Tool};
|
||||||
|
use crate::util::output;
|
||||||
|
use crate::Mode;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct ExpandYamlAnchors;
|
pub struct ExpandYamlAnchors;
|
||||||
|
|
||||||
@ -125,3 +129,63 @@ impl Step for ReplaceVersionPlaceholder {
|
|||||||
builder.run(&mut cmd);
|
builder.run(&mut cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Miri {
|
||||||
|
stage: u32,
|
||||||
|
host: TargetSelection,
|
||||||
|
target: TargetSelection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Step for Miri {
|
||||||
|
type Output = ();
|
||||||
|
const ONLY_HOSTS: bool = false;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.path("src/tools/miri")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
run.builder.ensure(Miri {
|
||||||
|
stage: run.builder.top_stage,
|
||||||
|
host: run.build_triple(),
|
||||||
|
target: run.target,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, builder: &Builder<'_>) {
|
||||||
|
let stage = self.stage;
|
||||||
|
let host = self.host;
|
||||||
|
let target = self.target;
|
||||||
|
let compiler = builder.compiler(stage, host);
|
||||||
|
|
||||||
|
let miri = builder
|
||||||
|
.ensure(tool::Miri { compiler, target: self.host, extra_features: Vec::new() })
|
||||||
|
.expect("in-tree tool");
|
||||||
|
let miri_sysroot = test::Miri::build_miri_sysroot(builder, compiler, &miri, target);
|
||||||
|
|
||||||
|
// # Run miri.
|
||||||
|
// Running it via `cargo run` as that figures out the right dylib path.
|
||||||
|
// add_rustc_lib_path does not add the path that contains librustc_driver-<...>.so.
|
||||||
|
let mut miri = tool::prepare_tool_cargo(
|
||||||
|
builder,
|
||||||
|
compiler,
|
||||||
|
Mode::ToolRustc,
|
||||||
|
host,
|
||||||
|
"run",
|
||||||
|
"src/tools/miri",
|
||||||
|
SourceType::InTree,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
miri.add_rustc_lib_path(builder, compiler);
|
||||||
|
// Forward arguments.
|
||||||
|
miri.arg("--").arg("--target").arg(target.rustc_target_arg());
|
||||||
|
miri.args(builder.config.cmd.args());
|
||||||
|
|
||||||
|
// miri tests need to know about the stage sysroot
|
||||||
|
miri.env("MIRI_SYSROOT", &miri_sysroot);
|
||||||
|
|
||||||
|
let mut miri = Command::from(miri);
|
||||||
|
builder.run(&mut miri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -465,6 +465,66 @@ pub struct Miri {
|
|||||||
target: TargetSelection,
|
target: TargetSelection,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Miri {
|
||||||
|
/// Run `cargo miri setup` for the given target, return where the Miri sysroot was put.
|
||||||
|
pub fn build_miri_sysroot(
|
||||||
|
builder: &Builder<'_>,
|
||||||
|
compiler: Compiler,
|
||||||
|
miri: &Path,
|
||||||
|
target: TargetSelection,
|
||||||
|
) -> String {
|
||||||
|
let miri_sysroot = builder.out.join(compiler.host.triple).join("miri-sysrot");
|
||||||
|
let mut cargo = tool::prepare_tool_cargo(
|
||||||
|
builder,
|
||||||
|
compiler,
|
||||||
|
Mode::ToolRustc,
|
||||||
|
compiler.host,
|
||||||
|
"run",
|
||||||
|
"src/tools/miri/cargo-miri",
|
||||||
|
SourceType::InTree,
|
||||||
|
&[],
|
||||||
|
);
|
||||||
|
cargo.add_rustc_lib_path(builder, compiler);
|
||||||
|
cargo.arg("--").arg("miri").arg("setup");
|
||||||
|
cargo.arg("--target").arg(target.rustc_target_arg());
|
||||||
|
|
||||||
|
// Tell `cargo miri setup` where to find the sources.
|
||||||
|
cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
|
||||||
|
// Tell it where to find Miri.
|
||||||
|
cargo.env("MIRI", &miri);
|
||||||
|
// Tell it where to put the sysroot.
|
||||||
|
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
||||||
|
// Debug things.
|
||||||
|
cargo.env("RUST_BACKTRACE", "1");
|
||||||
|
|
||||||
|
let mut cargo = Command::from(cargo);
|
||||||
|
builder.run(&mut cargo);
|
||||||
|
|
||||||
|
// # Determine where Miri put its sysroot.
|
||||||
|
// To this end, we run `cargo miri setup --print-sysroot` and capture the output.
|
||||||
|
// (We do this separately from the above so that when the setup actually
|
||||||
|
// happens we get some output.)
|
||||||
|
// We re-use the `cargo` from above.
|
||||||
|
cargo.arg("--print-sysroot");
|
||||||
|
|
||||||
|
// FIXME: Is there a way in which we can re-use the usual `run` helpers?
|
||||||
|
if builder.config.dry_run {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
builder.verbose(&format!("running: {:?}", cargo));
|
||||||
|
let out =
|
||||||
|
cargo.output().expect("We already ran `cargo miri setup` before and that worked");
|
||||||
|
assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
|
||||||
|
// Output is "<sysroot>\n".
|
||||||
|
let stdout = String::from_utf8(out.stdout)
|
||||||
|
.expect("`cargo miri setup` stdout is not valid UTF-8");
|
||||||
|
let sysroot = stdout.trim_end();
|
||||||
|
builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
|
||||||
|
sysroot.to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Step for Miri {
|
impl Step for Miri {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
const ONLY_HOSTS: bool = false;
|
const ONLY_HOSTS: bool = false;
|
||||||
@ -501,54 +561,8 @@ impl Step for Miri {
|
|||||||
// sysroot does not seem to populate it, so we do that first.
|
// sysroot does not seem to populate it, so we do that first.
|
||||||
builder.ensure(compile::Std::new(compiler_std, host));
|
builder.ensure(compile::Std::new(compiler_std, host));
|
||||||
let sysroot = builder.sysroot(compiler_std);
|
let sysroot = builder.sysroot(compiler_std);
|
||||||
|
// We also need a Miri sysroot.
|
||||||
// # Run `cargo miri setup` for the given target.
|
let miri_sysroot = Miri::build_miri_sysroot(builder, compiler, &miri, target);
|
||||||
let mut cargo = tool::prepare_tool_cargo(
|
|
||||||
builder,
|
|
||||||
compiler,
|
|
||||||
Mode::ToolRustc,
|
|
||||||
host,
|
|
||||||
"run",
|
|
||||||
"src/tools/miri/cargo-miri",
|
|
||||||
SourceType::InTree,
|
|
||||||
&[],
|
|
||||||
);
|
|
||||||
cargo.add_rustc_lib_path(builder, compiler);
|
|
||||||
cargo.arg("--").arg("miri").arg("setup");
|
|
||||||
cargo.arg("--target").arg(target.rustc_target_arg());
|
|
||||||
|
|
||||||
// Tell `cargo miri setup` where to find the sources.
|
|
||||||
cargo.env("MIRI_LIB_SRC", builder.src.join("library"));
|
|
||||||
// Tell it where to find Miri.
|
|
||||||
cargo.env("MIRI", &miri);
|
|
||||||
// Debug things.
|
|
||||||
cargo.env("RUST_BACKTRACE", "1");
|
|
||||||
|
|
||||||
let mut cargo = Command::from(cargo);
|
|
||||||
builder.run(&mut cargo);
|
|
||||||
|
|
||||||
// # Determine where Miri put its sysroot.
|
|
||||||
// To this end, we run `cargo miri setup --print-sysroot` and capture the output.
|
|
||||||
// (We do this separately from the above so that when the setup actually
|
|
||||||
// happens we get some output.)
|
|
||||||
// We re-use the `cargo` from above.
|
|
||||||
cargo.arg("--print-sysroot");
|
|
||||||
|
|
||||||
// FIXME: Is there a way in which we can re-use the usual `run` helpers?
|
|
||||||
let miri_sysroot = if builder.config.dry_run {
|
|
||||||
String::new()
|
|
||||||
} else {
|
|
||||||
builder.verbose(&format!("running: {:?}", cargo));
|
|
||||||
let out =
|
|
||||||
cargo.output().expect("We already ran `cargo miri setup` before and that worked");
|
|
||||||
assert!(out.status.success(), "`cargo miri setup` returned with non-0 exit code");
|
|
||||||
// Output is "<sysroot>\n".
|
|
||||||
let stdout = String::from_utf8(out.stdout)
|
|
||||||
.expect("`cargo miri setup` stdout is not valid UTF-8");
|
|
||||||
let sysroot = stdout.trim_end();
|
|
||||||
builder.verbose(&format!("`cargo miri setup --print-sysroot` said: {:?}", sysroot));
|
|
||||||
sysroot.to_owned()
|
|
||||||
};
|
|
||||||
|
|
||||||
// # Run `cargo test`.
|
// # Run `cargo test`.
|
||||||
let mut cargo = tool::prepare_tool_cargo(
|
let mut cargo = tool::prepare_tool_cargo(
|
||||||
@ -566,7 +580,6 @@ impl Step for Miri {
|
|||||||
// miri tests need to know about the stage sysroot
|
// miri tests need to know about the stage sysroot
|
||||||
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
||||||
cargo.env("MIRI_HOST_SYSROOT", sysroot);
|
cargo.env("MIRI_HOST_SYSROOT", sysroot);
|
||||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
|
||||||
cargo.env("MIRI", &miri);
|
cargo.env("MIRI", &miri);
|
||||||
// propagate --bless
|
// propagate --bless
|
||||||
if builder.config.cmd.bless() {
|
if builder.config.cmd.bless() {
|
||||||
@ -607,7 +620,6 @@ impl Step for Miri {
|
|||||||
// Tell `cargo miri` where to find things.
|
// Tell `cargo miri` where to find things.
|
||||||
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
cargo.env("MIRI_SYSROOT", &miri_sysroot);
|
||||||
cargo.env("MIRI_HOST_SYSROOT", sysroot);
|
cargo.env("MIRI_HOST_SYSROOT", sysroot);
|
||||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
|
||||||
cargo.env("MIRI", &miri);
|
cargo.env("MIRI", &miri);
|
||||||
// Debug things.
|
// Debug things.
|
||||||
cargo.env("RUST_BACKTRACE", "1");
|
cargo.env("RUST_BACKTRACE", "1");
|
||||||
|
@ -433,8 +433,10 @@ Moreover, Miri recognizes some environment variables:
|
|||||||
trigger a re-build of the standard library; you have to clear the Miri build
|
trigger a re-build of the standard library; you have to clear the Miri build
|
||||||
cache manually (on Linux, `rm -rf ~/.cache/miri`).
|
cache manually (on Linux, `rm -rf ~/.cache/miri`).
|
||||||
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
|
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
|
||||||
using `cargo miri`, only set this if you do not want to use the automatically created sysroot. For
|
using `cargo miri`, this skips the automatic setup -- only set this if you do not want to use the
|
||||||
directly invoking the Miri driver, this variable (or a `--sysroot` flag) is mandatory.
|
automatically created sysroot. For directly invoking the Miri driver, this variable (or a
|
||||||
|
`--sysroot` flag) is mandatory. When invoking `cargo miri setup`, this indicates where the sysroot
|
||||||
|
will be put.
|
||||||
* `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target
|
* `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target
|
||||||
architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same
|
architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same
|
||||||
purpose.
|
purpose.
|
||||||
|
@ -17,10 +17,8 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
|
|||||||
let only_setup = matches!(subcommand, MiriCommand::Setup);
|
let only_setup = matches!(subcommand, MiriCommand::Setup);
|
||||||
let ask_user = !only_setup;
|
let ask_user = !only_setup;
|
||||||
let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
|
let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
|
||||||
if std::env::var_os("MIRI_SYSROOT").is_some() {
|
if !only_setup && std::env::var_os("MIRI_SYSROOT").is_some() {
|
||||||
if only_setup {
|
// Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
|
||||||
println!("WARNING: MIRI_SYSROOT already set, not doing anything.")
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,8 +59,13 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine where to put the sysroot.
|
// Determine where to put the sysroot.
|
||||||
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
|
let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") {
|
||||||
let sysroot_dir = user_dirs.cache_dir();
|
Some(dir) => PathBuf::from(dir),
|
||||||
|
None => {
|
||||||
|
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
|
||||||
|
user_dirs.cache_dir().to_owned()
|
||||||
|
}
|
||||||
|
};
|
||||||
// Sysroot configuration and build details.
|
// Sysroot configuration and build details.
|
||||||
let sysroot_config = if std::env::var_os("MIRI_NO_STD").is_some() {
|
let sysroot_config = if std::env::var_os("MIRI_NO_STD").is_some() {
|
||||||
SysrootConfig::NoStd
|
SysrootConfig::NoStd
|
||||||
@ -111,7 +114,7 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
|
|||||||
(command, rustflags)
|
(command, rustflags)
|
||||||
};
|
};
|
||||||
// Make sure all target-level Miri invocations know their sysroot.
|
// Make sure all target-level Miri invocations know their sysroot.
|
||||||
std::env::set_var("MIRI_SYSROOT", sysroot_dir);
|
std::env::set_var("MIRI_SYSROOT", &sysroot_dir);
|
||||||
|
|
||||||
// Do the build.
|
// Do the build.
|
||||||
if only_setup {
|
if only_setup {
|
||||||
@ -121,7 +124,7 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
|
|||||||
// We want to be quiet, but still let the user know that something is happening.
|
// We want to be quiet, but still let the user know that something is happening.
|
||||||
eprint!("Preparing a sysroot for Miri (target: {target})... ");
|
eprint!("Preparing a sysroot for Miri (target: {target})... ");
|
||||||
}
|
}
|
||||||
Sysroot::new(sysroot_dir, target)
|
Sysroot::new(&sysroot_dir, target)
|
||||||
.build_from_source(&rust_src, BuildMode::Check, sysroot_config, rustc_version, cargo_cmd)
|
.build_from_source(&rust_src, BuildMode::Check, sysroot_config, rustc_version, cargo_cmd)
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
if only_setup {
|
if only_setup {
|
||||||
|
Loading…
Reference in New Issue
Block a user