Skip to content

Commit 7f2eca6

Browse files
osiewiczRalfJung
authored andcommitted
rewrite miri script in Rust
1 parent 2183cda commit 7f2eca6

File tree

6 files changed

+1277
-357
lines changed

6 files changed

+1277
-357
lines changed

src/tools/miri/miri

+4-357
Original file line numberDiff line numberDiff line change
@@ -1,359 +1,6 @@
11
#!/bin/bash
22
set -e
3-
USAGE=$(cat <<"EOF"
4-
COMMANDS
5-
6-
./miri install <flags>:
7-
Installs the miri driver and cargo-miri. <flags> are passed to `cargo
8-
install`. Sets up the rpath such that the installed binary should work in any
9-
working directory. Note that the binaries are placed in the `miri` toolchain
10-
sysroot, to prevent conflicts with other toolchains.
11-
12-
./miri build <flags>:
13-
Just build miri. <flags> are passed to `cargo build`.
14-
15-
./miri check <flags>:
16-
Just check miri. <flags> are passed to `cargo check`.
17-
18-
./miri test <flags>:
19-
Build miri, set up a sysroot and then run the test suite. <flags> are passed
20-
to the final `cargo test` invocation.
21-
22-
./miri run <flags>:
23-
Build miri, set up a sysroot and then run the driver with the given <flags>.
24-
(Also respects MIRIFLAGS environment variable.)
25-
26-
./miri fmt <flags>:
27-
Format all sources and tests. <flags> are passed to `rustfmt`.
28-
29-
./miri clippy <flags>:
30-
Runs clippy on all sources. <flags> are passed to `cargo clippy`.
31-
32-
./miri cargo <flags>:
33-
Runs just `cargo <flags>` with the Miri-specific environment variables.
34-
Mainly meant to be invoked by rust-analyzer.
35-
36-
./miri many-seeds <command>:
37-
Runs <command> over and over again with different seeds for Miri. The MIRIFLAGS
38-
variable is set to its original value appended with ` -Zmiri-seed=$SEED` for
39-
many different seeds. The MIRI_SEEDS variable controls how many seeds are being
40-
tried; MIRI_SEED_START controls the first seed to try.
41-
42-
./miri bench <benches>:
43-
Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
44-
<benches> can explicitly list the benchmarks to run; by default, all of them are run.
45-
46-
./miri toolchain <flags>:
47-
Update and activate the rustup toolchain 'miri' to the commit given in the
48-
`rust-version` file.
49-
`rustup-toolchain-install-master` must be installed for this to work. Any extra
50-
flags are passed to `rustup-toolchain-install-master`.
51-
52-
./miri rustc-pull <commit>:
53-
Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest
54-
rustc commit. The fetched commit is stored in the `rust-version` file, so the
55-
next `./miri toolchain` will install the rustc that just got pulled.
56-
57-
./miri rustc-push <github user> <branch>:
58-
Push Miri changes back to the rustc repo. This will pull a copy of the rustc
59-
history into the Miri repo, unless you set the RUSTC_GIT env var to an existing
60-
clone of the rustc repo.
61-
62-
ENVIRONMENT VARIABLES
63-
64-
MIRI_SYSROOT:
65-
If already set, the "sysroot setup" step is skipped.
66-
67-
CARGO_EXTRA_FLAGS:
68-
Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)
69-
EOF
70-
)
71-
72-
## We need to know which command to run and some global constants.
73-
COMMAND="$1"
74-
if [ -z "$COMMAND" ]; then
75-
echo "$USAGE"
76-
exit 1
77-
fi
78-
shift
79-
# macOS does not have a useful readlink/realpath so we have to use Python instead...
80-
MIRIDIR=$(python3 -c 'import pathlib, sys; print(pathlib.Path(sys.argv[1]).resolve().parent.as_posix())' "$0")
81-
# Used for rustc syncs.
82-
JOSH_FILTER=":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri"
83-
# Needed for `./miri bench`.
84-
TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1)
85-
86-
## Early commands, that don't do auto-things and don't want the environment-altering things happening below.
87-
case "$COMMAND" in
88-
toolchain)
89-
cd "$MIRIDIR"
90-
NEW_COMMIT=$(cat rust-version)
91-
# Make sure rustup-toolchain-install-master is installed.
92-
if ! which rustup-toolchain-install-master >/dev/null; then
93-
echo "Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'"
94-
exit 1
95-
fi
96-
# Check if we already are at that commit.
97-
CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | grep "^commit-hash: " | cut -d " " -f 2)
98-
if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then
99-
echo "miri toolchain is already at commit $CUR_COMMIT."
100-
if [[ "$TOOLCHAIN" != "miri" ]]; then
101-
rustup override set miri
102-
fi
103-
exit 0
104-
fi
105-
# Install and setup new toolchain.
106-
rustup toolchain uninstall miri
107-
rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy "$@" -- "$NEW_COMMIT"
108-
rustup override set miri
109-
# Cleanup.
110-
cargo clean
111-
# Call 'cargo metadata' on the sources in case that changes the lockfile
112-
# (which fails under some setups when it is done from inside vscode).
113-
cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null
114-
# Done!
115-
exit 0
116-
;;
117-
rustc-pull)
118-
cd "$MIRIDIR"
119-
FETCH_COMMIT="$1"
120-
if [ -z "$FETCH_COMMIT" ]; then
121-
FETCH_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1)
122-
fi
123-
# Update rust-version file. As a separate commit, since making it part of
124-
# the merge has confused the heck out of josh in the past.
125-
echo "$FETCH_COMMIT" > rust-version
126-
git commit rust-version -m "Preparing for merge from rustc" || (echo "FAILED to commit rust-version file, something went wrong"; exit 1)
127-
# Fetch given rustc commit and note down which one that was
128-
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)
129-
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)
130-
exit 0
131-
;;
132-
rustc-push)
133-
USER="$1"
134-
BRANCH="$2"
135-
if [ -z "$USER" ] || [ -z "$BRANCH" ]; then
136-
echo "Usage: $0 rustc-push <github user> <branch>"
137-
exit 1
138-
fi
139-
if [ -n "$RUSTC_GIT" ]; then
140-
# Use an existing fork for the branch updates.
141-
cd "$RUSTC_GIT"
142-
else
143-
# Do this in the local Miri repo.
144-
echo "This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
145-
read -r -p "To avoid that, abort now and set the RUSTC_GIT environment variable to an existing rustc checkout. Proceed? [y/N] "
146-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
147-
exit 1
148-
fi
149-
cd "$MIRIDIR"
150-
fi
151-
# Prepare the branch. Pushing works much better if we use as base exactly
152-
# the commit that we pulled from last time, so we use the `rust-version`
153-
# file as a good approximation of that.
154-
BASE=$(cat "$MIRIDIR/rust-version")
155-
echo "Preparing $USER/rust (base: $BASE)..."
156-
if git fetch "https://github.com/$USER/rust" "$BRANCH" &>/dev/null; then
157-
echo "The branch '$BRANCH' seems to already exist in 'https://github.com/$USER/rust'. Please delete it and try again."
158-
exit 1
159-
fi
160-
git fetch https://github.com/rust-lang/rust $BASE
161-
git push https://github.com/$USER/rust $BASE:refs/heads/$BRANCH -f
162-
echo
163-
# Do the actual push.
164-
cd "$MIRIDIR"
165-
echo "Pushing Miri changes..."
166-
git push http://localhost:8000/$USER/rust.git$JOSH_FILTER.git HEAD:$BRANCH
167-
# Do a round-trip check to make sure the push worked as expected.
168-
echo
169-
git fetch http://localhost:8000/$USER/rust.git@$JOSH_FILTER.git $BRANCH &>/dev/null
170-
if [[ $(git rev-parse HEAD) != $(git rev-parse FETCH_HEAD) ]]; then
171-
echo "ERROR: Josh created a non-roundtrip push! Do NOT merge this into rustc!"
172-
exit 1
173-
else
174-
echo "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
175-
echo " https://github.com/$USER/rust/pull/new/$BRANCH"
176-
exit 0
177-
fi
178-
;;
179-
many-seeds)
180-
MIRI_SEED_START=${MIRI_SEED_START:-0} # default to 0
181-
MIRI_SEEDS=${MIRI_SEEDS:-256} # default to 256
182-
for SEED in $(seq $MIRI_SEED_START $(( $MIRI_SEED_START + $MIRI_SEEDS - 1 )) ); do
183-
echo "Trying seed: $SEED"
184-
MIRIFLAGS="$MIRIFLAGS -Zlayout-seed=$SEED -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; }
185-
done
186-
exit 0
187-
;;
188-
bench)
189-
# The hyperfine to use
190-
HYPERFINE=${HYPERFINE:-hyperfine -w 1 -m 5 --shell=none}
191-
# Make sure we have an up-to-date Miri installed
192-
"$0" install
193-
# Run the requested benchmarks
194-
if [ -z "${1+exists}" ]; then
195-
BENCHES=( $(ls "$MIRIDIR/bench-cargo-miri" ) )
196-
else
197-
BENCHES=("$@")
198-
fi
199-
for BENCH in "${BENCHES[@]}"; do
200-
$HYPERFINE "cargo +$TOOLCHAIN miri run --manifest-path $MIRIDIR/bench-cargo-miri/$BENCH/Cargo.toml"
201-
done
202-
exit 0
203-
;;
204-
esac
205-
206-
## Run the auto-things.
207-
if [ -z "$MIRI_AUTO_OPS" ]; then
208-
export MIRI_AUTO_OPS=42
209-
210-
# Run this first, so that the toolchain doesn't change after
211-
# other code has run.
212-
if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then
213-
$0 toolchain
214-
# Let's make sure to actually use that toolchain, too.
215-
TOOLCHAIN=miri
216-
fi
217-
218-
if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then
219-
$0 fmt
220-
fi
221-
222-
if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-clippy" ] ; then
223-
$0 clippy -- -D warnings
224-
fi
225-
fi
226-
227-
## Prepare the environment
228-
# Determine some toolchain properties
229-
TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2)
230-
SYSROOT=$(rustc +$TOOLCHAIN --print sysroot)
231-
LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib
232-
if ! test -d "$LIBDIR"; then
233-
echo "Something went wrong determining the library dir."
234-
echo "I got $LIBDIR but that does not exist."
235-
echo "Please report a bug at https://github.com/rust-lang/miri/issues."
236-
exit 2
237-
fi
238-
239-
# Prepare flags for cargo and rustc.
240-
CARGO="cargo +$TOOLCHAIN"
241-
# Share target dir between `miri` and `cargo-miri`.
242-
if [ -z "$CARGO_TARGET_DIR" ]; then
243-
export CARGO_TARGET_DIR="$MIRIDIR/target"
244-
fi
245-
# We configure dev builds to not be unusably slow.
246-
if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then
247-
export CARGO_PROFILE_DEV_OPT_LEVEL=2
248-
fi
249-
# Enable rustc-specific lints (ignored without `-Zunstable-options`).
250-
export RUSTFLAGS="-Zunstable-options -Wrustc::internal -Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros $RUSTFLAGS"
251-
# We set the rpath so that Miri finds the private rustc libraries it needs.
252-
export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS"
253-
254-
## Helper functions
255-
256-
# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`.
257-
build_sysroot() {
258-
if ! MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup --print-sysroot "$@")"; then
259-
# Run it again so the user can see the error.
260-
$CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@"
261-
echo "'cargo miri setup' failed"
262-
exit 1
263-
fi
264-
export MIRI_SYSROOT
265-
}
266-
267-
# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account
268-
# locally built vs. distributed rustc.
269-
find_sysroot() {
270-
if [ -n "$MIRI_SYSROOT" ]; then
271-
# Sysroot already set, use that.
272-
return 0
273-
fi
274-
# We need to build a sysroot.
275-
if [ -n "$MIRI_TEST_TARGET" ]; then
276-
build_sysroot --target "$MIRI_TEST_TARGET"
277-
else
278-
build_sysroot
279-
fi
280-
}
281-
282-
## Main
283-
284-
# Run command.
285-
case "$COMMAND" in
286-
install)
287-
# Install binaries to the miri toolchain's sysroot so they do not interact with other toolchains.
288-
$CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --root "$SYSROOT" "$@"
289-
$CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --root "$SYSROOT" "$@"
290-
;;
291-
check)
292-
# Check, and let caller control flags.
293-
$CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@"
294-
$CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
295-
;;
296-
build)
297-
# Build, and let caller control flags.
298-
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@"
299-
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
300-
;;
301-
test|bless)
302-
# First build and get a sysroot.
303-
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
304-
find_sysroot
305-
if [ "$COMMAND" = "bless" ]; then
306-
export RUSTC_BLESS="Gesundheit"
307-
fi
308-
# Then test, and let caller control flags.
309-
# Only in root project as `cargo-miri` has no tests.
310-
$CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@"
311-
;;
312-
run|run-dep)
313-
# Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
314-
# that we set the MIRI_SYSROOT up the right way.
315-
FOUND_TARGET_OPT=0
316-
for ARG in "$@"; do
317-
if [ "$LAST_ARG" = "--target" ]; then
318-
# Found it!
319-
export MIRI_TEST_TARGET="$ARG"
320-
FOUND_TARGET_OPT=1
321-
break
322-
fi
323-
LAST_ARG="$ARG"
324-
done
325-
if [ "$FOUND_TARGET_OPT" = "0" ] && [ -n "$MIRI_TEST_TARGET" ]; then
326-
# Make sure Miri actually uses this target.
327-
MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET"
328-
fi
329-
330-
CARGO="$CARGO --quiet"
331-
# First build and get a sysroot.
332-
$CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
333-
find_sysroot
334-
# Then run the actual command.
335-
336-
if [ "$COMMAND" = "run-dep" ]; then
337-
exec $CARGO test --test compiletest $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --miri-run-dep-mode $MIRIFLAGS "$@"
338-
else
339-
exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- $MIRIFLAGS "$@"
340-
fi
341-
;;
342-
fmt)
343-
find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \
344-
| xargs rustfmt +$TOOLCHAIN --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@"
345-
;;
346-
clippy)
347-
$CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@"
348-
$CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
349-
;;
350-
cargo)
351-
# We carefully kept the working dir intact, so this will run cargo *on the workspace in the
352-
# current working dir*, not on the main Miri workspace. That is exactly what RA needs.
353-
$CARGO "$@"
354-
;;
355-
*)
356-
echo "Unknown command: $COMMAND"
357-
exit 1
358-
;;
359-
esac
3+
# Instead of doing just `cargo run --manifest-path .. $@`, we invoke miri-script binary directly. Invoking `cargo run` goes through
4+
# rustup (that sets it's own environmental variables), which is undesirable.
5+
cargo build --manifest-path "$(dirname "$0")"/miri-script/Cargo.toml
6+
"$(dirname "$0")"/miri-script/target/debug/miri-script $@

0 commit comments

Comments
 (0)