Code coverage (#529)

Adds `make coverage` (cargo-llvm-cov over the full workspace including
revive-llvm-builder), a new "Code coverage" book chapter that briefly
explains how to run it, and a PR workflow that runs coverage and
comments on the PR (it updates the same comment if it already exists)
when the `measure code coverage` label is applied (see e.g. [this
comment](https://github.com/paritytech/revive/pull/529#issuecomment-4966136441)).

Building instrumented LLVM and generating an LLVM C++ coverage report is
also possible, see accompanying [PR description
#575](https://github.com/paritytech/revive/pull/575) for more details.

---------

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Signed-off-by: xermicus <bigcyrill@hotmail.com>
Co-authored-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
Co-authored-by: xermicus <cyrill@parity.io>
Co-authored-by: elle-j <linnea@parity.io>
Co-authored-by: LJ <81748770+elle-j@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-07-16 14:48:44 +02:00
1 parent ca3c770228
commit ed95ffbdfe
40 files changed
+882 -123

No files matched your search

@@ -120,6 +120,7 @@ fn build_crt(
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DLLVM_ENABLE_PROJECTS='compiler-rt'",
"-DLLVM_ENABLE_ZLIB='Off'",
format!("-DLLVM_TARGETS_TO_BUILD='{}'", Platform::AArch64).as_str(),
"-DLLVM_DEFAULT_TARGET_TRIPLE='aarch64-unknown-linux-musl'",
"-DLLVM_BUILD_TESTS='Off'",
@@ -200,6 +201,7 @@ fn build_host(
"-DLLVM_INCLUDE_UTILS='Off'",
"-DLLVM_ENABLE_PROJECTS='clang;lld'",
"-DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind'",
"-DLLVM_ENABLE_ZLIB='Off'",
"-DLIBCXX_CXX_ABI='libcxxabi'",
"-DLIBCXX_HAS_MUSL_LIBC='On'",
"-DLIBCXX_ENABLE_SHARED='Off'",
+14 -6
View File
@@ -8,7 +8,8 @@ use std::path::Path;
use std::process::Command;
/// The build options shared by all platforms.
pub const SHARED_BUILD_OPTS: [&str; 21] = [
/// `LLVM_ENABLE_ZLIB` is emitted by [`shared_build_opts_coverage`].
pub const SHARED_BUILD_OPTS: [&str; 20] = [
"-DPACKAGE_VENDOR='Parity Technologies'",
"-DCMAKE_BUILD_WITH_INSTALL_RPATH=1",
"-DLLVM_BUILD_DOCS='Off'",
@@ -18,7 +19,6 @@ pub const SHARED_BUILD_OPTS: [&str; 21] = [
"-DLLVM_ENABLE_DOXYGEN='Off'",
"-DLLVM_ENABLE_SPHINX='Off'",
"-DLLVM_ENABLE_OCAMLDOC='Off'",
"-DLLVM_ENABLE_ZLIB='Off'",
"-DLLVM_ENABLE_ZSTD='Off'",
"-DLLVM_ENABLE_LIBXML2='Off'",
"-DLLVM_ENABLE_BINDINGS='Off'",
@@ -188,10 +188,18 @@ pub fn shared_build_opts_tests(enabled: bool) -> Vec<String> {
/// The code coverage build options shared by all platforms.
pub fn shared_build_opts_coverage(enabled: bool) -> Vec<String> {
vec![format!(
"-DLLVM_BUILD_INSTRUMENTED_COVERAGE='{}'",
if enabled { "On" } else { "Off" },
)]
vec![
format!(
"-DLLVM_BUILD_INSTRUMENTED_COVERAGE='{}'",
if enabled { "On" } else { "Off" },
),
// zlib is required to be able to read the compressed profiles that
// instrumented resolc binaries emit.
format!(
"-DLLVM_ENABLE_ZLIB='{}'",
if enabled { "FORCE_ON" } else { "Off" },
),
]
}
/// Use of compiler cache (ccache) to speed up the build process.
@@ -98,6 +98,7 @@ fn build_host(
crate::Platform::PolkaVM
),
"-DLLVM_ENABLE_PROJECTS='clang;lld'",
"-DLLVM_ENABLE_ZLIB='Off'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::SHARED_BUILD_OPTS_NOT_MUSL)
@@ -70,6 +70,7 @@ pub fn build(
musl_target.as_path(),
llvm_target_crt.as_path(),
ccache_variant,
enable_coverage,
)?;
build_target(
build_type,
@@ -121,6 +122,7 @@ fn build_crt(
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DLLVM_ENABLE_PROJECTS='compiler-rt'",
"-DLLVM_ENABLE_ZLIB='Off'",
format!("-DLLVM_TARGETS_TO_BUILD='{}'", Platform::X86).as_str(),
"-DLLVM_DEFAULT_TARGET_TRIPLE='x86_64-pc-linux-musl'",
"-DLLVM_BUILD_TESTS='Off'",
@@ -166,69 +168,78 @@ fn build_host(
musl_target_directory: &Path,
crt_target_directory: &Path,
ccache_variant: Option<CcacheVariant>,
enable_coverage: bool,
) -> anyhow::Result<()> {
crate::utils::command(
Command::new("cmake")
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DDEFAULT_SYSROOT='{}'",
musl_target_directory.to_string_lossy()
)
.as_str(),
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
"-DCMAKE_BUILD_TYPE='Release'",
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DCLANG_DEFAULT_CXX_STDLIB='libc++'",
"-DCLANG_DEFAULT_RTLIB='compiler-rt'",
"-DLLVM_DEFAULT_TARGET_TRIPLE='x86_64-pc-linux-musl'",
"-DLLVM_TARGETS_TO_BUILD='X86'",
"-DLLVM_BUILD_TESTS='Off'",
"-DLLVM_BUILD_UTILS='Off'",
"-DLLVM_INCLUDE_TESTS='Off'",
"-DLLVM_INCLUDE_UTILS='Off'",
"-DLLVM_ENABLE_PROJECTS='clang;lld'",
"-DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind'",
"-DLIBCXX_CXX_ABI='libcxxabi'",
"-DLIBCXX_HAS_MUSL_LIBC='On'",
"-DLIBCXX_ENABLE_SHARED='Off'",
"-DLIBCXX_ENABLE_STATIC='On'",
"-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY='On'",
"-DLIBCXXABI_ENABLE_SHARED='Off'",
"-DLIBCXXABI_ENABLE_STATIC='On'",
"-DLIBCXXABI_ENABLE_STATIC_UNWINDER='On'",
"-DLIBCXXABI_USE_LLVM_UNWINDER='On'",
"-DLIBCXXABI_USE_COMPILER_RT='On'",
"-DLIBUNWIND_ENABLE_STATIC='On'",
"-DLIBUNWIND_ENABLE_SHARED='Off'",
"-DCOMPILER_RT_BUILD_CRT='On'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='On'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'",
"-DLIBCLANG_BUILD_STATIC='On'",
"-DBUILD_SHARED_LIBS='Off'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
)),
"LLVM host building cmake",
)?;
let mut cmake_command = Command::new("cmake");
cmake_command
.args([
"-S",
source_directory.to_string_lossy().as_ref(),
"-B",
build_directory.to_string_lossy().as_ref(),
"-G",
"Ninja",
format!(
"-DDEFAULT_SYSROOT='{}'",
musl_target_directory.to_string_lossy()
)
.as_str(),
"-DLINKER_SUPPORTS_COLOR_DIAGNOSTICS=0",
format!(
"-DCMAKE_INSTALL_PREFIX='{}'",
target_directory.to_string_lossy()
)
.as_str(),
"-DCMAKE_BUILD_TYPE='Release'",
"-DCMAKE_C_COMPILER='clang'",
"-DCMAKE_CXX_COMPILER='clang++'",
"-DCLANG_DEFAULT_CXX_STDLIB='libc++'",
"-DCLANG_DEFAULT_RTLIB='compiler-rt'",
"-DLLVM_DEFAULT_TARGET_TRIPLE='x86_64-pc-linux-musl'",
"-DLLVM_TARGETS_TO_BUILD='X86'",
"-DLLVM_BUILD_TESTS='Off'",
"-DLLVM_BUILD_UTILS='Off'",
"-DLLVM_INCLUDE_TESTS='Off'",
"-DLLVM_INCLUDE_UTILS='Off'",
"-DLLVM_ENABLE_PROJECTS='clang;lld'",
"-DLLVM_ENABLE_RUNTIMES='compiler-rt;libcxx;libcxxabi;libunwind'",
"-DLLVM_ENABLE_ZLIB='Off'",
"-DLIBCXX_CXX_ABI='libcxxabi'",
"-DLIBCXX_HAS_MUSL_LIBC='On'",
"-DLIBCXX_ENABLE_SHARED='Off'",
"-DLIBCXX_ENABLE_STATIC='On'",
"-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY='On'",
"-DLIBCXXABI_ENABLE_SHARED='Off'",
"-DLIBCXXABI_ENABLE_STATIC='On'",
"-DLIBCXXABI_ENABLE_STATIC_UNWINDER='On'",
"-DLIBCXXABI_USE_LLVM_UNWINDER='On'",
"-DLIBCXXABI_USE_COMPILER_RT='On'",
"-DLIBUNWIND_ENABLE_STATIC='On'",
"-DLIBUNWIND_ENABLE_SHARED='Off'",
"-DCOMPILER_RT_BUILD_CRT='On'",
"-DCOMPILER_RT_BUILD_SANITIZERS='Off'",
"-DCOMPILER_RT_BUILD_XRAY='Off'",
"-DCOMPILER_RT_BUILD_LIBFUZZER='Off'",
"-DCOMPILER_RT_BUILD_PROFILE='On'",
"-DCOMPILER_RT_BUILD_MEMPROF='Off'",
"-DCOMPILER_RT_BUILD_ORC='Off'",
"-DCOMPILER_RT_DEFAULT_TARGET_ARCH='x86_64'",
"-DLIBCLANG_BUILD_STATIC='On'",
"-DBUILD_SHARED_LIBS='Off'",
])
.args(crate::platforms::shared::SHARED_BUILD_OPTS)
.args(crate::platforms::shared::shared_build_opts_ccache(
ccache_variant,
));
if enable_coverage {
cmake_command.args([
"-DCOMPILER_RT_BUILD_CTX_PROFILE='Off'",
// Skip the link-based target probe; libc++ isn't built yet so
// the probe fails and silently disables `libclang_rt.profile.a`.
"-DCOMPILER_RT_DEFAULT_TARGET_ONLY='On'",
]);
}
crate::utils::command(&mut cmake_command, "LLVM host building cmake")?;
let mut crt_lib_directory = crt_target_directory.to_path_buf();
crt_lib_directory.push("lib/");
+7
View File
@@ -104,6 +104,13 @@ pub fn ninja(build_dir: &Path) -> anyhow::Result<()> {
if std::env::var("DRY_RUN").is_ok() {
ninja.arg("-n");
}
// Mirror cmake's native CMAKE_BUILD_PARALLEL_LEVEL so one env var
// throttles both this ninja call and the compiler-rt `cmake --build`.
if let Ok(jobs) = std::env::var("CMAKE_BUILD_PARALLEL_LEVEL") {
if !jobs.is_empty() {
ninja.args(["-j", &jobs]);
}
}
command(ninja.arg("install"), "Running ninja install")?;
Ok(())
}