Skip to content

Commit 9c0b5c1

Browse files
committed
miri-script: use --remap-path-prefix to print errors relative to the right root
1 parent 83248ce commit 9c0b5c1

File tree

6 files changed

+75
-61
lines changed

6 files changed

+75
-61
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ anyone but Miri itself. They are used to communicate between different Miri
309309
binaries, and as such worth documenting:
310310

311311
* `CARGO_EXTRA_FLAGS` is understood by `./miri` and passed to all host cargo invocations.
312+
It is reserved for CI usage; setting the wrong flags this way can easily confuse the script.
312313
* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to
313314
actually not interpret the code but compile it like rustc would. With `target`, Miri sets
314315
some compiler flags to prepare the code for interpretation; with `host`, this is not done.

cargo-miri/miri

Lines changed: 0 additions & 4 deletions
This file was deleted.

miri

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
#!/usr/bin/env bash
22
set -e
3-
# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
4-
# rustup (that sets it's own environmental variables), which is undesirable.
3+
# We want to call the binary directly, so we need to know where it ends up.
54
MIRI_SCRIPT_TARGET_DIR="$(dirname "$0")"/miri-script/target
6-
cargo +stable build $CARGO_EXTRA_FLAGS -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml || \
5+
# If stdout is not a terminal and we are not on CI, assume that we are being invoked by RA, and use JSON output.
6+
if ! [ -t 1 ] && [ -z "$CI" ]; then
7+
MESSAGE_FORMAT="--message-format=json"
8+
fi
9+
# Set --remap-path-prefix so miri-script build failures are printed relative to the Miri root.
10+
RUSTFLAGS="$RUSTFLAGS --remap-path-prefix =miri-script" \
11+
cargo +stable build $CARGO_EXTRA_FLAGS --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml \
12+
-q --target-dir "$MIRI_SCRIPT_TARGET_DIR" $MESSAGE_FORMAT || \
713
( echo "Failed to build miri-script. Is the 'stable' toolchain installed?"; exit 1 )
14+
# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
15+
# rustup (that sets it's own environmental variables), which is undesirable.
816
"$MIRI_SCRIPT_TARGET_DIR"/debug/miri-script "$@"

miri-script/miri

Lines changed: 0 additions & 4 deletions
This file was deleted.

miri-script/src/commands.rs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ impl MiriEnv {
3535
return Ok(miri_sysroot.into());
3636
}
3737
let manifest_path = path!(self.miri_dir / "cargo-miri" / "Cargo.toml");
38-
let Self { toolchain, cargo_extra_flags, .. } = &self;
3938

40-
// Make sure everything is built. Also Miri itself.
39+
// Make sure everything is built. Also Miri itself; we need the Miri binary.
4140
self.build(path!(self.miri_dir / "Cargo.toml"), &[], quiet)?;
41+
let miri_bin =
42+
path!(self.miri_dir / "target" / "debug" / format!("miri{}", env::consts::EXE_SUFFIX));
4243
self.build(&manifest_path, &[], quiet)?;
4344

4445
let target_flag = if let Some(target) = &target {
@@ -56,10 +57,13 @@ impl MiriEnv {
5657
eprintln!();
5758
}
5859

59-
let mut cmd = cmd!(self.sh,
60-
"cargo +{toolchain} --quiet run {cargo_extra_flags...} --manifest-path {manifest_path} --
61-
miri setup --print-sysroot {target_flag...}"
62-
);
60+
let mut cmd = self
61+
.cargo_cmd(&manifest_path, "run")
62+
.arg("--quiet")
63+
.arg("--")
64+
.args(&["miri", "setup", "--print-sysroot"])
65+
.args(target_flag)
66+
.env("MIRI", miri_bin);
6367
cmd.set_quiet(quiet);
6468
let output = cmd.read()?;
6569
self.sh.set_var("MIRI_SYSROOT", &output);
@@ -513,23 +517,19 @@ impl Command {
513517
let miri_manifest = path!(e.miri_dir / "Cargo.toml");
514518
let miri_flags = e.sh.var("MIRIFLAGS").unwrap_or_default();
515519
let miri_flags = flagsplit(&miri_flags);
516-
let toolchain = &e.toolchain;
517-
let extra_flags = &e.cargo_extra_flags;
518520
let quiet_flag = if verbose { None } else { Some("--quiet") };
519521
// This closure runs the command with the given `seed_flag` added between the MIRIFLAGS and
520522
// the `flags` given on the command-line.
521-
let run_miri = |sh: &Shell, seed_flag: Option<String>| -> Result<()> {
523+
let run_miri = |e: &MiriEnv, seed_flag: Option<String>| -> Result<()> {
522524
// The basic command that executes the Miri driver.
523525
let mut cmd = if dep {
524-
cmd!(
525-
sh,
526-
"cargo +{toolchain} {quiet_flag...} test {extra_flags...} --manifest-path {miri_manifest} --test ui -- --miri-run-dep-mode"
527-
)
526+
e.cargo_cmd(&miri_manifest, "test")
527+
.args(&["--test", "ui"])
528+
.args(quiet_flag)
529+
.arg("--")
530+
.args(&["--miri-run-dep-mode"])
528531
} else {
529-
cmd!(
530-
sh,
531-
"cargo +{toolchain} {quiet_flag...} run {extra_flags...} --manifest-path {miri_manifest} --"
532-
)
532+
e.cargo_cmd(&miri_manifest, "run").args(quiet_flag).arg("--")
533533
};
534534
cmd.set_quiet(!verbose);
535535
// Add Miri flags
@@ -545,14 +545,14 @@ impl Command {
545545
};
546546
// Run the closure once or many times.
547547
if let Some(seed_range) = many_seeds {
548-
e.run_many_times(seed_range, |sh, seed| {
548+
e.run_many_times(seed_range, |e, seed| {
549549
eprintln!("Trying seed: {seed}");
550-
run_miri(sh, Some(format!("-Zmiri-seed={seed}"))).inspect_err(|_| {
550+
run_miri(e, Some(format!("-Zmiri-seed={seed}"))).inspect_err(|_| {
551551
eprintln!("FAILING SEED: {seed}");
552552
})
553553
})?;
554554
} else {
555-
run_miri(&e.sh, None)?;
555+
run_miri(&e, None)?;
556556
}
557557
Ok(())
558558
}
@@ -579,6 +579,6 @@ impl Command {
579579
.filter_ok(|item| item.file_type().is_file())
580580
.map_ok(|item| item.into_path());
581581

582-
e.format_files(files, &e.toolchain[..], &config_path, &flags)
582+
e.format_files(files, &config_path, &flags)
583583
}
584584
}

miri-script/src/util.rs

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::ffi::{OsStr, OsString};
2+
use std::fmt::Write;
23
use std::ops::Range;
34
use std::path::{Path, PathBuf};
45
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
@@ -7,7 +8,7 @@ use std::thread;
78
use anyhow::{anyhow, Context, Result};
89
use dunce::canonicalize;
910
use path_macro::path;
10-
use xshell::{cmd, Shell};
11+
use xshell::{cmd, Cmd, Shell};
1112

1213
pub fn miri_dir() -> std::io::Result<PathBuf> {
1314
const MIRI_SCRIPT_ROOT_DIR: &str = env!("CARGO_MANIFEST_DIR");
@@ -28,13 +29,14 @@ pub fn flagsplit(flags: &str) -> Vec<String> {
2829
}
2930

3031
/// Some extra state we track for building Miri, such as the right RUSTFLAGS.
32+
#[derive(Clone)]
3133
pub struct MiriEnv {
3234
/// miri_dir is the root of the miri repository checkout we are working in.
3335
pub miri_dir: PathBuf,
3436
/// active_toolchain is passed as `+toolchain` argument to cargo/rustc invocations.
3537
pub toolchain: String,
3638
/// Extra flags to pass to cargo.
37-
pub cargo_extra_flags: Vec<String>,
39+
cargo_extra_flags: Vec<String>,
3840
/// The rustc sysroot
3941
pub sysroot: PathBuf,
4042
/// The shell we use.
@@ -59,10 +61,6 @@ impl MiriEnv {
5961
println!("Please report a bug at https://github.com/rust-lang/miri/issues.");
6062
std::process::exit(2);
6163
}
62-
// Share target dir between `miri` and `cargo-miri`.
63-
let target_dir = std::env::var_os("CARGO_TARGET_DIR")
64-
.unwrap_or_else(|| path!(miri_dir / "target").into());
65-
sh.set_var("CARGO_TARGET_DIR", target_dir);
6664

6765
// We configure dev builds to not be unusably slow.
6866
let devel_opt_level =
@@ -95,13 +93,37 @@ impl MiriEnv {
9593
Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags })
9694
}
9795

96+
pub fn cargo_cmd(&self, manifest_path: impl AsRef<OsStr>, cmd: &str) -> Cmd<'_> {
97+
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
98+
let manifest_path = Path::new(manifest_path.as_ref());
99+
let cmd = cmd!(
100+
self.sh,
101+
"cargo +{toolchain} {cmd} {cargo_extra_flags...} --manifest-path {manifest_path}"
102+
);
103+
// Hard-code the target dir, since we rely on knowing where the binaries end up.
104+
let manifest_dir = manifest_path.parent().unwrap();
105+
let cmd = cmd.env("CARGO_TARGET_DIR", path!(manifest_dir / "target"));
106+
// Apply path remapping to have errors printed relative to `miri_dir`.
107+
let cmd = if let Ok(relative_to_miri) = manifest_dir.strip_prefix(&self.miri_dir) {
108+
// Add `--remap-path-prefix` to RUSTFLAGS.
109+
let mut rustflags = self.sh.var("RUSTFLAGS").unwrap();
110+
write!(rustflags, " --remap-path-prefix ={}", relative_to_miri.display()).unwrap();
111+
cmd.env("RUSTFLAGS", rustflags)
112+
} else {
113+
cmd
114+
};
115+
// All set up!
116+
cmd
117+
}
118+
98119
pub fn install_to_sysroot(
99120
&self,
100121
path: impl AsRef<OsStr>,
101122
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
102123
) -> Result<()> {
103124
let MiriEnv { sysroot, toolchain, cargo_extra_flags, .. } = self;
104125
// Install binaries to the miri toolchain's `sysroot` so they do not interact with other toolchains.
126+
// (Not using `cargo_cmd` as `install` is special and doesn't use `--manifest-path`.)
105127
cmd!(self.sh, "cargo +{toolchain} install {cargo_extra_flags...} --path {path} --force --root {sysroot} {args...}").run()?;
106128
Ok(())
107129
}
@@ -112,40 +134,31 @@ impl MiriEnv {
112134
args: &[String],
113135
quiet: bool,
114136
) -> Result<()> {
115-
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
116137
let quiet_flag = if quiet { Some("--quiet") } else { None };
117138
// We build the tests as well, (a) to avoid having rebuilds when building the tests later
118139
// and (b) to have more parallelism during the build of Miri and its tests.
119-
let mut cmd = cmd!(
120-
self.sh,
121-
"cargo +{toolchain} build --bins --tests {cargo_extra_flags...} --manifest-path {manifest_path} {quiet_flag...} {args...}"
122-
);
140+
let mut cmd = self
141+
.cargo_cmd(manifest_path, "build")
142+
.args(&["--bins", "--tests"])
143+
.args(quiet_flag)
144+
.args(args);
123145
cmd.set_quiet(quiet);
124146
cmd.run()?;
125147
Ok(())
126148
}
127149

128150
pub fn check(&self, manifest_path: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
129-
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
130-
cmd!(self.sh, "cargo +{toolchain} check {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}")
131-
.run()?;
151+
self.cargo_cmd(manifest_path, "check").arg("--all-targets").args(args).run()?;
132152
Ok(())
133153
}
134154

135155
pub fn clippy(&self, manifest_path: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
136-
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
137-
cmd!(self.sh, "cargo +{toolchain} clippy {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}")
138-
.run()?;
156+
self.cargo_cmd(manifest_path, "clippy").arg("--all-targets").args(args).run()?;
139157
Ok(())
140158
}
141159

142160
pub fn test(&self, manifest_path: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
143-
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
144-
cmd!(
145-
self.sh,
146-
"cargo +{toolchain} test {cargo_extra_flags...} --manifest-path {manifest_path} {args...}"
147-
)
148-
.run()?;
161+
self.cargo_cmd(manifest_path, "test").args(args).run()?;
149162
Ok(())
150163
}
151164

@@ -155,7 +168,6 @@ impl MiriEnv {
155168
pub fn format_files(
156169
&self,
157170
files: impl Iterator<Item = Result<PathBuf, walkdir::Error>>,
158-
toolchain: &str,
159171
config_path: &Path,
160172
flags: &[String],
161173
) -> anyhow::Result<()> {
@@ -166,6 +178,7 @@ impl MiriEnv {
166178
// Format in batches as not all our files fit into Windows' command argument limit.
167179
for batch in &files.chunks(256) {
168180
// Build base command.
181+
let toolchain = &self.toolchain;
169182
let mut cmd = cmd!(
170183
self.sh,
171184
"rustfmt +{toolchain} --edition=2021 --config-path {config_path} --unstable-features --skip-children {flags...}"
@@ -197,7 +210,7 @@ impl MiriEnv {
197210
pub fn run_many_times(
198211
&self,
199212
range: Range<u32>,
200-
run: impl Fn(&Shell, u32) -> Result<()> + Sync,
213+
run: impl Fn(&Self, u32) -> Result<()> + Sync,
201214
) -> Result<()> {
202215
// `next` is atomic so threads can concurrently fetch their next value to run.
203216
let next = AtomicU32::new(range.start);
@@ -207,10 +220,10 @@ impl MiriEnv {
207220
let mut handles = Vec::new();
208221
// Spawn one worker per core.
209222
for _ in 0..thread::available_parallelism()?.get() {
210-
// Create a copy of the shell for this thread.
211-
let local_shell = self.sh.clone();
223+
// Create a copy of the environment for this thread.
224+
let local_miri = self.clone();
212225
let handle = s.spawn(|| -> Result<()> {
213-
let local_shell = local_shell; // move the copy into this thread.
226+
let local_miri = local_miri; // move the copy into this thread.
214227
// Each worker thread keeps asking for numbers until we're all done.
215228
loop {
216229
let cur = next.fetch_add(1, Ordering::Relaxed);
@@ -219,7 +232,7 @@ impl MiriEnv {
219232
break;
220233
}
221234
// Run the command with this seed.
222-
run(&local_shell, cur).inspect_err(|_| {
235+
run(&local_miri, cur).inspect_err(|_| {
223236
// If we failed, tell everyone about this.
224237
failed.store(true, Ordering::Relaxed);
225238
})?;

0 commit comments

Comments
 (0)