11#! /bin/bash
22set -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