Skip to content

Commit 606adf9

Browse files
committed
Auto merge of #3006 - RalfJung:miri-script-shell, r=RalfJung
miri-script and cargo-miri cleanups At least in an initial test, `cmd!(Shell::new()?, "env")` does show the full environment. Let's see what CI says. `@osiewicz` why did you add this code to forward the host environment?
2 parents 69358d0 + f96c30d commit 606adf9

File tree

5 files changed

+41
-71
lines changed

5 files changed

+41
-71
lines changed

cargo-miri/src/phases.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
9494
let target = target.as_ref().unwrap_or(host);
9595

9696
// We always setup.
97-
setup(&subcommand, target, &rustc_version, verbose);
97+
let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose);
9898

9999
// Invoke actual cargo for the job, but with different flags.
100100
// We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but
@@ -159,6 +159,8 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
159159
// Forward all further arguments (not consumed by `ArgSplitFlagValue`) to cargo.
160160
cmd.args(args);
161161

162+
// Let it know where the Miri sysroot lives.
163+
cmd.env("MIRI_SYSROOT", miri_sysroot);
162164
// Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation,
163165
// i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish
164166
// the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.)

cargo-miri/src/setup.rs

+15-6
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,20 @@ use crate::util::*;
1313
/// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets
1414
/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has
1515
/// done all this already.
16-
pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta, verbose: usize) {
16+
pub fn setup(
17+
subcommand: &MiriCommand,
18+
target: &str,
19+
rustc_version: &VersionMeta,
20+
verbose: usize,
21+
) -> PathBuf {
1722
let only_setup = matches!(subcommand, MiriCommand::Setup);
1823
let ask_user = !only_setup;
1924
let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
20-
if !only_setup && std::env::var_os("MIRI_SYSROOT").is_some() {
21-
// Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
22-
return;
25+
if !only_setup {
26+
if let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") {
27+
// Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
28+
return sysroot.into();
29+
}
2330
}
2431

2532
// Determine where the rust sources are located. The env var trumps auto-detection.
@@ -92,6 +99,8 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
9299
command.env("RUSTC", &cargo_miri_path);
93100
}
94101
command.env("MIRI_CALLED_FROM_SETUP", "1");
102+
// Miri expects `MIRI_SYSROOT` to be set when invoked in target mode. Even if that directory is empty.
103+
command.env("MIRI_SYSROOT", &sysroot_dir);
95104
// Make sure there are no other wrappers getting in our way (Cc
96105
// https://github.com/rust-lang/miri/issues/1421,
97106
// https://github.com/rust-lang/miri/issues/2429). Looks like setting
@@ -117,8 +126,6 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
117126
// the user might have set, which is consistent with normal `cargo build` that does
118127
// not apply `RUSTFLAGS` to the sysroot either.
119128
let rustflags = &["-Cdebug-assertions=off", "-Coverflow-checks=on"];
120-
// Make sure all target-level Miri invocations know their sysroot.
121-
std::env::set_var("MIRI_SYSROOT", &sysroot_dir);
122129

123130
// Do the build.
124131
if print_sysroot {
@@ -159,4 +166,6 @@ pub fn setup(subcommand: &MiriCommand, target: &str, rustc_version: &VersionMeta
159166
// Print just the sysroot and nothing else to stdout; this way we do not need any escaping.
160167
println!("{}", sysroot_dir.display());
161168
}
169+
170+
sysroot_dir
162171
}

cargo-miri/src/util.rs

+1-39
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
use std::collections::HashMap;
21
use std::env;
32
use std::ffi::OsString;
4-
use std::fmt::Write as _;
53
use std::fs::File;
64
use std::io::{self, BufWriter, Read, Write};
75
use std::ops::Not;
@@ -247,46 +245,10 @@ pub fn local_crates(metadata: &Metadata) -> String {
247245
local_crates
248246
}
249247

250-
fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> {
251-
let mut envs = HashMap::new();
252-
for (key, value) in std::env::vars() {
253-
envs.insert(key, value);
254-
}
255-
for (key, value) in cmd.get_envs() {
256-
if let Some(value) = value {
257-
envs.insert(key.to_string_lossy().to_string(), value.to_string_lossy().to_string());
258-
} else {
259-
envs.remove(&key.to_string_lossy().to_string());
260-
}
261-
}
262-
let mut envs: Vec<_> = envs.into_iter().collect();
263-
envs.sort();
264-
envs
265-
}
266-
267248
/// Debug-print a command that is going to be run.
268249
pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) {
269250
if verbose == 0 {
270251
return;
271252
}
272-
// We only do a single `eprintln!` call to minimize concurrency interactions.
273-
let mut out = prefix.to_string();
274-
writeln!(out, " running command: env \\").unwrap();
275-
if verbose > 1 {
276-
// Print the full environment this will be called in.
277-
for (key, value) in env_vars_from_cmd(cmd) {
278-
writeln!(out, "{key}={value:?} \\").unwrap();
279-
}
280-
} else {
281-
// Print only what has been changed for this `cmd`.
282-
for (var, val) in cmd.get_envs() {
283-
if let Some(val) = val {
284-
writeln!(out, "{}={val:?} \\", var.to_string_lossy()).unwrap();
285-
} else {
286-
writeln!(out, "--unset={}", var.to_string_lossy()).unwrap();
287-
}
288-
}
289-
}
290-
write!(out, "{cmd:?}").unwrap();
291-
eprintln!("{out}");
253+
eprintln!("{prefix} running command: {cmd:?}");
292254
}

miri-script/src/commands.rs

+20-14
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::ops::Not;
66
use anyhow::{anyhow, bail, Context, Result};
77
use path_macro::path;
88
use walkdir::WalkDir;
9-
use xshell::cmd;
9+
use xshell::{cmd, Shell};
1010

1111
use crate::util::*;
1212
use crate::Command;
@@ -16,17 +16,25 @@ const JOSH_FILTER: &str =
1616
":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri";
1717

1818
impl MiriEnv {
19-
fn build_miri_sysroot(&mut self) -> Result<()> {
19+
fn build_miri_sysroot(&mut self, quiet: bool) -> Result<()> {
2020
if self.sh.var("MIRI_SYSROOT").is_ok() {
2121
// Sysroot already set, use that.
2222
return Ok(());
2323
}
2424
let manifest_path = path!(self.miri_dir / "cargo-miri" / "Cargo.toml");
2525
let Self { toolchain, cargo_extra_flags, .. } = &self;
26+
27+
// Make sure everything is built. Also Miri itself.
28+
self.build(path!(self.miri_dir / "Cargo.toml"), &[], quiet)?;
29+
self.build(&manifest_path, &[], quiet)?;
30+
2631
let target = &match self.sh.var("MIRI_TEST_TARGET") {
2732
Ok(target) => vec!["--target".into(), target],
2833
Err(_) => vec![],
2934
};
35+
if !quiet {
36+
eprintln!("$ (buildig Miri sysroot)");
37+
}
3038
let output = cmd!(self.sh,
3139
"cargo +{toolchain} --quiet run {cargo_extra_flags...} --manifest-path {manifest_path} --
3240
miri setup --print-sysroot {target...}"
@@ -91,7 +99,7 @@ impl Command {
9199
// Make sure rustup-toolchain-install-master is installed.
92100
which::which("rustup-toolchain-install-master")
93101
.context("Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'")?;
94-
let sh = shell()?;
102+
let sh = Shell::new()?;
95103
sh.change_dir(miri_dir()?);
96104
let new_commit = Some(sh.read_file("rust-version")?.trim().to_owned());
97105
let current_commit = {
@@ -130,7 +138,7 @@ impl Command {
130138
}
131139

132140
fn rustc_pull(commit: Option<String>) -> Result<()> {
133-
let sh = shell()?;
141+
let sh = Shell::new()?;
134142
sh.change_dir(miri_dir()?);
135143
let commit = commit.map(Result::Ok).unwrap_or_else(|| {
136144
let rust_repo_head =
@@ -177,7 +185,7 @@ impl Command {
177185
}
178186

179187
fn rustc_push(github_user: String, branch: String) -> Result<()> {
180-
let sh = shell()?;
188+
let sh = Shell::new()?;
181189
sh.change_dir(miri_dir()?);
182190
let base = sh.read_file("rust-version")?.trim().to_owned();
183191
// Make sure the repo is clean.
@@ -265,7 +273,7 @@ impl Command {
265273
let Some((command_name, trailing_args)) = command.split_first() else {
266274
bail!("expected many-seeds command to be non-empty");
267275
};
268-
let sh = shell()?;
276+
let sh = Shell::new()?;
269277
for seed in seed_start..seed_end {
270278
println!("Trying seed: {seed}");
271279
let mut miriflags = env::var_os("MIRIFLAGS").unwrap_or_default();
@@ -293,7 +301,7 @@ impl Command {
293301
// Make sure we have an up-to-date Miri installed and selected the right toolchain.
294302
Self::install(vec![])?;
295303

296-
let sh = shell()?;
304+
let sh = Shell::new()?;
297305
sh.change_dir(miri_dir()?);
298306
let benches_dir = "bench-cargo-miri";
299307
let benches = if benches.is_empty() {
@@ -365,9 +373,8 @@ impl Command {
365373
fn test(bless: bool, flags: Vec<OsString>) -> Result<()> {
366374
Self::auto_actions()?;
367375
let mut e = MiriEnv::new()?;
368-
// First build, and get a sysroot.
369-
e.build(path!(e.miri_dir / "Cargo.toml"), &[], /* quiet */ true)?;
370-
e.build_miri_sysroot()?;
376+
// Prepare a sysroot.
377+
e.build_miri_sysroot(/* quiet */ false)?;
371378

372379
// Then test, and let caller control flags.
373380
// Only in root project as `cargo-miri` has no tests.
@@ -393,12 +400,11 @@ impl Command {
393400
let miriflags = e.sh.var("MIRIFLAGS").unwrap_or_default();
394401
e.sh.set_var("MIRIFLAGS", format!("{miriflags} --target {target}"));
395402
}
396-
// First build, and get a sysroot.
397-
let miri_manifest = path!(e.miri_dir / "Cargo.toml");
398-
e.build(&miri_manifest, &[], /* quiet */ true)?;
399-
e.build_miri_sysroot()?;
403+
// Prepare a sysroot.
404+
e.build_miri_sysroot(/* quiet */ true)?;
400405

401406
// Then run the actual command.
407+
let miri_manifest = path!(e.miri_dir / "Cargo.toml");
402408
let miri_flags = e.sh.var("MIRIFLAGS").unwrap_or_default();
403409
let miri_flags = flagsplit(&miri_flags);
404410
let toolchain = &e.toolchain;

miri-script/src/util.rs

+2-11
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,12 @@ pub fn miri_dir() -> std::io::Result<PathBuf> {
1313

1414
/// Queries the active toolchain for the Miri dir.
1515
pub fn active_toolchain() -> Result<String> {
16-
let sh = shell()?;
16+
let sh = Shell::new()?;
1717
sh.change_dir(miri_dir()?);
1818
let stdout = cmd!(sh, "rustup show active-toolchain").read()?;
1919
Ok(stdout.split_whitespace().next().context("Could not obtain active Rust toolchain")?.into())
2020
}
2121

22-
pub fn shell() -> Result<Shell> {
23-
let sh = Shell::new()?;
24-
// xshell does not propagate parent's env variables by default.
25-
for (k, v) in std::env::vars_os() {
26-
sh.set_var(k, v);
27-
}
28-
Ok(sh)
29-
}
30-
3122
pub fn flagsplit(flags: &str) -> Vec<String> {
3223
// This code is taken from `RUSTFLAGS` handling in cargo.
3324
flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect()
@@ -50,7 +41,7 @@ pub struct MiriEnv {
5041
impl MiriEnv {
5142
pub fn new() -> Result<Self> {
5243
let toolchain = active_toolchain()?;
53-
let sh = shell()?; // we are preserving the current_dir on this one, so paths resolve properly!
44+
let sh = Shell::new()?; // we are preserving the current_dir on this one, so paths resolve properly!
5445
let miri_dir = miri_dir()?;
5546

5647
let sysroot = cmd!(sh, "rustc +{toolchain} --print sysroot").read()?.into();

0 commit comments

Comments
 (0)