Skip to content

Commit 5d45bd6

Browse files
authored
Fix test coverage documentation (#4064)
1 parent d3872f1 commit 5d45bd6

File tree

1 file changed

+38
-17
lines changed

1 file changed

+38
-17
lines changed

guide/src/wasm-bindgen-test/coverage.md

+38-17
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ Currently it is particularly difficult to [deliver compile-line arguments to pro
2222

2323
Make sure you are using `RUSTFLAGS=-Cinstrument-coverage -Zno-profiler-runtime`.
2424

25-
Due to the current limitation of `llvm-cov`, we can't collect profiling symbols from the generated `.wasm` files. Instead, we can grab them from the LLVM IR with `--emit=llvm-ir` by using Clang. Additionally, the emitted LLVM IR files by Rust contain invalid code that can't be parsed by Clang, so they need to be adjusted. Clang must use the same LLVM version that Rustc is using, which can be checkd by calling `rustc +nightly -vV`.
25+
Due to the current limitation of `llvm-cov`, we can't collect profiling symbols from the generated `.wasm` files. Instead, we can grab them from the LLVM IR with `--emit=llvm-ir` by using Clang. Additionally, the emitted LLVM IR files by Rust contain invalid code that can't be parsed by Clang, so they need to be adjusted.
26+
27+
At the time of writing Rust Nightly uses LLVM v19, however [minicov] only supports LLVM v18. Usage of Clang or any LLVM tools must match the version used by [minicov].
28+
29+
[minicov]: https://crates.io/crates/minicov
2630

2731
### Arguments to the test runner
2832

@@ -43,6 +47,8 @@ This feature relies on the [minicov] crate, which provides a profiling runtime f
4347

4448
### Example
4549

50+
This adapts code taken from the [Rustc book], see that for more examples and general information on test coverage as well.
51+
4652
```sh
4753
# Run the tests:
4854
# - `CARGO_HOST_RUSTFLAGS` to pass the configuration to `wasm-bindgen-macro`.
@@ -53,26 +59,41 @@ RUSTFLAGS="-Cinstrument-coverage -Zno-profiler-runtime --emit=llvm-ir --cfg=wasm
5359
CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER=wasm-bindgen-test-runner \
5460
cargo +nightly test -Ztarget-applies-to-host -Zhost-config --tests
5561
# Adjust the LLVM IR and compile to object files:
56-
# - Replaces every function body with `unreachable`.
57-
# - Removes Rust-specific `range` annotations from function signatures.
58-
name=name_of_the_tested_crate_in_snake_case; \
59-
for file in `ls target/wasm32-unknown-unknown/debug/deps/$name-*.ll`; \
60-
do \
61-
perl -i -p0e 's/(^define.*?$).*?^}/$1\nstart:\n unreachable\n}/gms' $file && \
62-
perl -i -p0e 's/(?<=noundef) range\(.*?\)//g' $file && \
63-
clang $file -Wno-override-module -c; \
62+
# - Extract a list of compiled artifacts from Cargo and filter them with `jq`.
63+
# - Figure out the path to the LLVM IR file corresponding to an artifact.
64+
# - Replace every function body with `unreachable`.
65+
# - Remove Rust-specific `range` annotations from function signatures.
66+
# - Compile to object file with Clang and store for later usage with `llvm-cov`.
67+
crate_name=name_of_the_tested_crate_in_snake_case
68+
objects=()
69+
IFS=$'\n'
70+
for file in $(
71+
CARGO_HOST_RUSTFLAGS=--cfg=wasm_bindgen_unstable_test_coverage \
72+
RUSTFLAGS="-Cinstrument-coverage -Zno-profiler-runtime --emit=llvm-ir --cfg=wasm_bindgen_unstable_test_coverage" \
73+
cargo +nightly test -Ztarget-applies-to-host -Zhost-config --tests --no-run --message-format=json | \
74+
jq -r "select(.reason == \"compiler-artifact\") | (select(.target.kind == [\"test\"]) // select(.target.name == \"$crate_name\")) | .filenames[0]"
75+
)
76+
do
77+
if [[ ${file##*.} == "rlib" ]]; then
78+
base=$(basename $file .rlib)
79+
file=$(dirname $file)/${base#"lib"}.ll
80+
else
81+
file=$(dirname $file)/$(basename $file .wasm).ll
82+
fi
83+
84+
perl -i -p0e 's/(^define.*?$).*?^}/$1\nstart:\n unreachable\n}/gms' $file
85+
perl -i -p0e 's/(^define( [^ ]+)*) range\(.*?\)/$1/gm' $file
86+
87+
output = $(basename $file .ll).o
88+
clang-18 $input -Wno-override-module -c -o $output
89+
objects+=(-object $output)
6490
done
6591
# Merge all generated raw profiling data.
66-
# This uses `cargo-binutils` which uses LLVM tools shipped by Rust to make sure there is no LLVM version discrepancy.
67-
# But `llvm-profdata` can be used directly as well.
68-
# See <https://crates.io/crates/cargo-binutils>.
69-
rust-profdata merge -sparse ./*.profraw -o coverage.profdata
70-
# Produce test coverage data in the HTML format.
71-
rust-cov show --instr-profile=coverage.profdata --object ./*.o --format=html --Xdemangler=rust-demangler --sources src --output-dir coverage
92+
llvm-profdata-18 merge -sparse *.profraw -o coverage.profdata
93+
# Produce test coverage data in the HTML format and pass the object files we generated earlier.
94+
llvm-cov-18 show -show-instantiations=false -Xdemangler=rustfilt -output-dir coverage -format=html -instr-profile=coverage.profdata ${objects[@]} -sources src
7295
```
7396

74-
The [rustc book] has a lot more exapmles and information on test coverage as well.
75-
7697
[rustc book]: https://doc.rust-lang.org/nightly/rustc/instrument-coverage.html
7798

7899
## Attribution

0 commit comments

Comments
 (0)