Skip to content

Commit

Permalink
Auto merge of rust-lang#3312 - RossSmyth:miri-clean, r=RalfJung
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Feb 24, 2024
2 parents 2f1c9db + 3e7c2e1 commit 4db9a36
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/tools/miri/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ Miri builds and vice-versa.

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

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

Expand Down Expand Up @@ -465,7 +465,7 @@ Moreover, Miri recognizes some environment variables:
must point to the `library` subdirectory of a `rust-lang/rust` repository
checkout. Note that changing files in that directory does not automatically
trigger a re-build of the standard library; you have to clear the Miri build
cache manually (on Linux, `rm -rf ~/.cache/miri`;
cache with `cargo miri clean` or deleting it manually (on Linux, `rm -rf ~/.cache/miri`;
on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`;
and on macOS, `rm -rf ~/Library/Caches/org.rust-lang.miri`).
* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When
Expand Down
23 changes: 16 additions & 7 deletions src/tools/miri/cargo-miri/src/phases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Subcommands:
test, t Run tests
nextest Run tests with nextest (requires cargo-nextest installed)
setup Only perform automatic setup, but without asking questions (for getting a proper libstd)
clean Clean the Miri cache & target directory
The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively.
Expand Down Expand Up @@ -74,14 +75,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
// We cannot know which of those flags take arguments and which do not,
// so we cannot detect subcommands later.
let Some(subcommand) = args.next() else {
show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)");
show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`, `clean`)");
};
let subcommand = match &*subcommand {
"setup" => MiriCommand::Setup,
"test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand),
"clean" => MiriCommand::Clean,
_ =>
show_error!(
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`."
"`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, `clean`, and `setup`."
),
};
let verbose = num_arg_flag("-v");
Expand All @@ -93,6 +95,16 @@ pub fn phase_cargo_miri(mut args: impl Iterator<Item = String>) {
let target = get_arg_flag_value("--target");
let target = target.as_ref().unwrap_or(host);

// If cleaning the the target directory & sysroot cache,
// delete them then exit. There is no reason to setup a new
// sysroot in this execution.
if let MiriCommand::Clean = subcommand {
let metadata = get_cargo_metadata();
clean_target_dir(&metadata);
clean_sysroot();
return;
}

// We always setup.
let miri_sysroot = setup(&subcommand, target, &rustc_version, verbose);

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

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

// *After* we set all the flags that need setting, forward everything else. Make sure to skip
Expand Down
9 changes: 2 additions & 7 deletions src/tools/miri/cargo-miri/src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,8 @@ pub fn setup(
}

// Determine where to put the sysroot.
let sysroot_dir = match std::env::var_os("MIRI_SYSROOT") {
Some(dir) => PathBuf::from(dir),
None => {
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
user_dirs.cache_dir().to_owned()
}
};
let sysroot_dir = get_sysroot_dir();

// Sysroot configuration and build details.
let no_std = match std::env::var_os("MIRI_NO_STD") {
None =>
Expand Down
64 changes: 64 additions & 0 deletions src/tools/miri/cargo-miri/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ pub enum MiriCommand {
Setup,
/// A command to be forwarded to cargo.
Forward(String),
/// Clean the miri cache
Clean,
}

/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax.
Expand Down Expand Up @@ -249,3 +251,65 @@ pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) {
}
eprintln!("{prefix} running command: {cmd:?}");
}

/// Get the target directory for miri output.
///
/// Either in an argument passed-in, or from cargo metadata.
pub fn get_target_dir(meta: &Metadata) -> PathBuf {
let mut output = match get_arg_flag_value("--target-dir") {
Some(dir) => PathBuf::from(dir),
None => meta.target_directory.clone().into_std_path_buf(),
};
output.push("miri");
output
}

/// Determines where the sysroot of this exeuction is
///
/// Either in a user-specified spot by an envar, or in a default cache location.
pub fn get_sysroot_dir() -> PathBuf {
match std::env::var_os("MIRI_SYSROOT") {
Some(dir) => PathBuf::from(dir),
None => {
let user_dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap();
user_dirs.cache_dir().to_owned()
}
}
}

/// An idempotent version of the stdlib's remove_dir_all
/// it is considered a success if the directory was not there.
fn remove_dir_all_idem(dir: &Path) -> std::io::Result<()> {
match std::fs::remove_dir_all(dir) {
Ok(_) => Ok(()),
// If the directory doesn't exist, it is still a success.
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
Err(err) => Err(err),
}
}

/// Deletes the Miri sysroot cache
/// Returns an error if the MIRI_SYSROOT env var is set.
pub fn clean_sysroot() {
if std::env::var_os("MIRI_SYSROOT").is_some() {
show_error!(
"MIRI_SYSROOT is set. Please clean your custom sysroot cache directory manually."
)
}

let sysroot_dir = get_sysroot_dir();

eprintln!("Cleaning sysroot cache at {}", sysroot_dir.display());

// Keep it simple, just remove the directory.
remove_dir_all_idem(&sysroot_dir).unwrap_or_else(|err| show_error!("{}", err));
}

/// Deletes the Miri target directory
pub fn clean_target_dir(meta: &Metadata) {
let target_dir = get_target_dir(meta);

eprintln!("Cleaning target directory at {}", target_dir.display());

remove_dir_all_idem(&target_dir).unwrap_or_else(|err| show_error!("{}", err))
}

0 comments on commit 4db9a36

Please sign in to comment.