Skip to content

Commit 6bae73a

Browse files
committed
./miri run: directly run binary instead of using 'cargo run'
1 parent c0fb1a7 commit 6bae73a

File tree

5 files changed

+143
-54
lines changed

5 files changed

+143
-54
lines changed

ci/ci.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ time ./miri install
2626
# We enable all features to make sure the Stacked Borrows consistency check runs.
2727
echo "Building debug version of Miri"
2828
export CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS --all-features"
29-
time ./miri build --all-targets # the build that all the `./miri test` below will use
29+
time ./miri build # the build that all the `./miri test` below will use
3030

3131
endgroup
3232

miri-script/Cargo.lock

+88-30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

miri-script/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ xshell = "0.2.6"
2323
rustc_version = "0.4"
2424
dunce = "1.0.4"
2525
directories = "5"
26+
serde_json = "1"

miri-script/src/commands.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -494,23 +494,21 @@ impl Command {
494494
flags: Vec<String>,
495495
) -> Result<()> {
496496
let mut e = MiriEnv::new()?;
497+
498+
// Preparation: get a sysroot, and get the miri binary.
499+
let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?;
500+
let miri_bin =
501+
e.build_get_binary(".").context("failed to get filename of miri executable")?;
502+
497503
// More flags that we will pass before `flags`
498504
// (because `flags` may contain `--`).
499505
let mut early_flags = Vec::<OsString>::new();
500-
501-
// Add target, edition to flags.
502506
if let Some(target) = &target {
503507
early_flags.push("--target".into());
504508
early_flags.push(target.into());
505509
}
506-
if verbose {
507-
early_flags.push("--verbose".into());
508-
}
509510
early_flags.push("--edition".into());
510511
early_flags.push(edition.as_deref().unwrap_or("2021").into());
511-
512-
// Prepare a sysroot, add it to the flags. (Also builds cargo-miri, which we need.)
513-
let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?;
514512
early_flags.push("--sysroot".into());
515513
early_flags.push(miri_sysroot.into());
516514

@@ -523,13 +521,14 @@ impl Command {
523521
let run_miri = |e: &MiriEnv, seed_flag: Option<String>| -> Result<()> {
524522
// The basic command that executes the Miri driver.
525523
let mut cmd = if dep {
524+
// We invoke the test suite as that has all the logic for running with dependencies.
526525
e.cargo_cmd(".", "test")
527526
.args(&["--test", "ui"])
528527
.args(quiet_flag)
529528
.arg("--")
530529
.args(&["--miri-run-dep-mode"])
531530
} else {
532-
e.cargo_cmd(".", "run").args(quiet_flag).arg("--")
531+
cmd!(e.sh, "{miri_bin}")
533532
};
534533
cmd.set_quiet(!verbose);
535534
// Add Miri flags

miri-script/src/util.rs

+45-14
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use std::ffi::{OsStr, OsString};
2+
use std::io::BufRead;
23
use std::ops::Range;
34
use std::path::{Path, PathBuf};
45
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
5-
use std::thread;
6+
use std::{env, iter, thread};
67

7-
use anyhow::{anyhow, Context, Result};
8+
use anyhow::{anyhow, bail, Context, Result};
89
use dunce::canonicalize;
910
use path_macro::path;
1011
use xshell::{cmd, Cmd, Shell};
@@ -73,8 +74,11 @@ impl MiriEnv {
7374
let rustflags = {
7475
let mut flags = OsString::new();
7576
// We set the rpath so that Miri finds the private rustc libraries it needs.
76-
flags.push("-C link-args=-Wl,-rpath,");
77-
flags.push(libdir);
77+
// (This only makes sense on Unix.)
78+
if cfg!(unix) {
79+
flags.push("-C link-args=-Wl,-rpath,");
80+
flags.push(&libdir);
81+
}
7882
// Enable rustc-specific lints (ignored without `-Zunstable-options`).
7983
flags.push(
8084
" -Zunstable-options -Wrustc::internal -Wrust_2018_idioms -Wunused_lifetimes",
@@ -88,6 +92,14 @@ impl MiriEnv {
8892
};
8993
sh.set_var("RUSTFLAGS", rustflags);
9094

95+
// On Windows, the `-Wl,-rpath,` above does not help. Instead we add the libdir to the PATH,
96+
// so that Windows can find the DLLs.
97+
if cfg!(windows) {
98+
let old_path = sh.var("PATH")?;
99+
let new_path = env::join_paths(iter::once(libdir).chain(env::split_paths(&old_path)))?;
100+
sh.set_var("PATH", new_path);
101+
}
102+
91103
// Get extra flags for cargo.
92104
let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default();
93105
let cargo_extra_flags = flagsplit(&cargo_extra_flags);
@@ -126,21 +138,40 @@ impl MiriEnv {
126138

127139
pub fn build(&self, crate_dir: impl AsRef<OsStr>, args: &[String], quiet: bool) -> Result<()> {
128140
let quiet_flag = if quiet { Some("--quiet") } else { None };
129-
// We build the tests as well, (a) to avoid having rebuilds when building the tests later
130-
// and (b) to have more parallelism during the build of Miri and its tests.
131-
// This means `./miri run` without `--dep` will build Miri twice (for the sysroot with
132-
// dev-dependencies, and then for running without dev-dependencies), but the way more common
133-
// `./miri test` will avoid building Miri twice.
134-
let mut cmd = self
135-
.cargo_cmd(crate_dir, "build")
136-
.args(&["--bins", "--tests"])
137-
.args(quiet_flag)
138-
.args(args);
141+
// We build all targets, since building *just* the bin target doesnot include
142+
// `dev-dependencies` and that changes feature resolution. This also gets us more
143+
// parallelism in `./miri test` as we build Miri and its tests together.
144+
let mut cmd =
145+
self.cargo_cmd(crate_dir, "build").args(&["--all-targets"]).args(quiet_flag).args(args);
139146
cmd.set_quiet(quiet);
140147
cmd.run()?;
141148
Ok(())
142149
}
143150

151+
/// Returns the path to the main crate binary. Assumes that `build` has been called before.
152+
pub fn build_get_binary(&self, crate_dir: impl AsRef<OsStr>) -> Result<PathBuf> {
153+
let cmd =
154+
self.cargo_cmd(crate_dir, "build").args(&["--all-targets", "--message-format=json"]);
155+
let output = cmd.output()?;
156+
let mut bin = None;
157+
for line in output.stdout.lines() {
158+
let line = line?;
159+
if line.starts_with("{") {
160+
let json: serde_json::Value = serde_json::from_str(&line)?;
161+
if json["reason"] == "compiler-artifact"
162+
&& !json["profile"]["test"].as_bool().unwrap()
163+
&& !json["executable"].is_null()
164+
{
165+
if bin.is_some() {
166+
bail!("found two binaries in cargo output");
167+
}
168+
bin = Some(PathBuf::from(json["executable"].as_str().unwrap()))
169+
}
170+
}
171+
}
172+
bin.ok_or_else(|| anyhow!("found no binary in cargo output"))
173+
}
174+
144175
pub fn check(&self, crate_dir: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
145176
self.cargo_cmd(crate_dir, "check").arg("--all-targets").args(args).run()?;
146177
Ok(())

0 commit comments

Comments
 (0)