about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-02-24 18:00:29 +0000
committerbors <bors@rust-lang.org>2024-02-24 18:00:29 +0000
commit4db9a3652ab8b57f4ccb844fe045fa28b07efefe (patch)
tree6cb44ce649470e28964574f2f2d9999cdc0efb6e /src
parent2f1c9db3cf34593b93048060a00e13b325b64283 (diff)
parent3e7c2e1f6dcfb2d1b1c81885c274a4d73f91b0f3 (diff)
downloadrust-4db9a3652ab8b57f4ccb844fe045fa28b07efefe.tar.gz
rust-4db9a3652ab8b57f4ccb844fe045fa28b07efefe.zip
Auto merge of #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.
Diffstat (limited to 'src')
-rw-r--r--src/tools/miri/README.md4
-rw-r--r--src/tools/miri/cargo-miri/src/phases.rs23
-rw-r--r--src/tools/miri/cargo-miri/src/setup.rs9
-rw-r--r--src/tools/miri/cargo-miri/src/util.rs64
4 files changed, 84 insertions, 16 deletions
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 60bf07b1736..944d2bbe879 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -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`"
 
@@ -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
diff --git a/src/tools/miri/cargo-miri/src/phases.rs b/src/tools/miri/cargo-miri/src/phases.rs
index 79ce1f4ca32..315f7a23a91 100644
--- a/src/tools/miri/cargo-miri/src/phases.rs
+++ b/src/tools/miri/cargo-miri/src/phases.rs
@@ -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.
 
@@ -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");
@@ -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);
 
@@ -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();
@@ -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
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index 8ae5b8c3e82..a98e1fcd485 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -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 =>
diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs
index 3c591268455..6c1a074cd8c 100644
--- a/src/tools/miri/cargo-miri/src/util.rs
+++ b/src/tools/miri/cargo-miri/src/util.rs
@@ -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.
@@ -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))
+}