From 8f27ab3020e03e9aedbe14be4ca5c9b358e8b474 Mon Sep 17 00:00:00 2001 From: Konstantin Andrikopoulos Date: Sat, 16 Nov 2024 15:27:31 +0100 Subject: [PATCH 1/4] experiment with using clap --- miri-script/Cargo.lock | 122 +++++++++++++++++++- miri-script/Cargo.toml | 1 + miri-script/src/args.rs | 135 ---------------------- miri-script/src/main.rs | 241 ++++++++++++---------------------------- 4 files changed, 194 insertions(+), 305 deletions(-) delete mode 100644 miri-script/src/args.rs diff --git a/miri-script/Cargo.lock b/miri-script/Cargo.lock index 0c0fe477cd..0208327a8d 100644 --- a/miri-script/Cargo.lock +++ b/miri-script/Cargo.lock @@ -2,6 +2,55 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + [[package]] name = "anyhow" version = "1.0.80" @@ -20,6 +69,52 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + [[package]] name = "directories" version = "5.0.1" @@ -80,6 +175,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "home" version = "0.5.9" @@ -89,6 +190,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.11.0" @@ -137,6 +244,7 @@ name = "miri-script" version = "0.1.0" dependencies = [ "anyhow", + "clap", "directories", "dunce", "itertools", @@ -278,6 +386,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.50" @@ -328,6 +442,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "walkdir" version = "2.4.0" @@ -362,7 +482,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/miri-script/Cargo.toml b/miri-script/Cargo.toml index 5b31d5a6ff..0ab49bbacf 100644 --- a/miri-script/Cargo.toml +++ b/miri-script/Cargo.toml @@ -25,3 +25,4 @@ dunce = "1.0.4" directories = "5" serde_json = "1" tempfile = "3.13.0" +clap = { version = "4.5.21", features = ["derive"] } diff --git a/miri-script/src/args.rs b/miri-script/src/args.rs deleted file mode 100644 index 55d9de4233..0000000000 --- a/miri-script/src/args.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::{env, iter}; - -use anyhow::{Result, bail}; - -pub struct Args { - args: iter::Peekable, - /// Set to `true` once we saw a `--`. - terminated: bool, -} - -impl Args { - pub fn new() -> Self { - let mut args = Args { args: env::args().peekable(), terminated: false }; - args.args.next().unwrap(); // skip program name - args - } - - /// Get the next argument without any interpretation. - pub fn next_raw(&mut self) -> Option { - self.args.next() - } - - /// Consume a `-$f` flag if present. - pub fn get_short_flag(&mut self, flag: char) -> Result { - if self.terminated { - return Ok(false); - } - if let Some(next) = self.args.peek() { - if let Some(next) = next.strip_prefix("-") { - if let Some(next) = next.strip_prefix(flag) { - if next.is_empty() { - self.args.next().unwrap(); // consume this argument - return Ok(true); - } else { - bail!("`-{flag}` followed by value"); - } - } - } - } - Ok(false) - } - - /// Consume a `--$name` flag if present. - pub fn get_long_flag(&mut self, name: &str) -> Result { - if self.terminated { - return Ok(false); - } - if let Some(next) = self.args.peek() { - if let Some(next) = next.strip_prefix("--") { - if next == name { - self.args.next().unwrap(); // consume this argument - return Ok(true); - } - } - } - Ok(false) - } - - /// Consume a `--$name val` or `--$name=val` option if present. - pub fn get_long_opt(&mut self, name: &str) -> Result> { - assert!(!name.is_empty()); - if self.terminated { - return Ok(None); - } - let Some(next) = self.args.peek() else { return Ok(None) }; - let Some(next) = next.strip_prefix("--") else { return Ok(None) }; - let Some(next) = next.strip_prefix(name) else { return Ok(None) }; - // Starts with `--flag`. - Ok(if let Some(val) = next.strip_prefix("=") { - // `--flag=val` form - let val = val.into(); - self.args.next().unwrap(); // consume this argument - Some(val) - } else if next.is_empty() { - // `--flag val` form - self.args.next().unwrap(); // consume this argument - let Some(val) = self.args.next() else { bail!("`--{name}` not followed by value") }; - Some(val) - } else { - // Some unrelated flag, like `--flag-more` or so. - None - }) - } - - /// Consume a `--$name=val` or `--$name` option if present; the latter - /// produces a default value. (`--$name val` is *not* accepted for this form - /// of argument, it understands `val` already as the next argument!) - pub fn get_long_opt_with_default( - &mut self, - name: &str, - default: &str, - ) -> Result> { - assert!(!name.is_empty()); - if self.terminated { - return Ok(None); - } - let Some(next) = self.args.peek() else { return Ok(None) }; - let Some(next) = next.strip_prefix("--") else { return Ok(None) }; - let Some(next) = next.strip_prefix(name) else { return Ok(None) }; - // Starts with `--flag`. - Ok(if let Some(val) = next.strip_prefix("=") { - // `--flag=val` form - let val = val.into(); - self.args.next().unwrap(); // consume this argument - Some(val) - } else if next.is_empty() { - // `--flag` form - self.args.next().unwrap(); // consume this argument - Some(default.into()) - } else { - // Some unrelated flag, like `--flag-more` or so. - None - }) - } - - /// Returns the next free argument or uninterpreted flag, or `None` if there are no more - /// arguments left. `--` is returned as well, but it is interpreted in the sense that no more - /// flags will be parsed after this. - pub fn get_other(&mut self) -> Option { - if self.terminated { - return self.args.next(); - } - let next = self.args.next()?; - if next == "--" { - self.terminated = true; // don't parse any more flags - // This is where our parser is special, we do yield the `--`. - } - Some(next) - } - - /// Return the rest of the aguments entirely unparsed. - pub fn remainder(self) -> Vec { - self.args.collect() - } -} diff --git a/miri-script/src/main.rs b/miri-script/src/main.rs index e1bf3c1862..f0f4778f83 100644 --- a/miri-script/src/main.rs +++ b/miri-script/src/main.rs @@ -1,15 +1,33 @@ #![allow(clippy::needless_question_mark)] -mod args; mod commands; mod coverage; mod util; use std::ops::Range; -use anyhow::{Context, Result, anyhow, bail}; +use anyhow::{Context, Result, anyhow}; +use clap::{Parser, Subcommand}; + +/// Parses a seed range +/// +/// This function is used for the `--many-seeds` flag. It expects the range in the form +/// `..`. `` is inclusive, `` is exclusive. `` can be omitted, +/// in which case it is assumed to be `0`. +fn parse_range(val: &str) -> anyhow::Result> { + let (from, to) = val + .split_once("..") + .ok_or_else(|| anyhow!("invalid format for `--many-seeds`: expected `from..to`"))?; + let from: u32 = if from.is_empty() { + 0 + } else { + from.parse().context("invalid `from` in `--many-seeds=from..to")? + }; + let to: u32 = to.parse().context("invalid `to` in `--many-seeds=from..to")?; + Ok(from..to) +} -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Subcommand)] pub enum Command { /// Installs the miri driver and cargo-miri. /// Sets up the rpath such that the installed binary should work in any @@ -17,57 +35,74 @@ pub enum Command { /// sysroot, to prevent conflicts with other toolchains. Install { /// Flags that are passed through to `cargo install`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Just build miri. Build { /// Flags that are passed through to `cargo build`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Just check miri. Check { /// Flags that are passed through to `cargo check`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Build miri, set up a sysroot and then run the test suite. Test { + #[arg(long)] bless: bool, /// The cross-interpretation target. /// If none then the host is the target. + #[arg(long)] target: Option, /// Produce coverage report if set. + #[arg(long)] coverage: bool, /// Flags that are passed through to the test harness. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Build miri, set up a sysroot and then run the driver with the given . /// (Also respects MIRIFLAGS environment variable.) Run { + #[arg(long)] dep: bool, + #[arg(long, short)] verbose: bool, + #[arg(long, value_parser = parse_range)] many_seeds: Option>, + #[arg(long)] target: Option, + #[arg(long)] edition: Option, /// Flags that are passed through to `miri`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Build documentation Doc { /// Flags that are passed through to `cargo doc`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Format all sources and tests. Fmt { /// Flags that are passed through to `rustfmt`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Runs clippy on all sources. Clippy { /// Flags that are passed through to `cargo clippy`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. Bench { + #[arg(long)] target: Option, /// When `true`, skip the `./miri install` step. no_install: bool, @@ -89,176 +124,44 @@ pub enum Command { RustcPush { github_user: String, branch: String }, } -const HELP: &str = r#" COMMANDS - -./miri build : -Just build miri. are passed to `cargo build`. - -./miri check : -Just check miri. are passed to `cargo check`. - -./miri test [--bless] [--target ] : -Build miri, set up a sysroot and then run the test suite. - are passed to the test harness. - -./miri run [--dep] [-v|--verbose] [--many-seeds|--many-seeds=..to|--many-seeds=from..to] : -Build miri, set up a sysroot and then run the driver with the given . -(Also respects MIRIFLAGS environment variable.) -If `--many-seeds` is present, Miri is run many times in parallel with different seeds. -The range defaults to `0..64`. - -./miri fmt : -Format all sources and tests. are passed to `rustfmt`. - -./miri clippy : -Runs clippy on all sources. are passed to `cargo clippy`. - -./miri cargo : -Runs just `cargo ` with the Miri-specific environment variables. -Mainly meant to be invoked by rust-analyzer. - -./miri install : -Installs the miri driver and cargo-miri. are passed to `cargo -install`. Sets up the rpath such that the installed binary should work in any -working directory. Note that the binaries are placed in the `miri` toolchain -sysroot, to prevent conflicts with other toolchains. - -./miri bench [--target ] [--no-install] : -Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. - can explicitly list the benchmarks to run; by default, all of them are run. -By default, this runs `./miri install` to ensure the latest local Miri is being benchmarked; -`--no-install` can be used to skip that step. - -./miri toolchain : -Update and activate the rustup toolchain 'miri' to the commit given in the -`rust-version` file. -`rustup-toolchain-install-master` must be installed for this to work. Any extra -flags are passed to `rustup-toolchain-install-master`. - -./miri rustc-pull : -Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest -rustc commit. The fetched commit is stored in the `rust-version` file, so the -next `./miri toolchain` will install the rustc that just got pulled. - -./miri rustc-push []: -Push Miri changes back to the rustc repo. This will pull a copy of the rustc -history into the Miri repo, unless you set the RUSTC_GIT env var to an existing -clone of the rustc repo. The branch defaults to `miri-sync`. - - ENVIRONMENT VARIABLES +impl Command { + fn add_remainder(&mut self, remainder: Vec) -> Result<()> { + if remainder.is_empty() { + return Ok(()); + } -MIRI_SYSROOT: -If already set, the "sysroot setup" step is skipped. + match self { + Self::Install { flags } + | Self::Build { flags } + | Self::Check { flags } + | Self::Doc { flags } + | Self::Fmt { flags } + | Self::Toolchain { flags } + | Self::Clippy { flags } + | Self::Run { flags, .. } + | Self::Test { flags, .. } => { + flags.extend(remainder); + Ok(()) + } + Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } => + Err(anyhow::Error::msg("unexpected \"--\" found in arguments")), + } + } +} -CARGO_EXTRA_FLAGS: -Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)"#; +#[derive(Parser)] +pub struct Cli { + #[command(subcommand)] + pub command: Command, +} fn main() -> Result<()> { - // We are hand-rolling our own argument parser, since `clap` can't express what we need - // (https://github.com/clap-rs/clap/issues/5055). - let mut args = args::Args::new(); - let command = match args.next_raw().as_deref() { - Some("build") => Command::Build { flags: args.remainder() }, - Some("check") => Command::Check { flags: args.remainder() }, - Some("doc") => Command::Doc { flags: args.remainder() }, - Some("test") => { - let mut target = None; - let mut bless = false; - let mut flags = Vec::new(); - let mut coverage = false; - loop { - if args.get_long_flag("bless")? { - bless = true; - } else if args.get_long_flag("coverage")? { - coverage = true; - } else if let Some(val) = args.get_long_opt("target")? { - target = Some(val); - } else if let Some(flag) = args.get_other() { - flags.push(flag); - } else { - break; - } - } - Command::Test { bless, flags, target, coverage } - } - Some("run") => { - let mut dep = false; - let mut verbose = false; - let mut many_seeds = None; - let mut target = None; - let mut edition = None; - let mut flags = Vec::new(); - loop { - if args.get_long_flag("dep")? { - dep = true; - } else if args.get_long_flag("verbose")? || args.get_short_flag('v')? { - verbose = true; - } else if let Some(val) = args.get_long_opt_with_default("many-seeds", "0..64")? { - let (from, to) = val.split_once("..").ok_or_else(|| { - anyhow!("invalid format for `--many-seeds`: expected `from..to`") - })?; - let from: u32 = if from.is_empty() { - 0 - } else { - from.parse().context("invalid `from` in `--many-seeds=from..to")? - }; - let to: u32 = to.parse().context("invalid `to` in `--many-seeds=from..to")?; - many_seeds = Some(from..to); - } else if let Some(val) = args.get_long_opt("target")? { - target = Some(val); - } else if let Some(val) = args.get_long_opt("edition")? { - edition = Some(val); - } else if let Some(flag) = args.get_other() { - flags.push(flag); - } else { - break; - } - } - Command::Run { dep, verbose, many_seeds, target, edition, flags } - } - Some("fmt") => Command::Fmt { flags: args.remainder() }, - Some("clippy") => Command::Clippy { flags: args.remainder() }, - Some("install") => Command::Install { flags: args.remainder() }, - Some("bench") => { - let mut target = None; - let mut benches = Vec::new(); - let mut no_install = false; - loop { - if let Some(val) = args.get_long_opt("target")? { - target = Some(val); - } else if args.get_long_flag("no-install")? { - no_install = true; - } else if let Some(flag) = args.get_other() { - benches.push(flag); - } else { - break; - } - } - Command::Bench { target, benches, no_install } - } - Some("toolchain") => Command::Toolchain { flags: args.remainder() }, - Some("rustc-pull") => { - let commit = args.next_raw(); - if args.next_raw().is_some() { - bail!("Too many arguments for `./miri rustc-pull`"); - } - Command::RustcPull { commit } - } - Some("rustc-push") => { - let github_user = args.next_raw().ok_or_else(|| { - anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER [BRANCH]`") - })?; - let branch = args.next_raw().unwrap_or_else(|| "miri-sync".into()); - if args.next_raw().is_some() { - bail!("Too many arguments for `./miri rustc-push GITHUB_USER BRANCH`"); - } - Command::RustcPush { github_user, branch } - } - _ => { - eprintln!("Unknown or missing command. Usage:\n\n{HELP}"); - std::process::exit(1); - } - }; + let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); + let remainder: Vec<_> = std::env::args().skip_while(|x| *x != "--").collect(); + + let args = Cli::parse_from(miri_args); + let mut command = args.command; + command.add_remainder(remainder)?; command.exec()?; Ok(()) } From 147bbd085ae80df9aaf2b247a883004c85af3e12 Mon Sep 17 00:00:00 2001 From: Kostis Andrikopoulos Date: Fri, 13 Dec 2024 21:21:12 +0100 Subject: [PATCH 2/4] Update miri-script/src/main.rs Co-authored-by: Ralf Jung --- miri-script/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miri-script/src/main.rs b/miri-script/src/main.rs index f0f4778f83..1e816e7262 100644 --- a/miri-script/src/main.rs +++ b/miri-script/src/main.rs @@ -156,6 +156,8 @@ pub struct Cli { } fn main() -> Result<()> { + /// Split the arguments into the part before the `--` and the part after. + /// The `--` itself ends up in the second part. let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); let remainder: Vec<_> = std::env::args().skip_while(|x| *x != "--").collect(); From cb10ece26f778e932bf5009c30a0274d326703a6 Mon Sep 17 00:00:00 2001 From: Konstantin Andrikopoulos Date: Fri, 13 Dec 2024 21:32:51 +0100 Subject: [PATCH 3/4] address comments --- miri-script/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miri-script/src/main.rs b/miri-script/src/main.rs index 1e816e7262..ab0c4e1391 100644 --- a/miri-script/src/main.rs +++ b/miri-script/src/main.rs @@ -6,7 +6,7 @@ mod util; use std::ops::Range; -use anyhow::{Context, Result, anyhow}; +use anyhow::{Context, Result, anyhow, bail}; use clap::{Parser, Subcommand}; /// Parses a seed range @@ -144,7 +144,7 @@ impl Command { Ok(()) } Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } => - Err(anyhow::Error::msg("unexpected \"--\" found in arguments")), + bail!("unexpected \"--\" found in arguments"), } } } @@ -156,8 +156,8 @@ pub struct Cli { } fn main() -> Result<()> { - /// Split the arguments into the part before the `--` and the part after. - /// The `--` itself ends up in the second part. + // Split the arguments into the part before the `--` and the part after. + // The `--` itself ends up in the second part. let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); let remainder: Vec<_> = std::env::args().skip_while(|x| *x != "--").collect(); From 1309e4c3eb1c57329626875f77aa0ee6da83c16e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Dec 2024 09:59:44 +0100 Subject: [PATCH 4/4] fix 'rustc-push' and adjust help texts --- miri-script/src/main.rs | 92 +++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 32 deletions(-) diff --git a/miri-script/src/main.rs b/miri-script/src/main.rs index ab0c4e1391..7592e56cfc 100644 --- a/miri-script/src/main.rs +++ b/miri-script/src/main.rs @@ -29,60 +29,74 @@ fn parse_range(val: &str) -> anyhow::Result> { #[derive(Clone, Debug, Subcommand)] pub enum Command { - /// Installs the miri driver and cargo-miri. + /// Installs the miri driver and cargo-miri to the sysroot of the active toolchain. + /// /// Sets up the rpath such that the installed binary should work in any - /// working directory. Note that the binaries are placed in the `miri` toolchain - /// sysroot, to prevent conflicts with other toolchains. + /// working directory. Install { /// Flags that are passed through to `cargo install`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Just build miri. + /// Build Miri. Build { /// Flags that are passed through to `cargo build`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Just check miri. + /// Check Miri. Check { /// Flags that are passed through to `cargo check`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Build miri, set up a sysroot and then run the test suite. + /// Check Miri with Clippy. + Clippy { + /// Flags that are passed through to `cargo clippy`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + flags: Vec, + }, + /// Run the Miri test suite. Test { + /// Update stdout/stderr reference files. #[arg(long)] bless: bool, /// The cross-interpretation target. - /// If none then the host is the target. #[arg(long)] target: Option, - /// Produce coverage report if set. + /// Produce coverage report. #[arg(long)] coverage: bool, /// Flags that are passed through to the test harness. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Build miri, set up a sysroot and then run the driver with the given . - /// (Also respects MIRIFLAGS environment variable.) + /// Run the Miri driver. + /// + /// Also respects MIRIFLAGS environment variable. Run { + /// Build the program with the dependencies declared in `test_dependencies/Cargo.toml`. #[arg(long)] dep: bool, + /// Show build progress. #[arg(long, short)] verbose: bool, + /// Run the driver with the seeds in the given range (`..to` or `from..to`, default: `0..64`). #[arg(long, value_parser = parse_range)] many_seeds: Option>, + /// The cross-interpretation target. #[arg(long)] target: Option, + /// The Rust edition. #[arg(long)] edition: Option, /// Flags that are passed through to `miri`. + /// + /// The flags set in `MIRIFLAGS` are added in front of these flags. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Build documentation + /// Build documentation. Doc { /// Flags that are passed through to `cargo doc`. #[arg(trailing_var_arg = true, allow_hyphen_values = true)] @@ -94,34 +108,45 @@ pub enum Command { #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec, }, - /// Runs clippy on all sources. - Clippy { - /// Flags that are passed through to `cargo clippy`. - #[arg(trailing_var_arg = true, allow_hyphen_values = true)] - flags: Vec, - }, - /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. + /// Runs the benchmarks from bench-cargo-miri in hyperfine. + /// + /// hyperfine needs to be installed. Bench { #[arg(long)] target: Option, /// When `true`, skip the `./miri install` step. + #[arg(long)] no_install: bool, - /// List of benchmarks to run. By default all benchmarks are run. + /// List of benchmarks to run (default: run all benchmarks). benches: Vec, }, - /// Update and activate the rustup toolchain 'miri' to the commit given in the - /// `rust-version` file. - /// `rustup-toolchain-install-master` must be installed for this to work. Any extra - /// flags are passed to `rustup-toolchain-install-master`. - Toolchain { flags: Vec }, - /// Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest - /// rustc commit. The fetched commit is stored in the `rust-version` file, so the - /// next `./miri toolchain` will install the rustc that just got pulled. - RustcPull { commit: Option }, - /// Push Miri changes back to the rustc repo. This will pull a copy of the rustc - /// history into the Miri repo, unless you set the RUSTC_GIT env var to an existing - /// clone of the rustc repo. - RustcPush { github_user: String, branch: String }, + /// Update and activate the rustup toolchain 'miri'. + /// + /// The `rust-version` file is used to determine the commit that will be intsalled. + /// `rustup-toolchain-install-master` must be installed for this to work. + Toolchain { + /// Flags that are passed through to `rustup-toolchain-install-master`. + flags: Vec, + }, + /// Pull and merge Miri changes from the rustc repo. + /// + /// The fetched commit is stored in the `rust-version` file, so the next `./miri toolchain` will + /// install the rustc that just got pulled. + RustcPull { + /// The commit to fetch (default: latest rustc commit). + commit: Option, + }, + /// Push Miri changes back to the rustc repo. + /// + /// This will pull a copy of the rustc history into the Miri repo, unless you set the RUSTC_GIT + /// env var to an existing clone of the rustc repo. + RustcPush { + /// The Github user that owns the rustc fork to which we should push. + github_user: String, + /// The branch to push to. + #[arg(default_value = "miri-sync")] + branch: String, + }, } impl Command { @@ -150,6 +175,9 @@ impl Command { } #[derive(Parser)] +#[command(after_help = "Environment variables: + MIRI_SYSROOT: If already set, the \"sysroot setup\" step is skipped + CARGO_EXTRA_FLAGS: Pass extra flags to all cargo invocations")] pub struct Cli { #[command(subcommand)] pub command: Command,