Skip to content

Commit 4db9a36

Browse files
committed
Auto merge of rust-lang#3312 - RossSmyth:miri-clean, r=RalfJung
Add "cargo miri clean" command My first reaction when my miri cache was messed up was to attempt run this, which obviously failed. This helps paper over platform differences and such.
2 parents 2f1c9db + 3e7c2e1 commit 4db9a36

File tree

4 files changed

+84
-16
lines changed

4 files changed

+84
-16
lines changed

src/tools/miri/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ Miri builds and vice-versa.
279279

280280
You may be running `cargo miri` with a different compiler version than the one
281281
used to build the custom libstd that Miri uses, and Miri failed to detect that.
282-
Try deleting `~/.cache/miri`.
282+
Try running `cargo miri clean`.
283283

284284
#### "no mir for `std::rt::lang_start_internal`"
285285

@@ -465,7 +465,7 @@ Moreover, Miri recognizes some environment variables:
465465
must point to the `library` subdirectory of a `rust-lang/rust` repository
466466
checkout. Note that changing files in that directory does not automatically
467467
trigger a re-build of the standard library; you have to clear the Miri build
468-
cache manually (on Linux, `rm -rf ~/.cache/miri`;
468+
cache with `cargo miri clean` or deleting it manually (on Linux, `rm -rf ~/.cache/miri`;
469469
on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`;
470470
and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`).
471471
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When

src/tools/miri/cargo-miri/src/phases.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Subcommands:
2020
test, t Run tests
2121
nextest Run tests with nextest (requires cargo-nextest installed)
2222
setup Only perform automatic setup, but without asking questions (for getting a proper libstd)
23+
clean Clean the Miri cache & target directory
2324
2425
The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively.
2526
@@ -74,14 +75,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
7475
// We cannot know which of those flags take arguments and which do not,
7576
// so we cannot detect subcommands later.
7677
let Some(subcommand) = args.next() else {
77-
show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)");
78+
show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`, `clean`)");
7879
};
7980
let subcommand = match &*subcommand {
8081
"setup" => MiriCommand::Setup,
8182
"test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
83+
"clean" => MiriCommand::Clean,
8284
_ =>
8385
show_error!(
84-
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`."
86+
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`."
8587
),
8688
};
8789
let verbose = num_arg_flag("-v");
@@ -93,6 +95,16 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
9395
let target = get_arg_flag_value("--target");
9496
let target = target.as_ref().unwrap_or(host);
9597

98+
// If cleaning the the target directory & sysroot cache,
99+
// delete them then exit. There is no reason to setup a new
100+
// sysroot in this execution.
101+
if let MiriCommand::Clean = subcommand {
102+
let metadata = get_cargo_metadata();
103+
clean_target_dir(&metadata);
104+
clean_sysroot();
105+
return;
106+
}
107+
96108
// We always setup.
97109
let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose);
98110

@@ -110,6 +122,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
110122
let cargo_cmd = match subcommand {
111123
MiriCommand::Forward(s) => s,
112124
MiriCommand::Setup => return, // `cargo miri setup` stops here.
125+
MiriCommand::Clean => unreachable!(),
113126
};
114127
let metadata = get_cargo_metadata();
115128
let mut cmd = cargo();
@@ -142,11 +155,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
142155
.arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']"));
143156

144157
// Set `--target-dir` to `miri` inside the original target directory.
145-
let mut target_dir = match get_arg_flag_value("--target-dir") {
146-
Some(dir) => PathBuf::from(dir),
147-
None => metadata.target_directory.clone().into_std_path_buf(),
148-
};
149-
target_dir.push("miri");
158+
let target_dir = get_target_dir(&metadata);
150159
cmd.arg("--target-dir").arg(target_dir);
151160

152161
// *After* we set all the flags that need setting, forward everything else. Make sure to skip

src/tools/miri/cargo-miri/src/setup.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,8 @@ pub fn setup(
6767
}
6868

6969
// Determine where to put the sysroot.
70-
let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") {
71-
Some(dir) => PathBuf::from(dir),
72-
None => {
73-
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
74-
user_dirs.cache_dir().to_owned()
75-
}
76-
};
70+
let sysroot_dir = get_sysroot_dir();
71+
7772
// Sysroot configuration and build details.
7873
let no_std = match std::env::var_os("MIRI_NO_STD") {
7974
None =>

src/tools/miri/cargo-miri/src/util.rs

+64
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ pub enum MiriCommand {
7474
Setup,
7575
/// A command to be forwarded to cargo.
7676
Forward(String),
77+
/// Clean the miri cache
78+
Clean,
7779
}
7880

7981
/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax.
@@ -249,3 +251,65 @@ pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) {
249251
}
250252
eprintln!("{prefix} running command: {cmd:?}");
251253
}
254+
255+
/// Get the target directory for miri output.
256+
///
257+
/// Either in an argument passed-in, or from cargo metadata.
258+
pub fn get_target_dir(meta: &Metadata) -> PathBuf {
259+
let mut output = match get_arg_flag_value("--target-dir") {
260+
Some(dir) => PathBuf::from(dir),
261+
None => meta.target_directory.clone().into_std_path_buf(),
262+
};
263+
output.push("miri");
264+
output
265+
}
266+
267+
/// Determines where the sysroot of this exeuction is
268+
///
269+
/// Either in a user-specified spot by an envar, or in a default cache location.
270+
pub fn get_sysroot_dir() -> PathBuf {
271+
match std::env::var_os("MIRI_SYSROOT") {
272+
Some(dir) => PathBuf::from(dir),
273+
None => {
274+
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
275+
user_dirs.cache_dir().to_owned()
276+
}
277+
}
278+
}
279+
280+
/// An idempotent version of the stdlib's remove_dir_all
281+
/// it is considered a success if the directory was not there.
282+
fn remove_dir_all_idem(dir: &Path) -> std::io::Result<()> {
283+
match std::fs::remove_dir_all(dir) {
284+
Ok(_) => Ok(()),
285+
// If the directory doesn't exist, it is still a success.
286+
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
287+
Err(err) => Err(err),
288+
}
289+
}
290+
291+
/// Deletes the Miri sysroot cache
292+
/// Returns an error if the MIRI_SYSROOT env var is set.
293+
pub fn clean_sysroot() {
294+
if std::env::var_os("MIRI_SYSROOT").is_some() {
295+
show_error!(
296+
"MIRI_SYSROOT is set. Please clean your custom sysroot cache directory manually."
297+
)
298+
}
299+
300+
let sysroot_dir = get_sysroot_dir();
301+
302+
eprintln!("Cleaning sysroot cache at {}", sysroot_dir.display());
303+
304+
// Keep it simple, just remove the directory.
305+
remove_dir_all_idem(&sysroot_dir).unwrap_or_else(|err| show_error!("{}", err));
306+
}
307+
308+
/// Deletes the Miri target directory
309+
pub fn clean_target_dir(meta: &Metadata) {
310+
let target_dir = get_target_dir(meta);
311+
312+
eprintln!("Cleaning target directory at {}", target_dir.display());
313+
314+
remove_dir_all_idem(&target_dir).unwrap_or_else(|err| show_error!("{}", err))
315+
}

0 commit comments

Comments
 (0)