Skip to content

Commit 788616d

Browse files
authored
Merge pull request #704 from RalfJung/dev
Hopefully make it a bit easier to develop on Miri
2 parents 96b2225 + 0d53178 commit 788616d

File tree

2 files changed

+76
-53
lines changed

2 files changed

+76
-53
lines changed

README.md

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ You may be running `cargo miri` with a different compiler version than the one
105105
used to build the custom libstd that Miri uses, and Miri failed to detect that.
106106
Try deleting `~/.cache/miri`.
107107

108+
#### "no mir for `std::rt::lang_start_internal`"
109+
110+
This means the sysroot you are using was not compiled with Miri in mind. This
111+
should never happen when you use `cargo miri` because that takes care of setting
112+
up the sysroot. If you are using `miri` (the Miri driver) directly, see
113+
[below][testing-miri] for how to set up the sysroot.
114+
108115
## Development and Debugging
109116

110117
If you want to hack on miri yourself, great! Here are some resources you might
@@ -113,90 +120,100 @@ find useful.
113120
### Using a nightly rustc
114121

115122
Miri heavily relies on internal rustc interfaces to execute MIR. Still, some
116-
things (like adding support for a new intrinsic) can be done by working just on
117-
the Miri side.
118-
119-
To prepare, make sure you are using a nightly Rust compiler. The most
120-
convenient way is to install Miri using cargo, then you can easily run it on
121-
other projects:
122-
123-
```sh
124-
rustup component remove miri # avoid having Miri installed twice
125-
cargo +nightly install --path "$DIR" --force
126-
cargo +nightly miri setup
127-
```
123+
things (like adding support for a new intrinsic or a shim for an external
124+
function being called) can be done by working just on the Miri side.
128125

129-
(We are giving `+nightly` explicitly here all the time because it is important
130-
that all of these commands get executed with the same toolchain.)
126+
To prepare, make sure you are using a nightly Rust compiler. Then you should be
127+
able to just `cargo build` Miri.
131128

132129
In case this fails, your nightly might be incompatible with Miri master. The
133130
`rust-version` file contains the commit hash of rustc that Miri is currently
134131
tested against; you can use that to find a nightly that works or you might have
135132
to wait for the next nightly to get released.
136133

137-
If you want to use a different libstd (not the one that comes with the
138-
nightly), you can do that by running
134+
### Testing the Miri driver
135+
[testing-miri]: #testing-the-miri-driver
136+
137+
The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a
138+
version of `rustc` that, instead of compiling your code, runs it. It accepts
139+
all the same flags as `rustc` (though the ones only affecting code generation
140+
and linking obviously will have no effect) [and more][miri-flags].
141+
142+
To run the Miri driver, you need to have the `MIRI_SYSROOT` environment variable
143+
set to an appropriate sysroot. You can generate such a sysroot with the
144+
following incantation:
139145

140-
```sh
141-
XARGO_RUST_SRC=~/src/rust/rustc/src/ cargo +nightly miri setup
146+
```
147+
cargo run --bin cargo-miri -- miri setup
142148
```
143149

144-
Either way, you can now do `cargo +nightly miri run` to run Miri with your
145-
local changes on whatever project you are debugging.
150+
This basically runs the `cargo-miri` binary (which backs the `cargo miri`
151+
subcommand) with `cargo`, and asks it to `setup`. It should in the end print
152+
the directory where the libstd was built. In the following, we will assume it
153+
is `~/.cache/miri/HOST`; you may have to adjust that if you are not using Linux.
146154

147-
`cargo miri setup` should end in printing the directory where the libstd was
148-
built. For the next step to work, set that as your `MIRI_SYSROOT` environment
149-
variable:
155+
Now you can run the driver directly using
150156

151157
```sh
152-
export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said
158+
MIRI_SYSROOT=~/.cache/miri/HOST cargo run tests/run-pass/format.rs # or whatever test you like
153159
```
154160

155-
### Testing Miri
156-
157-
Instead of running an entire project using `cargo miri`, you can also use the
158-
Miri "driver" directly to run just a single file. That can be easier during
159-
debugging.
161+
and you can run the test suite using
160162

161-
```sh
162-
cargo run tests/run-pass/format.rs # or whatever test you like
163163
```
164+
cargo test
165+
```
166+
167+
We recommend adding the `--release` flag to make tests run faster.
164168

165-
You can also run the test suite with `cargo test --release`. `cargo test
166-
--release FILTER` only runs those tests that contain `FILTER` in their filename
167-
(including the base directory, e.g. `cargo test --release fail` will run all
168-
compile-fail tests). We recommend using `--release` to make test running take
169-
less time.
169+
`cargo test --release FILTER` only runs those tests that contain `FILTER` in
170+
their filename (including the base directory, e.g. `cargo test --release fail`
171+
will run all compile-fail tests).
170172

171-
Now you are set up! You can write a failing test case, and tweak miri until it
172-
fails no more.
173173
You can get a trace of which MIR statements are being executed by setting the
174174
`MIRI_LOG` environment variable. For example:
175175

176176
```sh
177177
MIRI_LOG=info cargo run tests/run-pass/vecs.rs
178178
```
179179

180-
Setting `MIRI_LOG` like this will configure logging for miri itself as well as
180+
Setting `MIRI_LOG` like this will configure logging for Miri itself as well as
181181
the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You
182-
can also do more targeted configuration, e.g. to debug the stacked borrows
183-
implementation:
182+
can also do more targeted configuration, e.g. the following helps debug the
183+
stacked borrows implementation:
184+
184185
```sh
185186
MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs
186187
```
187188

188189
In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an
189-
evaluation error was originally created.
190+
evaluation error was originally raised.
191+
192+
### Testing `cargo miri`
193+
194+
Working with the driver directly gives you full control, but you also lose all
195+
the convenience provided by cargo. Once your test case depends on a crate, it
196+
is probably easier to test it with the cargo wrapper. You can install your
197+
development version of Miri using
198+
199+
```
200+
cargo install --path . --force
201+
```
202+
203+
and then you can use it as if it was installed by `rustup`. Make sure you use
204+
the same toolchain when calling `cargo miri` that you used when installing Miri!
190205

206+
There's a test for the cargo wrapper in the `test-cargo-miri` directory; run
207+
`./run-test.py` in there to execute it.
191208

192209
### Using a locally built rustc
193210

194-
Since the heart of Miri (the main interpreter engine) lives in rustc, working on
195-
Miri will often require using a locally built rustc. The bug you want to fix
196-
may actually be on the rustc side, or you just need to get more detailed trace
197-
of the execution than what is possible with release builds -- in both cases, you
198-
should develop miri against a rustc you compiled yourself, with debug assertions
199-
(and hence tracing) enabled.
211+
A big part of the Miri driver lives in rustc, so working on Miri will sometimes
212+
require using a locally built rustc. The bug you want to fix may actually be on
213+
the rustc side, or you just need to get more detailed trace of the execution
214+
than what is possible with release builds -- in both cases, you should develop
215+
miri against a rustc you compiled yourself, with debug assertions (and hence
216+
tracing) enabled.
200217

201218
The setup for a local rustc works as follows:
202219
```sh
@@ -216,18 +233,21 @@ rustup override set custom
216233
```
217234

218235
With this, you should now have a working development setup! See
219-
["Testing Miri"](#testing-miri) above for how to proceed.
236+
[above][testing-miri] for how to proceed working with the Miri driver. Notice
237+
that rustc's sysroot is already built for Miri in this case, so you can set
238+
`MIRI_SYSROOT=$(rustc --print sysroot)`.
220239

221240
Running `cargo miri` in this setup is a bit more complicated, because the Miri
222-
binary you just created does not actually run without some environment variables.
223-
But you can contort cargo into calling `cargo miri` the right way for you:
241+
binary you just created needs help to find the libraries it links against. On
242+
Linux, you can set the rpath to make this "just work":
224243

225244
```sh
226-
# in some other project's directory, to run `cargo miri test`:
227-
MIRI_SYSROOT=$(rustc +custom --print sysroot) cargo +custom run --manifest-path /path/to/miri/Cargo.toml --bin cargo-miri --release -- miri test
245+
export RUSTFLAGS="-C link-args=-Wl,-rpath,$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/lib"
246+
cargo install --path . --force
228247
```
229248

230249
### Miri `-Z` flags and environment variables
250+
[miri-flags]: #miri--z-flags-and-environment-variables
231251

232252
Several `-Z` flags are relevant for Miri:
233253

src/bin/cargo-miri.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ fn ask(question: &str) {
172172
/// done all this already.
173173
fn setup(ask_user: bool) {
174174
if std::env::var("MIRI_SYSROOT").is_ok() {
175+
if !ask_user {
176+
println!("WARNING: MIRI_SYSROOT already set, not doing anything.")
177+
}
175178
return;
176179
}
177180

0 commit comments

Comments
 (0)