I am rediscovering NixOS and trying to setup a development environment for Rust.
So far, I have the following default.nix file in my repo:
# default.nix
with import <nixpkgs> { };
stdenv.mkDerivation {
name = "dev-environment";
buildInputs = [
pkg-config
openssl
libgit2
zlib
rustc
cargo
llvm
rustc.llvmPackages.llvm
grcov
wxGTK30-gtk3
];
}
Everything works except code ceverage. Here is what happens when I run grcov:
❯ grcov . -s . --binary-path target/debug/
17:47:35 [ERROR] Error while executing llvm tools: We couldn't find llvm-profdata. Try installing the llvm-tools component with `rustup component add llvm-tools-preview`.
But llvm-profdata
does exists on PATH:
❯ llvm-profdata
llvm-profdata: No command specified!
USAGE: llvm-profdata <merge|show|overlap> [args...]
I dont know how to solve it. Please help
Alright, I have the exact same issue. I did some investigation:
Grcov is raising an error from here because this path is wrong.
The Tool
enum comes from the cargo-binutils project which is getting the path from a rustlib()
function defined in the rustc.rs
file. Here we can see the path where grcov is looking for lvm-profdata :
$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin
This path does not exist (there is no bin
folder here so no profdata because even if it’s in our PATH, it lives under a different folder (for my config) :
[nix-shell]$ echo "$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/bin"
/nix/store/xjx558ys8fnyl0kwxs4ws0806362snj7-rustc-1.60.0/lib/rustlib/x86_64-unknown-linux-gnu/bin
[nix-shell]$ whereis llvm-profdata
llvm-profdata: /nix/store/qp4b28b9x5nqspvl7hsn8m5pp5j1j83x-llvm-14.0.1/bin/llvm-profdata
1 Like
Yeap, I saw it too. This is definitely NixOS related and not an issue in grcov
.
Alright, thank’s for the issue on grcov, the solution on their side would be to add an “LLVM_TOOLS_PATH” environment variable and optionally reading the lib’s location from it.
By the way, i’m thinking : if there is a maintainer on the grcov package he must have been using the tool… I sent an email to justin@restivo.me telling him about this discourse, maybe he will respond.
1 Like
Until we have a clean solution here is a little work-around that i use to run my coverage (if you use podman/docker):
shellHook = ''
podman build -t grcov - <<EOF
FROM docker.io/rust
WORKDIR /srv
RUN rustup component add llvm-tools-preview
RUN cargo install grcov
ENTRYPOINT ["grcov"]
EOF
alias grcov='podman run -v $PWD:/srv grcov'
'';
You can then use grcov almost as if you had it installed
2 Likes
I just tried grcov
with my nascent rust environment. First I did cargo install grcov
, but then running grcov
produced the error about missing llvm-profdata
.
Next I did what the error message suggested: rustup component add llvm-tools-preview
. That solved the problem; although llvm-profdata
is still not on $PATH
.
My rust environment is declared in this flake (derived from Rust - NixOS Wiki)
{
inputs = {
nixpkgs.url = "git+file:///nix/nixpkgs?ref=upstream/nixpkgs-unstable";
};
outputs = inputs@{ self, nixpkgs, ... }:
let
pkgs = import nixpkgs { localSystem = "${system}"; };
system = "x86_64-linux";
rust_shell_pkgs = with pkgs; [
llvmPackages_latest.bintools
llvmPackages_latest.lld
llvmPackages_latest.llvm
zlib
rustup
];
in {
# https://nixos.wiki/wiki/Rust
# `nix develop .#rust_shell`
rust_shell = pkgs.mkShell rec {
name = "rust_shell";
buildInputs = rust_shell_pkgs;
NIX_DEBUG = 1;
RUST_BACKTRACE = 1;
RUSTC_VERSION = pkgs.lib.strings.fileContents ./rust-toolchain;
# https://github.com/rust-lang/rust-bindgen#environment-variables
LIBCLANG_PATH =
pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
# Add some headers to bindgen search path
BINDGEN_EXTRA_CLANG_ARGS =
(builtins.map (a: ''-I"${a}/include"'') [ pkgs.glibc.dev ])
++ [
''
-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
''-I"${pkgs.glib.dev}/include/glib-2.0"''
''-I"${pkgs.glib.out}/lib/glib-2.0/include/"''
];
shellHook = ''
export PATH="''${CARGO_HOME:-$PWD/.cargo}/bin:$PATH"
toolchain_bin="toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin"
export PATH="''${RUSTUP_HOME:-$PWD/.rustup}/$toolchain_bin:$PATH"
# call `rustup` to initialize toolchain, loading cargo, et. al.
rustup --version
'';
};
devShell.x86_64-linux = self.rust_shell;
};
}
Of note is that this shell installs rustup
but not cargo
; it let’s rustup
install (and manage) cargo
and other executables. The shell defines $LIBCLANG_PATH
and $BINDGEN_EXTRA_CLANG_ARGS
; I do not yet know rust well enough to know when these matter.
I’m not yet sure how best to integrate installation of grcov
and llvm-tools-preview
into this shell. It might be sufficient to add them to the end of the shell hook if there execution would take no time when already present. Or, maybe they could be added to Cargo.toml (assuming it has the notion of dev dependencies).
My full series of commands for success was
nix develop
cargo install grcov
rustup component add llvm-tools-preview
RUSTFLAGS="-Cinstrument-coverage" cargo build
RUSTFLAGS="-Cinstrument-coverage" LLVM_PROFILE_FILE="your_name-%p-%m.profraw" cargo test
grcov . -s . --binary-path target/debug/
1 Like
Yes, this is very similar to the solution I used eventually. Thank you