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. However, the rustup toolchain when invoking `cargo miri`
10 needs to be the same one used for `./miri install`.
13 Just build miri. <flags> are passed to `cargo build`.
16 Just check miri. <flags> are passed to `cargo check`.
19 Build miri, set up a sysroot and then run the test suite. <flags> are passed
20 to the final `cargo test` invocation.
23 Build miri, set up a sysroot and then run the driver with the given <flags>.
24 (Also respects MIRIFLAGS environment variable.)
27 Format all sources and tests. <flags> are passed to `rustfmt`.
29 ./miri clippy <flags>:
30 Runs clippy on all sources. <flags> are passed to `cargo clippy`.
33 Runs just `cargo <flags>` with the Miri-specific environment variables.
34 Mainly meant to be invoked by rust-analyzer.
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.
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.
46 ./miri toolchain <flags>:
47 Update and activate the rustup toolchain 'miri' to the commit given in the
49 `rustup-toolchain-install-master` must be installed for this to work. Any extra
50 flags are passed to `rustup-toolchain-install-master`.
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.
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.
65 If already set, the "sysroot setup" step is skipped.
68 Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.)
72 ## We need to know which command to run and some global constants.
74 if [ -z "$COMMAND" ]; then
79 # macOS does not have a useful readlink/realpath so we have to use Python instead...
80 MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$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)
86 ## Early commands, that don't do auto-things and don't want the environment-altering things happening below.
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'"
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 rustup override set miri
103 # Install and setup new toolchain.
104 rustup toolchain uninstall miri
105 rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy "$@" -- "$NEW_COMMIT"
106 rustup override set miri
109 # Call 'cargo metadata' on the sources in case that changes the lockfile
110 # (which fails under some setups when it is done from inside vscode).
111 cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null
118 if [ -z "$FETCH_COMMIT" ]; then
119 FETCH_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1)
121 # Update rust-version file. As a separate commit, since making it part of
122 # the merge has confused the heck out of josh in the past.
123 echo "$FETCH_COMMIT" > rust-version
124 git commit rust-version -m "Preparing for merge from rustc"
125 # Fetch given rustc commit and note down which one that was
126 git fetch http://localhost:8000/rust-lang/rust.git@$FETCH_COMMIT$JOSH_FILTER.git
127 git merge FETCH_HEAD --no-ff -m "Merge from rustc"
133 if [ -z "$USER" ] || [ -z "$BRANCH" ]; then
134 echo "Usage: $0 rustc-push <github user> <branch>"
137 if [ -n "$RUSTC_GIT" ]; then
138 # Use an existing fork for the branch updates.
141 # Do this in the local Miri repo.
142 echo "This will pull a copy of the rust-lang/rust history into this Miri checkout, growing it by about 1GB."
143 read -r -p "To avoid that, abort now and set the RUSTC_GIT environment variable to an existing rustc checkout. Proceed? [y/N] "
144 if [[ ! $REPLY =~ ^[Yy]$ ]]; then
149 # Prepare the branch. Pushing works much better if we use as base exactly
150 # the commit that we pulled from last time, so we use the `rust-version`
151 # file as a good approximation of that.
152 BASE=$(cat "$MIRIDIR/rust-version")
153 echo "Preparing $USER/rust (base: $BASE)..."
154 if git fetch "https://github.com/$USER/rust" "$BRANCH" &>/dev/null; then
155 echo "The branch '$BRANCH' seems to already exist in 'https://github.com/$USER/rust'. Please delete it and try again."
158 git fetch https://github.com/rust-lang/rust $BASE
159 git push https://github.com/$USER/rust $BASE:refs/heads/$BRANCH -f
161 # Do the actual push.
163 echo "Pushing Miri changes..."
164 git push http://localhost:8000/$USER/rust.git$JOSH_FILTER.git HEAD:$BRANCH
165 # Do a round-trip check to make sure the push worked as expected.
167 git fetch http://localhost:8000/$USER/rust.git@$JOSH_FILTER.git $BRANCH &>/dev/null
168 if [[ $(git rev-parse HEAD) != $(git rev-parse FETCH_HEAD) ]]; then
169 echo "ERROR: Josh created a non-roundtrip push! Do NOT merge this into rustc!"
172 echo "Confirmed that the push round-trips back to Miri properly. Please create a rustc PR:"
173 echo " https://github.com/$USER/rust/pull/new/$BRANCH"
178 MIRI_SEED_START=${MIRI_SEED_START:-0} # default to 0
179 MIRI_SEEDS=${MIRI_SEEDS:-256} # default to 256
180 for SEED in $(seq $MIRI_SEED_START $(( $MIRI_SEED_START + $MIRI_SEEDS - 1 )) ); do
181 echo "Trying seed: $SEED"
182 MIRIFLAGS="$MIRIFLAGS -Zlayout-seed=$SEED -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; }
187 # Make sure we have an up-to-date Miri installed
189 # Run the requested benchmarks
190 if [ -z "${1+exists}" ]; then
191 BENCHES=( $(ls "$MIRIDIR/bench-cargo-miri" ) )
195 for BENCH in "${BENCHES[@]}"; do
196 hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path $MIRIDIR/bench-cargo-miri/$BENCH/Cargo.toml"
202 ## Run the auto-things.
203 if [ -z "$MIRI_AUTO_OPS" ]; then
204 export MIRI_AUTO_OPS=42
206 # Run this first, so that the toolchain doesn't change after
207 # other code has run.
208 if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then
210 # Let's make sure to actually use that toolchain, too.
214 if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then
218 if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-clippy" ] ; then
219 $0 clippy -- -D warnings
223 ## Prepare the environment
224 # Determine some toolchain properties
225 TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2)
226 SYSROOT=$(rustc +$TOOLCHAIN --print sysroot)
227 LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib
228 if ! test -d "$LIBDIR"; then
229 echo "Something went wrong determining the library dir."
230 echo "I got $LIBDIR but that does not exist."
231 echo "Please report a bug at https://github.com/rust-lang/miri/issues."
235 # Prepare flags for cargo and rustc.
236 CARGO="cargo +$TOOLCHAIN"
237 # Share target dir between `miri` and `cargo-miri`.
238 if [ -z "$CARGO_TARGET_DIR" ]; then
239 export CARGO_TARGET_DIR="$MIRIDIR/target"
241 # We configure dev builds to not be unusably slow.
242 if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then
243 export CARGO_PROFILE_DEV_OPT_LEVEL=2
245 # Enable rustc-specific lints (ignored without `-Zunstable-options`).
246 export RUSTFLAGS="-Zunstable-options -Wrustc::internal -Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros $RUSTFLAGS"
247 # We set the rpath so that Miri finds the private rustc libraries it needs.
248 export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS"
252 # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`.
254 if ! MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup --print-sysroot "$@")"; then
255 # Run it again so the user can see the error.
256 $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@"
257 echo "'cargo miri setup' failed"
263 # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account
264 # locally built vs. distributed rustc.
266 if [ -n "$MIRI_SYSROOT" ]; then
267 # Sysroot already set, use that.
270 # We need to build a sysroot.
271 if [ -n "$MIRI_TEST_TARGET" ]; then
272 build_sysroot --target "$MIRI_TEST_TARGET"
283 # "--locked" to respect the Cargo.lock file if it exists.
284 $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked "$@"
285 $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked "$@"
288 # Check, and let caller control flags.
289 $CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@"
290 $CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
293 # Build, and let caller control flags.
294 $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@"
295 $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
298 # First build and get a sysroot.
299 $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
301 if [ "$COMMAND" = "bless" ]; then
302 export MIRI_BLESS="Gesundheit"
304 # Then test, and let caller control flags.
305 # Only in root project as `cargo-miri` has no tests.
306 $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@"
309 # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
310 # that we set the MIRI_SYSROOT up the right way.
313 if [ "$LAST_ARG" = "--target" ]; then
315 export MIRI_TEST_TARGET="$ARG"
321 if [ "$FOUND_TARGET_OPT" = "0" ] && [ -n "$MIRI_TEST_TARGET" ]; then
322 # Make sure Miri actually uses this target.
323 MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET"
325 # First build and get a sysroot.
326 $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml
328 # Then run the actual command.
329 exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- $MIRIFLAGS "$@"
332 find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \
333 | xargs rustfmt +$TOOLCHAIN --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@"
336 $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@"
337 $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@"
340 # We carefully kept the working dir intact, so this will run cargo *on the workspace in the
341 # current working dir*, not on the main Miri workspace. That is exactly what RA needs.
345 echo "Unknown command: $COMMAND"