Auto merge of #2909 - osiewicz:rewrite-miri-script-in-rust-2883, r=RalfJung
Rewrite miri script in rust This is a sketch of a rewrite of miri script in Rust. It does not include changes made in https://github.com/rust-lang/miri/pull/2908 yet. Environment variables are not properly propagated yet, which is something I plan to address. This PR is mostly a heads-up about the ongoing effort and it's state. It's definitely not the cleanest code I've seen in my life, but my first goal was feature/interface parity. I will iterate on it a bit before marking it as ready. I wonder though how this should be integrated/tested. Are you aware of anyone using `./miri` in their scripts? I guess we should keep existing `miri` script in place and let it run miri-script package directly? CI should probably `cargo check` this package as well. Fixes #2883
This commit is contained in:
commit
e1071af908
11 changed files with 1016 additions and 361 deletions
2
src/tools/miri/.github/workflows/ci.yml
vendored
2
src/tools/miri/.github/workflows/ci.yml
vendored
|
|
@ -130,7 +130,7 @@ jobs:
|
|||
- name: clippy
|
||||
run: ./miri clippy -- -D warnings
|
||||
- name: rustdoc
|
||||
run: RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items
|
||||
run: RUSTDOCFLAGS="-Dwarnings" ./miri cargo doc --document-private-items
|
||||
|
||||
# These jobs doesn't actually test anything, but they're only used to tell
|
||||
# bors the build completed, as there is no practical way to detect when a
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ evaluation error was originally raised.
|
|||
### UI testing
|
||||
|
||||
We use ui-testing in Miri, meaning we generate `.stderr` and `.stdout` files for the output
|
||||
produced by Miri. You can use `./miri bless` to automatically (re)generate these files when
|
||||
produced by Miri. You can use `./miri test --bless` to automatically (re)generate these files when
|
||||
you add new tests or change how Miri presents certain output.
|
||||
|
||||
Note that when you also use `MIRIFLAGS` to change optimizations and similar, the ui output
|
||||
|
|
|
|||
|
|
@ -538,8 +538,7 @@ pub fn phase_runner(mut binary_args: impl Iterator<Item = String>, phase: Runner
|
|||
}
|
||||
// Respect `MIRIFLAGS`.
|
||||
if let Ok(a) = env::var("MIRIFLAGS") {
|
||||
// This code is taken from `RUSTFLAGS` handling in cargo.
|
||||
let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string);
|
||||
let args = flagsplit(&a);
|
||||
cmd.args(args);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,6 +114,11 @@ pub fn cargo() -> Command {
|
|||
Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo")))
|
||||
}
|
||||
|
||||
pub fn flagsplit(flags: &str) -> Vec<String> {
|
||||
// This code is taken from `RUSTFLAGS` handling in cargo.
|
||||
flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect()
|
||||
}
|
||||
|
||||
/// Execute the `Command`, where possible by replacing the current process with a new process
|
||||
/// described by the `Command`. Then exit this process with the exit code of the new process.
|
||||
pub fn exec(mut cmd: Command) -> ! {
|
||||
|
|
|
|||
|
|
@ -1,359 +1,6 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
USAGE=$(cat <<"EOF"
|
||||
COMMANDS
|
||||
|
||||
./miri install <flags>:
|
||||
Installs the miri driver and cargo-miri. <flags> 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 build <flags>:
|
||||
Just build miri. <flags> are passed to `cargo build`.
|
||||
|
||||
./miri check <flags>:
|
||||
Just check miri. <flags> are passed to `cargo check`.
|
||||
|
||||
./miri test <flags>:
|
||||
Build miri, set up a sysroot and then run the test suite. <flags> are passed
|
||||
to the final `cargo test` invocation.
|
||||
|
||||
./miri run <flags>:
|
||||
Build miri, set up a sysroot and then run the driver with the given <flags>.
|
||||
(Also respects MIRIFLAGS environment variable.)
|
||||
|
||||
./miri fmt <flags>:
|
||||
Format all sources and tests. <flags> are passed to `rustfmt`.
|
||||
|
||||
./miri clippy <flags>:
|
||||
Runs clippy on all sources. <flags> are passed to `cargo clippy`.
|
||||
|
||||
./miri cargo <flags>:
|
||||
Runs just `cargo <flags>` with the Miri-specific environment variables.
|
||||
Mainly meant to be invoked by rust-analyzer.
|
||||
|
||||
./miri many-seeds <command>:
|
||||
Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
|
||||
variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
|
||||
many different seeds. The MIRI_SEEDS variable controls how many seeds are being
|
||||
tried; MIRI_SEED_START controls the first seed to try.
|
||||
|
||||
./miri bench <benches>:
|
||||
Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
|
||||
<benches> can explicitly list the benchmarks to run; by default, all of them are run.
|
||||
|
||||
./miri toolchain <flags>:
|
||||
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 <commit>:
|
||||
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 <github user> <branch>:
|
||||
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.
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
|
||||
MIRI_SYSROOT:
|
||||
If already set, the "sysroot setup" step is skipped.
|
||||
|
||||
CARGO_EXTRA_FLAGS:
|
||||
Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)
|
||||
EOF
|
||||
)
|
||||
|
||||
## We need to know which command to run and some global constants.
|
||||
COMMAND="$1"
|
||||
if [ -z "$COMMAND" ]; then
|
||||
echo "$USAGE"
|
||||
exit 1
|
||||
fi
|
||||
shift
|
||||
# macOS does not have a useful readlink/realpath so we have to use Python instead...
|
||||
MIRIDIR=$(python3 -c 'import pathlib, sys; print(pathlib.Path(sys.argv[1]).resolve().parent.as_posix())' "$0")
|
||||
# Used for rustc syncs.
|
||||
JOSH_FILTER=":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri"
|
||||
# Needed for `./miri bench`.
|
||||
TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1)
|
||||
|
||||
## Early commands, that don't do auto-things and don't want the environment-altering things happening below.
|
||||
case "$COMMAND" in
|
||||
toolchain)
|
||||
cd "$MIRIDIR"
|
||||
NEW_COMMIT=$(cat rust-version)
|
||||
# Make sure rustup-toolchain-install-master is installed.
|
||||
if ! which rustup-toolchain-install-master >/dev/null; then
|
||||
echo "Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'"
|
||||
exit 1
|
||||
fi
|
||||
# Check if we already are at that commit.
|
||||
CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | grep "^commit-hash: " | cut -d " " -f 2)
|
||||
if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then
|
||||
echo "miri toolchain is already at commit $CUR_COMMIT."
|
||||
if [[ "$TOOLCHAIN" != "miri" ]]; then
|
||||
rustup override set miri
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
# Install and setup new toolchain.
|
||||
rustup toolchain uninstall miri
|
||||
rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy "$@" -- "$NEW_COMMIT"
|
||||
rustup override set miri
|
||||
# Cleanup.
|
||||
cargo clean
|
||||
# Call 'cargo metadata' on the sources in case that changes the lockfile
|
||||
# (which fails under some setups when it is done from inside vscode).
|
||||
cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null
|
||||
# Done!
|
||||
exit 0
|
||||
;;
|
||||
rustc-pull)
|
||||
cd "$MIRIDIR"
|
||||
FETCH_COMMIT="$1"
|
||||
if [ -z "$FETCH_COMMIT" ]; then
|
||||
FETCH_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1)
|
||||
fi
|
||||
# Update rust-version file. As a separate commit, since making it part of
|
||||
# the merge has confused the heck out of josh in the past.
|
||||
echo "$FETCH_COMMIT" > rust-version
|
||||
git commit rust-version -m "Preparing for merge from rustc" || (echo "FAILED to commit rust-version file, something went wrong"; exit 1)
|
||||
# Fetch given rustc commit and note down which one that was
|
||||
git fetch http://localhost:8000/rust-lang/rust.git@$FETCH_COMMIT$JOSH_FILTER.git || (echo "FAILED to fetch new commits, something went wrong"; exit 1)
|
||||
git merge FETCH_HEAD --no-ff -m "Merge from rustc" || (echo "FAILED to merge new commits ($(git rev-parse FETCH_HEAD)), something went wrong"; exit 1)
|
||||
exit 0
|
||||
;;
|
||||
rustc-push)
|
||||
USER="$1"
|
||||
BRANCH="$2"
|
||||
if [ -z "$USER" ] || [ -z "$BRANCH" ]; then
|
||||
echo "Usage: $0 rustc-push <github user> <branch>"
|
||||
exit 1
|
||||
fi
|
||||
if [ -n "$RUSTC_GIT" ]; then
|
||||
# Use an existing fork for the branch updates.
|
||||
cd "$RUSTC_GIT"
|
||||
else
|
||||
# Do this in the local Miri repo.
|
||||
echo "This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
|
||||
read -r -p "To avoid that, abort now and set the RUSTC_GIT environment variable to an existing rustc checkout. Proceed? [y/N] "
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
cd "$MIRIDIR"
|
||||
fi
|
||||
# Prepare the branch. Pushing works much better if we use as base exactly
|
||||
# the commit that we pulled from last time, so we use the `rust-version`
|
||||
# file as a good approximation of that.
|
||||
BASE=$(cat "$MIRIDIR/rust-version")
|
||||
echo "Preparing $USER/rust (base: $BASE)..."
|
||||
if git fetch "https://github.com/$USER/rust" "$BRANCH" &>/dev/null; then
|
||||
echo "The branch '$BRANCH' seems to already exist in 'https://github.com/$USER/rust'. Please delete it and try again."
|
||||
exit 1
|
||||
fi
|
||||
git fetch https://github.com/rust-lang/rust $BASE
|
||||
git push https://github.com/$USER/rust $BASE:refs/heads/$BRANCH -f
|
||||
echo
|
||||
# Do the actual push.
|
||||
cd "$MIRIDIR"
|
||||
echo "Pushing Miri changes..."
|
||||
git push http://localhost:8000/$USER/rust.git$JOSH_FILTER.git HEAD:$BRANCH
|
||||
# Do a round-trip check to make sure the push worked as expected.
|
||||
echo
|
||||
git fetch http://localhost:8000/$USER/rust.git@$JOSH_FILTER.git $BRANCH &>/dev/null
|
||||
if [[ $(git rev-parse HEAD) != $(git rev-parse FETCH_HEAD) ]]; then
|
||||
echo "ERROR: Josh created a non-roundtrip push! Do NOT merge this into rustc!"
|
||||
exit 1
|
||||
else
|
||||
echo "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
|
||||
echo " https://github.com/$USER/rust/pull/new/$BRANCH"
|
||||
exit 0
|
||||
fi
|
||||
;;
|
||||
many-seeds)
|
||||
MIRI_SEED_START=${MIRI_SEED_START:-0} # default to 0
|
||||
MIRI_SEEDS=${MIRI_SEEDS:-256} # default to 256
|
||||
for SEED in $(seq $MIRI_SEED_START $(( $MIRI_SEED_START + $MIRI_SEEDS - 1 )) ); do
|
||||
echo "Trying seed: $SEED"
|
||||
MIRIFLAGS="$MIRIFLAGS -Zlayout-seed=$SEED -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; }
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
bench)
|
||||
# The hyperfine to use
|
||||
HYPERFINE=${HYPERFINE:-hyperfine -w 1 -m 5 --shell=none}
|
||||
# Make sure we have an up-to-date Miri installed
|
||||
"$0" install
|
||||
# Run the requested benchmarks
|
||||
if [ -z "${1+exists}" ]; then
|
||||
BENCHES=( $(ls "$MIRIDIR/bench-cargo-miri" ) )
|
||||
else
|
||||
BENCHES=("$@")
|
||||
fi
|
||||
for BENCH in "${BENCHES[@]}"; do
|
||||
$HYPERFINE "cargo +$TOOLCHAIN miri run --manifest-path $MIRIDIR/bench-cargo-miri/$BENCH/Cargo.toml"
|
||||
done
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
## Run the auto-things.
|
||||
if [ -z "$MIRI_AUTO_OPS" ]; then
|
||||
export MIRI_AUTO_OPS=42
|
||||
|
||||
# Run this first, so that the toolchain doesn't change after
|
||||
# other code has run.
|
||||
if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then
|
||||
$0 toolchain
|
||||
# Let's make sure to actually use that toolchain, too.
|
||||
TOOLCHAIN=miri
|
||||
fi
|
||||
|
||||
if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then
|
||||
$0 fmt
|
||||
fi
|
||||
|
||||
if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-clippy" ] ; then
|
||||
$0 clippy -- -D warnings
|
||||
fi
|
||||
fi
|
||||
|
||||
## Prepare the environment
|
||||
# Determine some toolchain properties
|
||||
TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2)
|
||||
SYSROOT=$(rustc +$TOOLCHAIN --print sysroot)
|
||||
LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib
|
||||
if ! test -d "$LIBDIR"; then
|
||||
echo "Something went wrong determining the library dir."
|
||||
echo "I got $LIBDIR but that does not exist."
|
||||
echo "Please report a bug at https://github.com/rust-lang/miri/issues."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# Prepare flags for cargo and rustc.
|
||||
CARGO="cargo +$TOOLCHAIN"
|
||||
# Share target dir between `miri` and `cargo-miri`.
|
||||
if [ -z "$CARGO_TARGET_DIR" ]; then
|
||||
export CARGO_TARGET_DIR="$MIRIDIR/target"
|
||||
fi
|
||||
# We configure dev builds to not be unusably slow.
|
||||
if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then
|
||||
export CARGO_PROFILE_DEV_OPT_LEVEL=2
|
||||
fi
|
||||
# Enable rustc-specific lints (ignored without `-Zunstable-options`).
|
||||
export RUSTFLAGS="-Zunstable-options -Wrustc::internal -Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros $RUSTFLAGS"
|
||||
# We set the rpath so that Miri finds the private rustc libraries it needs.
|
||||
export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS"
|
||||
|
||||
## Helper functions
|
||||
|
||||
# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`.
|
||||
build_sysroot() {
|
||||
if ! MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup --print-sysroot "$@")"; then
|
||||
# Run it again so the user can see the error.
|
||||
$CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@"
|
||||
echo "'cargo miri setup' failed"
|
||||
exit 1
|
||||
fi
|
||||
export MIRI_SYSROOT
|
||||
}
|
||||
|
||||
# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account
|
||||
# locally built vs. distributed rustc.
|
||||
find_sysroot() {
|
||||
if [ -n "$MIRI_SYSROOT" ]; then
|
||||
# Sysroot already set, use that.
|
||||
return 0
|
||||
fi
|
||||
# We need to build a sysroot.
|
||||
if [ -n "$MIRI_TEST_TARGET" ]; then
|
||||
build_sysroot --target "$MIRI_TEST_TARGET"
|
||||
else
|
||||
build_sysroot
|
||||
fi
|
||||
}
|
||||
|
||||
## Main
|
||||
|
||||
# Run command.
|
||||
case "$COMMAND" in
|
||||
install)
|
||||
# Install binaries to the miri toolchain's sysroot so they do not interact with other toolchains.
|
||||
$CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --root "$SYSROOT" "$@"
|
||||
$CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --root "$SYSROOT" "$@"
|
||||
;;
|
||||
check)
|
||||
# Check, and let caller control flags.
|
||||
$CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@"
|
||||
$CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
|
||||
;;
|
||||
build)
|
||||
# Build, and let caller control flags.
|
||||
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@"
|
||||
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
|
||||
;;
|
||||
test|bless)
|
||||
# First build and get a sysroot.
|
||||
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
|
||||
find_sysroot
|
||||
if [ "$COMMAND" = "bless" ]; then
|
||||
export RUSTC_BLESS="Gesundheit"
|
||||
fi
|
||||
# Then test, and let caller control flags.
|
||||
# Only in root project as `cargo-miri` has no tests.
|
||||
$CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@"
|
||||
;;
|
||||
run|run-dep)
|
||||
# Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
|
||||
# that we set the MIRI_SYSROOT up the right way.
|
||||
FOUND_TARGET_OPT=0
|
||||
for ARG in "$@"; do
|
||||
if [ "$LAST_ARG" = "--target" ]; then
|
||||
# Found it!
|
||||
export MIRI_TEST_TARGET="$ARG"
|
||||
FOUND_TARGET_OPT=1
|
||||
break
|
||||
fi
|
||||
LAST_ARG="$ARG"
|
||||
done
|
||||
if [ "$FOUND_TARGET_OPT" = "0" ] && [ -n "$MIRI_TEST_TARGET" ]; then
|
||||
# Make sure Miri actually uses this target.
|
||||
MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET"
|
||||
fi
|
||||
|
||||
CARGO="$CARGO --quiet"
|
||||
# First build and get a sysroot.
|
||||
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
|
||||
find_sysroot
|
||||
# Then run the actual command.
|
||||
|
||||
if [ "$COMMAND" = "run-dep" ]; then
|
||||
exec $CARGO test --test compiletest $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --miri-run-dep-mode $MIRIFLAGS "$@"
|
||||
else
|
||||
exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- $MIRIFLAGS "$@"
|
||||
fi
|
||||
;;
|
||||
fmt)
|
||||
find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \
|
||||
| xargs rustfmt +$TOOLCHAIN --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@"
|
||||
;;
|
||||
clippy)
|
||||
$CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@"
|
||||
$CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
|
||||
;;
|
||||
cargo)
|
||||
# We carefully kept the working dir intact, so this will run cargo *on the workspace in the
|
||||
# current working dir*, not on the main Miri workspace. That is exactly what RA needs.
|
||||
$CARGO "$@"
|
||||
;;
|
||||
*)
|
||||
echo "Unknown command: $COMMAND"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
|
||||
# rustup (that sets it's own environmental variables), which is undesirable.
|
||||
cargo build -q --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml
|
||||
"$(dirname "$0")"/miri-script/target/debug/miri-script "$@"
|
||||
|
|
|
|||
160
src/tools/miri/miri-script/Cargo.lock
Normal file
160
src/tools/miri/miri-script/Cargo.lock
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "dunce"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "miri-script"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"dunce",
|
||||
"itertools",
|
||||
"path_macro",
|
||||
"rustc_version",
|
||||
"shell-words",
|
||||
"walkdir",
|
||||
"which",
|
||||
"xshell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "path_macro"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6e819bbd49d5939f682638fa54826bf1650abddcd65d000923de8ad63cc7d15"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
|
||||
|
||||
[[package]]
|
||||
name = "shell-words"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269"
|
||||
dependencies = [
|
||||
"either",
|
||||
"libc",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "xshell"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "962c039b3a7b16cf4e9a4248397c6585c07547412e7d6a6e035389a802dcfe90"
|
||||
dependencies = [
|
||||
"xshell-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xshell-macros"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dbabb1cbd15a1d6d12d9ed6b35cc6777d4af87ab3ba155ea37215f20beab80c"
|
||||
22
src/tools/miri/miri-script/Cargo.toml
Normal file
22
src/tools/miri/miri-script/Cargo.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[package]
|
||||
authors = ["Miri Team"]
|
||||
description = "Helpers for miri maintenance"
|
||||
license = "MIT OR Apache-2.0"
|
||||
name = "miri-script"
|
||||
repository = "https://github.com/rust-lang/miri"
|
||||
version = "0.1.0"
|
||||
default-run = "miri-script"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
which = "4.4"
|
||||
walkdir = "2.3"
|
||||
itertools = "0.10"
|
||||
path_macro = "1.0"
|
||||
shell-words = "1.1"
|
||||
anyhow = "1.0"
|
||||
xshell = "0.2"
|
||||
rustc_version = "0.4"
|
||||
dunce = "1.0.4"
|
||||
4
src/tools/miri/miri-script/miri
Executable file
4
src/tools/miri/miri-script/miri
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
# RA invokes `./miri cargo ...` for each workspace, so we need to forward that to the main `miri`
|
||||
# script. See <https://github.com/rust-analyzer/rust-analyzer/issues/10793>.
|
||||
exec "$(dirname "$0")"/../miri "$@"
|
||||
455
src/tools/miri/miri-script/src/commands.rs
Normal file
455
src/tools/miri/miri-script/src/commands.rs
Normal file
|
|
@ -0,0 +1,455 @@
|
|||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::io::Write;
|
||||
use std::ops::Not;
|
||||
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use path_macro::path;
|
||||
use walkdir::WalkDir;
|
||||
use xshell::cmd;
|
||||
|
||||
use crate::util::*;
|
||||
use crate::Command;
|
||||
|
||||
/// Used for rustc syncs.
|
||||
const JOSH_FILTER: &str =
|
||||
":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri";
|
||||
|
||||
impl MiriEnv {
|
||||
fn build_miri_sysroot(&mut self) -> Result<()> {
|
||||
if self.sh.var("MIRI_SYSROOT").is_ok() {
|
||||
// Sysroot already set, use that.
|
||||
return Ok(());
|
||||
}
|
||||
let manifest_path = path!(self.miri_dir / "cargo-miri" / "Cargo.toml");
|
||||
let Self { toolchain, cargo_extra_flags, .. } = &self;
|
||||
let target = &match self.sh.var("MIRI_TEST_TARGET") {
|
||||
Ok(target) => vec!["--target".into(), target],
|
||||
Err(_) => vec![],
|
||||
};
|
||||
let output = cmd!(self.sh,
|
||||
"cargo +{toolchain} --quiet run {cargo_extra_flags...} --manifest-path {manifest_path} --
|
||||
miri setup --print-sysroot {target...}"
|
||||
).read();
|
||||
let Ok(output) = output else {
|
||||
// Run it again (without `--print-sysroot` or `--quiet`) so the user can see the error.
|
||||
cmd!(
|
||||
self.sh,
|
||||
"cargo +{toolchain} run {cargo_extra_flags...} --manifest-path {manifest_path} --
|
||||
miri setup {target...}"
|
||||
)
|
||||
.run()
|
||||
.with_context(|| "`cargo miri setup` failed")?;
|
||||
panic!("`cargo miri setup` didn't fail again the 2nd time?");
|
||||
};
|
||||
self.sh.set_var("MIRI_SYSROOT", output);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Command {
|
||||
fn auto_actions() -> Result<()> {
|
||||
let miri_dir = miri_dir()?;
|
||||
let auto_everything = path!(miri_dir / ".auto_everything").exists();
|
||||
let auto_toolchain = auto_everything || path!(miri_dir / ".auto-toolchain").exists();
|
||||
let auto_fmt = auto_everything || path!(miri_dir / ".auto-fmt").exists();
|
||||
let auto_clippy = auto_everything || path!(miri_dir / ".auto-clippy").exists();
|
||||
|
||||
// `toolchain` goes first as it could affect the others
|
||||
if auto_toolchain {
|
||||
Self::toolchain(vec![])?;
|
||||
}
|
||||
if auto_fmt {
|
||||
Self::fmt(vec![])?;
|
||||
}
|
||||
if auto_clippy {
|
||||
Self::clippy(vec![])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn exec(self) -> Result<()> {
|
||||
match self {
|
||||
Command::Install { flags } => Self::install(flags),
|
||||
Command::Build { flags } => Self::build(flags),
|
||||
Command::Check { flags } => Self::check(flags),
|
||||
Command::Test { bless, flags } => Self::test(bless, flags),
|
||||
Command::Run { dep, flags } => Self::run(dep, flags),
|
||||
Command::Fmt { flags } => Self::fmt(flags),
|
||||
Command::Clippy { flags } => Self::clippy(flags),
|
||||
Command::Cargo { flags } => Self::cargo(flags),
|
||||
Command::ManySeeds { command } => Self::many_seeds(command),
|
||||
Command::Bench { benches } => Self::bench(benches),
|
||||
Command::Toolchain { flags } => Self::toolchain(flags),
|
||||
Command::RustcPull { commit } => Self::rustc_pull(commit.clone()),
|
||||
Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch),
|
||||
}
|
||||
}
|
||||
|
||||
fn toolchain(flags: Vec<OsString>) -> Result<()> {
|
||||
// Make sure rustup-toolchain-install-master is installed.
|
||||
which::which("rustup-toolchain-install-master")
|
||||
.context("Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'")?;
|
||||
let sh = shell()?;
|
||||
sh.change_dir(miri_dir()?);
|
||||
let new_commit = Some(sh.read_file("rust-version")?.trim().to_owned());
|
||||
let current_commit = {
|
||||
let rustc_info = cmd!(sh, "rustc +miri --version -v").read();
|
||||
if rustc_info.is_err() {
|
||||
None
|
||||
} else {
|
||||
let metadata = rustc_version::version_meta_for(&rustc_info.unwrap())?;
|
||||
Some(
|
||||
metadata
|
||||
.commit_hash
|
||||
.ok_or_else(|| anyhow!("rustc metadata did not contain commit hash"))?,
|
||||
)
|
||||
}
|
||||
};
|
||||
// Check if we already are at that commit.
|
||||
if current_commit == new_commit {
|
||||
if active_toolchain()? != "miri" {
|
||||
cmd!(sh, "rustup override set miri").run()?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// Install and setup new toolchain.
|
||||
cmd!(sh, "rustup toolchain uninstall miri").run()?;
|
||||
|
||||
cmd!(sh, "rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy {flags...} -- {new_commit...}").run()?;
|
||||
cmd!(sh, "rustup override set miri").run()?;
|
||||
// Cleanup.
|
||||
cmd!(sh, "cargo clean").run()?;
|
||||
// Call `cargo metadata` on the sources in case that changes the lockfile
|
||||
// (which fails under some setups when it is done from inside vscode).
|
||||
let sysroot = cmd!(sh, "rustc --print sysroot").read()?;
|
||||
let sysroot = sysroot.trim();
|
||||
cmd!(sh, "cargo metadata --format-version 1 --manifest-path {sysroot}/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml").ignore_stdout().run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rustc_pull(commit: Option<String>) -> Result<()> {
|
||||
let sh = shell()?;
|
||||
sh.change_dir(miri_dir()?);
|
||||
let commit = commit.map(Result::Ok).unwrap_or_else(|| {
|
||||
let rust_repo_head =
|
||||
cmd!(sh, "git ls-remote https://github.com/rust-lang/rust/ HEAD").read()?;
|
||||
rust_repo_head
|
||||
.split_whitespace()
|
||||
.next()
|
||||
.map(|front| front.trim().to_owned())
|
||||
.ok_or_else(|| anyhow!("Could not obtain Rust repo HEAD from remote."))
|
||||
})?;
|
||||
// Make sure the repo is clean.
|
||||
if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
|
||||
bail!("working directory must be clean before running `./miri rustc-pull`");
|
||||
}
|
||||
|
||||
// Update rust-version file. As a separate commit, since making it part of
|
||||
// the merge has confused the heck out of josh in the past.
|
||||
// We pass `--no-verify` to avoid running git hooks like `./miri fmt` that could in turn
|
||||
// trigger auto-actions.
|
||||
sh.write_file("rust-version", &commit)?;
|
||||
const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rustc";
|
||||
cmd!(sh, "git commit rust-version --no-verify -m {PREPARING_COMMIT_MESSAGE}")
|
||||
.run()
|
||||
.context("FAILED to commit rust-version file, something went wrong")?;
|
||||
|
||||
// Fetch given rustc commit.
|
||||
cmd!(sh, "git fetch http://localhost:8000/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
|
||||
.run()
|
||||
.map_err(|e| {
|
||||
// Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
|
||||
cmd!(sh, "git reset --hard HEAD^")
|
||||
.run()
|
||||
.expect("FAILED to clean up again after failed `git fetch`, sorry for that");
|
||||
e
|
||||
})
|
||||
.context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
|
||||
|
||||
// Merge the fetched commit.
|
||||
const MERGE_COMMIT_MESSAGE: &str = "Merge from rustc";
|
||||
cmd!(sh, "git merge FETCH_HEAD --no-verify --no-ff -m {MERGE_COMMIT_MESSAGE}")
|
||||
.run()
|
||||
.context("FAILED to merge new commits, something went wrong")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn rustc_push(github_user: String, branch: String) -> Result<()> {
|
||||
let sh = shell()?;
|
||||
sh.change_dir(miri_dir()?);
|
||||
let base = sh.read_file("rust-version")?.trim().to_owned();
|
||||
// Make sure the repo is clean.
|
||||
if cmd!(sh, "git status --untracked-files=no --porcelain").read()?.is_empty().not() {
|
||||
bail!("working directory must be clean before running `./miri rustc-push`");
|
||||
}
|
||||
|
||||
// Find a repo we can do our preparation in.
|
||||
if let Ok(rustc_git) = env::var("RUSTC_GIT") {
|
||||
// If rustc_git is `Some`, we'll use an existing fork for the branch updates.
|
||||
sh.change_dir(rustc_git);
|
||||
} else {
|
||||
// Otherwise, do this in the local Miri repo.
|
||||
println!(
|
||||
"This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
|
||||
);
|
||||
print!(
|
||||
"To avoid that, abort now and set the `--rustc-git` flag to an existing rustc checkout. Proceed? [y/N] "
|
||||
);
|
||||
std::io::stdout().flush()?;
|
||||
let mut answer = String::new();
|
||||
std::io::stdin().read_line(&mut answer)?;
|
||||
if answer.trim().to_lowercase() != "y" {
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
// Prepare the branch. Pushing works much better if we use as base exactly
|
||||
// the commit that we pulled from last time, so we use the `rust-version`
|
||||
// file as a good approximation of that.
|
||||
println!("Preparing {github_user}/rust (base: {base})...");
|
||||
if cmd!(sh, "git fetch https://github.com/{github_user}/rust {branch}")
|
||||
.ignore_stderr()
|
||||
.read()
|
||||
.is_ok()
|
||||
{
|
||||
println!(
|
||||
"The branch '{branch}' seems to already exist in 'https://github.com/{github_user}/rust'. Please delete it and try again."
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
cmd!(sh, "git fetch https://github.com/rust-lang/rust {base}").run()?;
|
||||
cmd!(sh, "git push https://github.com/{github_user}/rust {base}:refs/heads/{branch}")
|
||||
.run()?;
|
||||
println!();
|
||||
|
||||
// Do the actual push.
|
||||
sh.change_dir(miri_dir()?);
|
||||
println!("Pushing miri changes...");
|
||||
cmd!(
|
||||
sh,
|
||||
"git push http://localhost:8000/{github_user}/rust.git{JOSH_FILTER}.git HEAD:{branch}"
|
||||
)
|
||||
.run()?;
|
||||
println!();
|
||||
|
||||
// Do a round-trip check to make sure the push worked as expected.
|
||||
cmd!(
|
||||
sh,
|
||||
"git fetch http://localhost:8000/{github_user}/rust.git{JOSH_FILTER}.git {branch}"
|
||||
)
|
||||
.ignore_stderr()
|
||||
.read()?;
|
||||
let head = cmd!(sh, "git rev-parse HEAD").read()?;
|
||||
let fetch_head = cmd!(sh, "git rev-parse FETCH_HEAD").read()?;
|
||||
if head != fetch_head {
|
||||
bail!("Josh created a non-roundtrip push! Do NOT merge this into rustc!");
|
||||
}
|
||||
println!(
|
||||
"Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
|
||||
);
|
||||
println!(" https://github.com/{github_user}/rust/pull/new/{branch}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn many_seeds(command: Vec<OsString>) -> Result<()> {
|
||||
let seed_start: u64 = env::var("MIRI_SEED_START")
|
||||
.unwrap_or_else(|_| "0".into())
|
||||
.parse()
|
||||
.context("failed to parse MIRI_SEED_START")?;
|
||||
let seed_count: u64 = env::var("MIRI_SEEDS")
|
||||
.unwrap_or_else(|_| "256".into())
|
||||
.parse()
|
||||
.context("failed to parse MIRI_SEEDS")?;
|
||||
let seed_end = seed_start + seed_count;
|
||||
let Some((command_name, trailing_args)) = command.split_first() else {
|
||||
bail!("expected many-seeds command to be non-empty");
|
||||
};
|
||||
let sh = shell()?;
|
||||
for seed in seed_start..seed_end {
|
||||
println!("Trying seed: {seed}");
|
||||
let mut miriflags = env::var_os("MIRIFLAGS").unwrap_or_default();
|
||||
miriflags.push(format!(" -Zlayout-seed={seed} -Zmiri-seed={seed}"));
|
||||
let status = cmd!(sh, "{command_name} {trailing_args...}")
|
||||
.env("MIRIFLAGS", miriflags)
|
||||
.quiet()
|
||||
.run();
|
||||
if status.is_err() {
|
||||
println!("Failing seed: {seed}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bench(benches: Vec<OsString>) -> Result<()> {
|
||||
// The hyperfine to use
|
||||
let hyperfine = env::var("HYPERFINE");
|
||||
let hyperfine = hyperfine.as_deref().unwrap_or("hyperfine -w 1 -m 5 --shell=none");
|
||||
let hyperfine = shell_words::split(hyperfine)?;
|
||||
let Some((program_name, args)) = hyperfine.split_first() else {
|
||||
bail!("expected HYPERFINE environment variable to be non-empty");
|
||||
};
|
||||
// Make sure we have an up-to-date Miri installed and selected the right toolchain.
|
||||
Self::install(vec![])?;
|
||||
|
||||
let sh = shell()?;
|
||||
sh.change_dir(miri_dir()?);
|
||||
let benches_dir = "bench-cargo-miri";
|
||||
let benches = if benches.is_empty() {
|
||||
sh.read_dir(benches_dir)?
|
||||
.into_iter()
|
||||
.filter(|path| path.is_dir())
|
||||
.map(Into::into)
|
||||
.collect()
|
||||
} else {
|
||||
benches.to_owned()
|
||||
};
|
||||
// Run the requested benchmarks
|
||||
for bench in benches {
|
||||
let current_bench = path!(benches_dir / bench / "Cargo.toml");
|
||||
// We don't attempt to escape `current_bench`, but we wrap it in quotes.
|
||||
// That seems to make Windows CI happy.
|
||||
cmd!(
|
||||
sh,
|
||||
"{program_name} {args...} 'cargo miri run --manifest-path \"'{current_bench}'\"'"
|
||||
)
|
||||
.run()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn install(flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let e = MiriEnv::new()?;
|
||||
e.install_to_sysroot(e.miri_dir.clone(), &flags)?;
|
||||
e.install_to_sysroot(path!(e.miri_dir / "cargo-miri"), &flags)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build(flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let e = MiriEnv::new()?;
|
||||
e.build(path!(e.miri_dir / "Cargo.toml"), &flags, /* quiet */ false)?;
|
||||
e.build(path!(e.miri_dir / "cargo-miri" / "Cargo.toml"), &flags, /* quiet */ false)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check(flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let e = MiriEnv::new()?;
|
||||
e.check(path!(e.miri_dir / "Cargo.toml"), &flags)?;
|
||||
e.check(path!(e.miri_dir / "cargo-miri" / "Cargo.toml"), &flags)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clippy(flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let e = MiriEnv::new()?;
|
||||
e.clippy(path!(e.miri_dir / "Cargo.toml"), &flags)?;
|
||||
e.clippy(path!(e.miri_dir / "cargo-miri" / "Cargo.toml"), &flags)?;
|
||||
e.clippy(path!(e.miri_dir / "miri-script" / "Cargo.toml"), &flags)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cargo(flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let e = MiriEnv::new()?;
|
||||
let toolchain = &e.toolchain;
|
||||
// We carefully kept the working dir intact, so this will run cargo *on the workspace in the
|
||||
// current working dir*, not on the main Miri workspace. That is exactly what RA needs.
|
||||
cmd!(e.sh, "cargo +{toolchain} {flags...}").run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn test(bless: bool, flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let mut e = MiriEnv::new()?;
|
||||
// First build, and get a sysroot.
|
||||
e.build(path!(e.miri_dir / "Cargo.toml"), &[], /* quiet */ true)?;
|
||||
e.build_miri_sysroot()?;
|
||||
|
||||
// Then test, and let caller control flags.
|
||||
// Only in root project as `cargo-miri` has no tests.
|
||||
if bless {
|
||||
e.sh.set_var("RUSTC_BLESS", "Gesundheit");
|
||||
}
|
||||
e.test(path!(e.miri_dir / "Cargo.toml"), &flags)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run(dep: bool, flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let mut e = MiriEnv::new()?;
|
||||
// Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
|
||||
// that we set the MIRI_SYSROOT up the right way.
|
||||
use itertools::Itertools;
|
||||
let target = flags.iter().tuple_windows().find(|(first, _)| first == &"--target");
|
||||
if let Some((_, target)) = target {
|
||||
// Found it!
|
||||
e.sh.set_var("MIRI_TEST_TARGET", target);
|
||||
} else if let Ok(target) = std::env::var("MIRI_TEST_TARGET") {
|
||||
// Make sure miri actually uses this target.
|
||||
let miriflags = e.sh.var("MIRIFLAGS").unwrap_or_default();
|
||||
e.sh.set_var("MIRIFLAGS", format!("{miriflags} --target {target}"));
|
||||
}
|
||||
// First build, and get a sysroot.
|
||||
let miri_manifest = path!(e.miri_dir / "Cargo.toml");
|
||||
e.build(&miri_manifest, &[], /* quiet */ true)?;
|
||||
e.build_miri_sysroot()?;
|
||||
|
||||
// Then run the actual command.
|
||||
let miri_flags = e.sh.var("MIRIFLAGS").unwrap_or_default();
|
||||
let miri_flags = flagsplit(&miri_flags);
|
||||
let toolchain = &e.toolchain;
|
||||
let extra_flags = &e.cargo_extra_flags;
|
||||
if dep {
|
||||
cmd!(
|
||||
e.sh,
|
||||
"cargo +{toolchain} --quiet test --test compiletest {extra_flags...} --manifest-path {miri_manifest} -- --miri-run-dep-mode {miri_flags...} {flags...}"
|
||||
).quiet().run()?;
|
||||
} else {
|
||||
cmd!(
|
||||
e.sh,
|
||||
"cargo +{toolchain} --quiet run {extra_flags...} --manifest-path {miri_manifest} -- {miri_flags...} {flags...}"
|
||||
).quiet().run()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fmt(flags: Vec<OsString>) -> Result<()> {
|
||||
Self::auto_actions()?;
|
||||
let e = MiriEnv::new()?;
|
||||
let toolchain = &e.toolchain;
|
||||
let config_path = path!(e.miri_dir / "rustfmt.toml");
|
||||
|
||||
let mut cmd = cmd!(
|
||||
e.sh,
|
||||
"rustfmt +{toolchain} --edition=2021 --config-path {config_path} {flags...}"
|
||||
);
|
||||
eprintln!("$ {cmd} ...");
|
||||
|
||||
// Add all the filenames to the command.
|
||||
// FIXME: `rustfmt` will follow the `mod` statements in these files, so we get a bunch of
|
||||
// duplicate diffs.
|
||||
for item in WalkDir::new(&e.miri_dir).into_iter().filter_entry(|entry| {
|
||||
let name = entry.file_name().to_string_lossy();
|
||||
let ty = entry.file_type();
|
||||
if ty.is_file() {
|
||||
name.ends_with(".rs")
|
||||
} else {
|
||||
// dir or symlink. skip `target` and `.git`.
|
||||
&name != "target" && &name != ".git"
|
||||
}
|
||||
}) {
|
||||
let item = item?;
|
||||
if item.file_type().is_file() {
|
||||
cmd = cmd.arg(item.into_path());
|
||||
}
|
||||
}
|
||||
|
||||
// We want our own error message, repeating the command is too much.
|
||||
cmd.quiet().run().map_err(|_| anyhow!("`rustfmt` failed"))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
210
src/tools/miri/miri-script/src/main.rs
Normal file
210
src/tools/miri/miri-script/src/main.rs
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
mod commands;
|
||||
mod util;
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Command {
|
||||
/// Installs the miri driver and cargo-miri.
|
||||
/// 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.
|
||||
Install {
|
||||
/// Flags that are passed through to `cargo install`.
|
||||
flags: Vec<OsString>,
|
||||
},
|
||||
/// Just build miri.
|
||||
Build {
|
||||
/// Flags that are passed through to `cargo build`.
|
||||
flags: Vec<OsString>,
|
||||
},
|
||||
/// Just check miri.
|
||||
Check {
|
||||
/// Flags that are passed through to `cargo check`.
|
||||
flags: Vec<OsString>,
|
||||
},
|
||||
/// Build miri, set up a sysroot and then run the test suite.
|
||||
Test {
|
||||
bless: bool,
|
||||
/// Flags that are passed through to `cargo test`.
|
||||
flags: Vec<OsString>,
|
||||
},
|
||||
/// Build miri, set up a sysroot and then run the driver with the given <flags>.
|
||||
/// (Also respects MIRIFLAGS environment variable.)
|
||||
Run {
|
||||
dep: bool,
|
||||
/// Flags that are passed through to `miri`.
|
||||
flags: Vec<OsString>,
|
||||
},
|
||||
/// Format all sources and tests.
|
||||
Fmt {
|
||||
/// Flags that are passed through to `rustfmt`.
|
||||
flags: Vec<OsString>,
|
||||
},
|
||||
/// Runs clippy on all sources.
|
||||
Clippy {
|
||||
/// Flags that are passed through to `cargo clippy`.
|
||||
flags: Vec<OsString>,
|
||||
},
|
||||
/// Runs just `cargo <flags>` with the Miri-specific environment variables.
|
||||
/// Mainly meant to be invoked by rust-analyzer.
|
||||
Cargo { flags: Vec<OsString> },
|
||||
/// Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
|
||||
/// variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
|
||||
/// many different seeds.
|
||||
ManySeeds { command: Vec<OsString> },
|
||||
/// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
|
||||
Bench {
|
||||
/// List of benchmarks to run. By default all benchmarks are run.
|
||||
benches: Vec<OsString>,
|
||||
},
|
||||
/// 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<OsString> },
|
||||
/// 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<String> },
|
||||
/// 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 },
|
||||
}
|
||||
|
||||
const HELP: &str = r#" COMMANDS
|
||||
|
||||
./miri build <flags>:
|
||||
Just build miri. <flags> are passed to `cargo build`.
|
||||
|
||||
./miri check <flags>:
|
||||
Just check miri. <flags> are passed to `cargo check`.
|
||||
|
||||
./miri test [--bless] <flags>:
|
||||
Build miri, set up a sysroot and then run the test suite. <flags> are passed
|
||||
to the final `cargo test` invocation.
|
||||
|
||||
./miri run [--dep] <flags>:
|
||||
Build miri, set up a sysroot and then run the driver with the given <flags>.
|
||||
(Also respects MIRIFLAGS environment variable.)
|
||||
|
||||
./miri fmt <flags>:
|
||||
Format all sources and tests. <flags> are passed to `rustfmt`.
|
||||
|
||||
./miri clippy <flags>:
|
||||
Runs clippy on all sources. <flags> are passed to `cargo clippy`.
|
||||
|
||||
./miri cargo <flags>:
|
||||
Runs just `cargo <flags>` with the Miri-specific environment variables.
|
||||
Mainly meant to be invoked by rust-analyzer.
|
||||
|
||||
./miri install <flags>:
|
||||
Installs the miri driver and cargo-miri. <flags> 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 many-seeds <command>:
|
||||
Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
|
||||
variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
|
||||
many different seeds. The MIRI_SEEDS variable controls how many seeds are being
|
||||
tried; MIRI_SEED_START controls the first seed to try.
|
||||
|
||||
./miri bench <benches>:
|
||||
Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
|
||||
<benches> can explicitly list the benchmarks to run; by default, all of them are run.
|
||||
|
||||
./miri toolchain <flags>:
|
||||
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 <commit>:
|
||||
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 <github user> <branch>:
|
||||
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.
|
||||
|
||||
ENVIRONMENT VARIABLES
|
||||
|
||||
MIRI_SYSROOT:
|
||||
If already set, the "sysroot setup" step is skipped.
|
||||
|
||||
CARGO_EXTRA_FLAGS:
|
||||
Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)"#;
|
||||
|
||||
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 = env::args_os().peekable();
|
||||
args.next().unwrap(); // skip program name
|
||||
let command = match args.next().and_then(|s| s.into_string().ok()).as_deref() {
|
||||
Some("build") => Command::Build { flags: args.collect() },
|
||||
Some("check") => Command::Check { flags: args.collect() },
|
||||
Some("test") => {
|
||||
let bless = args.peek().is_some_and(|a| a.to_str() == Some("--bless"));
|
||||
if bless {
|
||||
// Consume the flag.
|
||||
args.next().unwrap();
|
||||
}
|
||||
Command::Test { bless, flags: args.collect() }
|
||||
}
|
||||
Some("run") => {
|
||||
let dep = args.peek().is_some_and(|a| a.to_str() == Some("--dep"));
|
||||
if dep {
|
||||
// Consume the flag.
|
||||
args.next().unwrap();
|
||||
}
|
||||
Command::Run { dep, flags: args.collect() }
|
||||
}
|
||||
Some("fmt") => Command::Fmt { flags: args.collect() },
|
||||
Some("clippy") => Command::Clippy { flags: args.collect() },
|
||||
Some("cargo") => Command::Cargo { flags: args.collect() },
|
||||
Some("install") => Command::Install { flags: args.collect() },
|
||||
Some("many-seeds") => Command::ManySeeds { command: args.collect() },
|
||||
Some("bench") => Command::Bench { benches: args.collect() },
|
||||
Some("toolchain") => Command::Toolchain { flags: args.collect() },
|
||||
Some("rustc-pull") => {
|
||||
let commit = args.next().map(|a| a.to_string_lossy().into_owned());
|
||||
if args.next().is_some() {
|
||||
bail!("Too many arguments for `./miri rustc-pull`");
|
||||
}
|
||||
Command::RustcPull { commit }
|
||||
}
|
||||
Some("rustc-push") => {
|
||||
let github_user = args
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER BRANCH`")
|
||||
})?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
let branch = args
|
||||
.next()
|
||||
.ok_or_else(|| {
|
||||
anyhow!("Missing second argument for `./miri rustc-push GITHUB_USER BRANCH`")
|
||||
})?
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
if args.next().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);
|
||||
}
|
||||
};
|
||||
command.exec()?;
|
||||
Ok(())
|
||||
}
|
||||
153
src/tools/miri/miri-script/src/util.rs
Normal file
153
src/tools/miri/miri-script/src/util.rs
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
use std::ffi::{OsStr, OsString};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use dunce::canonicalize;
|
||||
use path_macro::path;
|
||||
use xshell::{cmd, Shell};
|
||||
|
||||
pub fn miri_dir() -> std::io::Result<PathBuf> {
|
||||
const MIRI_SCRIPT_ROOT_DIR: &str = env!("CARGO_MANIFEST_DIR");
|
||||
Ok(canonicalize(MIRI_SCRIPT_ROOT_DIR)?.parent().unwrap().into())
|
||||
}
|
||||
|
||||
/// Queries the active toolchain for the Miri dir.
|
||||
pub fn active_toolchain() -> Result<String> {
|
||||
let sh = shell()?;
|
||||
sh.change_dir(miri_dir()?);
|
||||
let stdout = cmd!(sh, "rustup show active-toolchain").read()?;
|
||||
Ok(stdout.split_whitespace().next().context("Could not obtain active Rust toolchain")?.into())
|
||||
}
|
||||
|
||||
pub fn shell() -> Result<Shell> {
|
||||
let sh = Shell::new()?;
|
||||
// xshell does not propagate parent's env variables by default.
|
||||
for (k, v) in std::env::vars_os() {
|
||||
sh.set_var(k, v);
|
||||
}
|
||||
Ok(sh)
|
||||
}
|
||||
|
||||
pub fn flagsplit(flags: &str) -> Vec<String> {
|
||||
// This code is taken from `RUSTFLAGS` handling in cargo.
|
||||
flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect()
|
||||
}
|
||||
|
||||
/// Some extra state we track for building Miri, such as the right RUSTFLAGS.
|
||||
pub struct MiriEnv {
|
||||
/// miri_dir is the root of the miri repository checkout we are working in.
|
||||
pub miri_dir: PathBuf,
|
||||
/// active_toolchain is passed as `+toolchain` argument to cargo/rustc invocations.
|
||||
pub toolchain: String,
|
||||
/// Extra flags to pass to cargo.
|
||||
pub cargo_extra_flags: Vec<String>,
|
||||
/// The rustc sysroot
|
||||
pub sysroot: PathBuf,
|
||||
/// The shell we use.
|
||||
pub sh: Shell,
|
||||
}
|
||||
|
||||
impl MiriEnv {
|
||||
pub fn new() -> Result<Self> {
|
||||
let sh = shell()?;
|
||||
let toolchain = active_toolchain()?;
|
||||
let miri_dir = miri_dir()?;
|
||||
|
||||
let sysroot = cmd!(sh, "rustc +{toolchain} --print sysroot").read()?.into();
|
||||
let target_output = cmd!(sh, "rustc +{toolchain} --version --verbose").read()?;
|
||||
let rustc_meta = rustc_version::version_meta_for(&target_output)?;
|
||||
let libdir = path!(sysroot / "lib" / "rustlib" / rustc_meta.host / "lib");
|
||||
|
||||
// Determine some toolchain properties
|
||||
if !libdir.exists() {
|
||||
println!("Something went wrong determining the library dir.");
|
||||
println!("I got {} but that does not exist.", libdir.display());
|
||||
println!("Please report a bug at https://github.com/rust-lang/miri/issues.");
|
||||
std::process::exit(2);
|
||||
}
|
||||
// Share target dir between `miri` and `cargo-miri`.
|
||||
let target_dir = std::env::var_os("CARGO_TARGET_DIR")
|
||||
.unwrap_or_else(|| path!(miri_dir / "target").into());
|
||||
sh.set_var("CARGO_TARGET_DIR", target_dir);
|
||||
|
||||
// We configure dev builds to not be unusably slow.
|
||||
let devel_opt_level =
|
||||
std::env::var_os("CARGO_PROFILE_DEV_OPT_LEVEL").unwrap_or_else(|| "2".into());
|
||||
sh.set_var("CARGO_PROFILE_DEV_OPT_LEVEL", devel_opt_level);
|
||||
|
||||
// Compute rustflags.
|
||||
let rustflags = {
|
||||
let env = std::env::var_os("RUSTFLAGS");
|
||||
let mut flags_with_warnings = OsString::from(
|
||||
"-Zunstable-options -Wrustc::internal -Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros ",
|
||||
);
|
||||
if let Some(value) = env {
|
||||
flags_with_warnings.push(value);
|
||||
}
|
||||
// We set the rpath so that Miri finds the private rustc libraries it needs.
|
||||
let mut flags_with_compiler_settings = OsString::from("-C link-args=-Wl,-rpath,");
|
||||
flags_with_compiler_settings.push(&libdir);
|
||||
flags_with_compiler_settings.push(flags_with_warnings);
|
||||
flags_with_compiler_settings
|
||||
};
|
||||
sh.set_var("RUSTFLAGS", rustflags);
|
||||
|
||||
// Get extra flags for cargo.
|
||||
let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default();
|
||||
let cargo_extra_flags = flagsplit(&cargo_extra_flags);
|
||||
|
||||
Ok(MiriEnv { miri_dir, toolchain, sh, sysroot, cargo_extra_flags })
|
||||
}
|
||||
|
||||
pub fn install_to_sysroot(
|
||||
&self,
|
||||
path: impl AsRef<OsStr>,
|
||||
args: impl IntoIterator<Item = impl AsRef<OsStr>>,
|
||||
) -> Result<()> {
|
||||
let MiriEnv { sysroot, toolchain, cargo_extra_flags, .. } = self;
|
||||
// Install binaries to the miri toolchain's `sysroot` so they do not interact with other toolchains.
|
||||
cmd!(self.sh, "cargo +{toolchain} install {cargo_extra_flags...} --path {path} --force --root {sysroot} {args...}").run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn build(
|
||||
&self,
|
||||
manifest_path: impl AsRef<OsStr>,
|
||||
args: &[OsString],
|
||||
quiet: bool,
|
||||
) -> Result<()> {
|
||||
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
|
||||
let quiet_flag = if quiet { Some("--quiet") } else { None };
|
||||
let mut cmd = cmd!(
|
||||
self.sh,
|
||||
"cargo +{toolchain} build {cargo_extra_flags...} --manifest-path {manifest_path} {quiet_flag...} {args...}"
|
||||
);
|
||||
cmd.set_quiet(quiet);
|
||||
cmd.run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check(&self, manifest_path: impl AsRef<OsStr>, args: &[OsString]) -> Result<()> {
|
||||
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
|
||||
cmd!(self.sh, "cargo +{toolchain} check {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}")
|
||||
.run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn clippy(&self, manifest_path: impl AsRef<OsStr>, args: &[OsString]) -> Result<()> {
|
||||
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
|
||||
cmd!(self.sh, "cargo +{toolchain} clippy {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}")
|
||||
.run()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn test(&self, manifest_path: impl AsRef<OsStr>, args: &[OsString]) -> Result<()> {
|
||||
let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
|
||||
cmd!(
|
||||
self.sh,
|
||||
"cargo +{toolchain} test {cargo_extra_flags...} --manifest-path {manifest_path} {args...}"
|
||||
)
|
||||
.run()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue