add Miri build script (#745)

add Miri build script
This commit is contained in:
Ralf Jung 2019-05-28 08:38:08 +02:00 committed by GitHub
commit 3c930e48e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 113 additions and 55 deletions

View File

@ -16,7 +16,6 @@ env:
global:
- RUST_TEST_NOCAPTURE=1
- RUST_BACKTRACE=1
- RUSTFLAGS="-C debug-assertions"
before_script:
# Linux: install extra stuff for cross-compilation

View File

@ -40,12 +40,15 @@ rustc_version = { version = "0.2.3", optional = true }
env_logger = "0.6"
log = "0.4"
shell-escape = "0.1.4"
hex = "0.3.2"
rand = "0.6"
# A noop dependency that changes in the Rust repository, it's a bit of a hack.
# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
# for more information.
rustc-workspace-hack = "1.0.0"
hex = "0.3.2"
rand = "0.6"
# Depend on num-traits with default features to avoid having to rebuild
# between "cargo build" and "cargo intall".
num-traits = "*"
[build-dependencies]
vergen = "3"

View File

@ -141,42 +141,30 @@ version of `rustc` that, instead of compiling your code, runs it. It accepts
all the same flags as `rustc` (though the ones only affecting code generation
and linking obviously will have no effect) [and more][miri-flags].
To run the Miri driver, you need to have the `MIRI_SYSROOT` environment variable
set to an appropriate sysroot. You can generate such a sysroot with the
following incantation:
```
cargo run --bin cargo-miri -- miri setup
```
This basically runs the `cargo-miri` binary (which backs the `cargo miri`
subcommand) with `cargo`, and asks it to `setup`. It should in the end print
the directory where the libstd was built. In the following, we will assume it
is `~/.cache/miri/HOST`; you may have to adjust that if you are not using Linux.
Now you can run the driver directly using
Running the Miri driver requires some fiddling with environment variables, so
the `miri` script helps you do that. For example, you can run the driver on a
particular file by doing
```sh
MIRI_SYSROOT=~/.cache/miri/HOST cargo run tests/run-pass/format.rs # or whatever test you like
./miri run tests/run-pass/format.rs
./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu
```
and you can run the test suite using
and you can run the test suite using:
```
cargo test
./miri test
```
We recommend adding the `--release` flag to make tests run faster.
`cargo test --release FILTER` only runs those tests that contain `FILTER` in
their filename (including the base directory, e.g. `cargo test --release fail`
will run all compile-fail tests).
`./miri test FILTER` only runs those tests that contain `FILTER` in their
filename (including the base directory, e.g. `./miri test fail` will run all
compile-fail tests).
You can get a trace of which MIR statements are being executed by setting the
`MIRI_LOG` environment variable. For example:
```sh
MIRI_LOG=info cargo run tests/run-pass/vecs.rs
MIRI_LOG=info ./miri run tests/run-pass/vecs.rs
```
Setting `MIRI_LOG` like this will configure logging for Miri itself as well as
@ -185,7 +173,7 @@ can also do more targeted configuration, e.g. the following helps debug the
stacked borrows implementation:
```sh
MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs
MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs
```
In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an
@ -199,7 +187,7 @@ is probably easier to test it with the cargo wrapper. You can install your
development version of Miri using
```
cargo install --path . --force
./miri install
```
and then you can use it as if it was installed by `rustup`. Make sure you use
@ -235,18 +223,7 @@ rustup override set custom
```
With this, you should now have a working development setup! See
[above][testing-miri] for how to proceed working with the Miri driver. Notice
that rustc's sysroot is already built for Miri in this case, so you can set
`MIRI_SYSROOT=$(rustc --print sysroot)`.
Running `cargo miri` in this setup is a bit more complicated, because the Miri
binary you just created needs help to find the libraries it links against. On
Linux, you can set the rpath to make this "just work":
```sh
export RUSTFLAGS="-C link-args=-Wl,-rpath,$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/lib"
cargo install --path . --force
```
[above][testing-miri] for how to proceed working with the Miri driver.
### Miri `-Z` flags and environment variables
[miri-flags]: #miri--z-flags-and-environment-variables

83
miri Executable file
View File

@ -0,0 +1,83 @@
#!/bin/sh
set -e
# I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work.
TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4)
SYSROOT=$(rustc --print sysroot)
# We set the rpath so that Miri finds the private rustc libraries it needs.
# We enable debug-assertions to get tracing.
# We enable line-only debuginfo for backtraces.
export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions -C debuginfo=1"
## Helper functions
# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`.
build_sysroot() {
# Build once, for the user to see.
cargo run --release --bin cargo-miri -- miri setup "$@"
# Call again, to just set env var.
eval $(cargo run --release -q --bin cargo-miri -- miri setup --env "$@")
export MIRI_SYSROOT
}
# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account
# locally built vs. distributed rustc.
find_sysroot() {
# Get ourselves a sysroot
if [ -n "$MIRI_SYSROOT" ]; then
# Sysroot already set, use that.
true
elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then
# A local rustc build.
if [ -n "$MIRI_TEST_TARGET" ]; then
# Foreign targets still need a build. Use the rustc sources.
export XARGO_RUST_SRC="$SYSROOT/../../../src"
build_sysroot --target "$MIRI_TEST_TARGET"
else
# Assume we have a proper host libstd in $SYSROOT.
true
fi
else
# A normal toolchain. We have to build a sysroot either way.
if [ -n "$MIRI_TEST_TARGET" ]; then
build_sysroot --target "$MIRI_TEST_TARGET"
else
build_sysroot
fi
fi
}
## Main
COMMAND="$1"
shift
case "$COMMAND" in
install)
# "--locked" to respect the Cargo.lock file if it exists,
# "--offline" to avoid querying the registry (for yanked packages).
exec cargo "$COMMAND" --path "$(dirname "$0")" --force --locked --offline "$@"
;;
build)
# Build, and let caller control flags.
exec cargo "$COMMAND" --release "$@"
;;
test|run)
# In "run" mode, scan for "--target" to set the "MIRI_TEST_TARGET" env var so
# that we set the MIRI_SYSROOT up the right way.
if [ "$COMMAND" = "run" ] && [ -z "$MIRI_TEST_TARGET" ]; then
for ARG in "$@"; do
if [ "$LAST_ARG" = "--target" ]; then
# Found it!
export MIRI_TEST_TARGET="$ARG"
break
fi
LAST_ARG="$ARG"
done
fi
# First build and get a sysroot.
cargo build --release
find_sysroot
# Then run the actual command.
exec cargo "$COMMAND" --release "$@"
;;
esac

View File

@ -243,6 +243,7 @@ path = "lib.rs"
File::create(dir.join("lib.rs")).unwrap();
// Run xargo.
let target = get_arg_flag_value("--target");
let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable
let mut command = Command::new("xargo");
command.arg("build").arg("-q")
.current_dir(&dir)
@ -265,7 +266,9 @@ path = "lib.rs"
};
let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) };
std::env::set_var("MIRI_SYSROOT", &sysroot);
if !ask_user {
if print_env {
println!("MIRI_SYSROOT={}", sysroot.display());
} else if !ask_user {
println!("A libstd for Miri is now available in `{}`", sysroot.display());
}
}

View File

@ -3,36 +3,29 @@ set -euo pipefail
# Determine configuration
if [ "$TRAVIS_OS_NAME" == osx ]; then
MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/
FOREIGN_TARGET=i686-apple-darwin
else
MIRI_SYSROOT_BASE=~/.cache/miri/
FOREIGN_TARGET=i686-unknown-linux-gnu
fi
# Prepare
echo "Build and install miri"
cargo build --release --all-features --all-targets
cargo install --all-features --force --path .
echo
echo "Get ourselves a MIR-full libstd for the host and a foreign architecture"
cargo miri setup
cargo miri setup --target "$FOREIGN_TARGET"
./miri build --all-features --all-targets
./miri install
echo
# Test
function run_tests {
cargo test --release --all-features
test-cargo-miri/run-test.py
./miri test
# "miri test" has built the sysroot for us, now this should pass without
# any interactive questions.
test-cargo-miri/run-test.py
}
echo "Test host architecture"
export MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST
run_tests
echo
echo "Test foreign architecture ($FOREIGN_TARGET)"
export MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TEST_TARGET="$FOREIGN_TARGET"
run_tests
MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests
echo