Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make cargo -Zbuild-std work with -Cinstrument-coverage #133300

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

Enselic
Copy link
Member

@Enselic Enselic commented Nov 21, 2024

By not trying to inject a profiler runtime when only building an rlib. This logic already exists for the panic runtime.

This makes

RUSTFLAGS="-Cinstrument-coverage" cargo build -Zbuild-std=std,profiler_builtins

work. Note that you probably also need
RUST_COMPILER_RT_FOR_PROFILER=$src/llvm-project/compiler-rt in your environment.

Fixes #79401

TODO

  • Figure out how to add a regression test for this. Maybe enough to add a test to the cargo repo? I think cargo tests are run as part of Rust CI?

Demonstration

Before this fix you get these errors:

$ rm -rf target ; RUST_COMPILER_RT_FOR_PROFILER=/home/martin/src/llvm-project/compiler-rt RUSTFLAGS="-Cinstrument-coverage" cargo +nightly build --release -Zbuild-std=std,profiler_builtins
error: `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]`
error[E0152]: found duplicate lang item `manually_drop`
    = note: first definition in `core` loaded from /home/martin/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-d453bab70303062c.rlib
    = note: second definition in the local crate (`core`)

With the fix the build succeeds:

$ rm -rf target ; RUST_COMPILER_RT_FOR_PROFILER=/home/martin/src/llvm-project/compiler-rt RUSTFLAGS="-Cinstrument-coverage" cargo +stage1 build --release -Zbuild-std=std,profiler_builtins
    Finished `release` profile [optimized] target(s) in 45.57s

And we can check code coverage. My example program looks like this:

fn main() {
    if std::env::args_os().nth(1) == Some("write-file".into()) {
        std::fs::write("hello.txt", "Hello, world!").unwrap();
    } else {
        println!("Hello, world!");
    }
}

when the program prints to stdout:

$ LLVM_PROFILE_FILE=stdout.profraw ./target/release/hello-world
Hello, world!

we can see that fs::write() is not being used (note the 0's):

$ /home/martin/src/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata merge -sparse stdout.profraw -o stdout.profdata
$ /home/martin/src/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-cov show target/release/hello-world --sources /home/martin/src/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/library/std/src/fs.rs --instr-profile stdout.profdata --color | grep -A 3 'pub fn write(&mut self, write: b
ool) -> &mut Self {'
 1357|      0|    pub fn write(&mut self, write: bool) -> &mut Self {
 1358|      0|        self.0.write(write);
 1359|      0|        self
 1360|      0|    }

but when we print to a file:

$ LLVM_PROFILE_FILE=file.profraw ./target/release/hello-world write-file

the code coverage shows fs::write() as being used (note the 1's):

$ /home/martin/src/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-profdata merge -sparse file.profraw -o file.profdata
$ /home/martin/src/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-cov show target/release/hello-world --sources /home/martin/src/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/library/std/src/fs.rs --instr-profile file.profdata --color | grep -A 3 'pub fn write(&mut self, write: bool) -> &mut Self {'
 1357|      1|    pub fn write(&mut self, write: bool) -> &mut Self {
 1358|      1|        self.0.write(write);
 1359|      1|        self
 1360|      1|    }

By not trying to inject a profiler runtime when only building an rlib.
This logic already exists for the panic runtime.

This makes

    RUSTFLAGS="-Cinstrument-coverage" cargo build -Zbuild-std=std,profiler_builtins

work. Note that you probably also need
`RUST_COMPILER_RT_FOR_PROFILER=$src/llvm-project/compiler-rt` in your
environment.
@rustbot
Copy link
Collaborator

rustbot commented Nov 21, 2024

r? @lcnr

rustbot has assigned @lcnr.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Nov 21, 2024
@Enselic Enselic changed the title Make cargo -Zbuild-std work with -Cinstrument-coverage Make cargo -Zbuild-std work with -Cinstrument-coverage Nov 21, 2024
@Enselic Enselic added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 21, 2024
@@ -698,11 +698,14 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
Ok(unsafe { *load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name)? })
}

fn only_generating_rlib(&mut self) -> bool {
!self.tcx.crate_types().iter().any(|ct| *ct != CrateType::Rlib)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
!self.tcx.crate_types().iter().any(|ct| *ct != CrateType::Rlib)
self.tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib)

avoids double negation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incompatibility using both -Zinstrument-coverage and -Z build-std
4 participants