[CMake] Add targets for generating coverage reports

This is a pretty small bit of CMake goop to generate code coverage
reports. I always forget the right script invocation and end up
fumbling around too much.

Wouldn't it be great to have targets that "Just Work"?

Well, I thought so.

At present this only really works correctly for LLVM, but I'll extend
it in subsequent patches to work for subprojects.

Reviewed By: phosek

Differential Revision: https://reviews.llvm.org/D109019
This commit is contained in:
Chris Bieneman 2021-08-31 12:20:16 -07:00
parent 2982bd9e9b
commit 2856719d74
3 changed files with 82 additions and 1 deletions

View File

@ -1152,6 +1152,7 @@ endif()
# after all targets are created.
llvm_distribution_add_targets()
process_llvm_pass_plugins(GEN_CONFIG)
include(CoverageReport)
# This allows us to deploy the Universal CRT DLLs by passing -DCMAKE_INSTALL_UCRT_LIBRARIES=ON to CMake
if (MSVC AND CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows" AND CMAKE_INSTALL_UCRT_LIBRARIES)

View File

@ -0,0 +1,64 @@
# if coverage reports are not enabled, skip all of this
if(NOT LLVM_BUILD_INSTRUMENTED_COVERAGE)
return()
endif()
file(TO_NATIVE_PATH
"${LLVM_SOURCE_DIR}/utils/prepare-code-coverage-artifact.py"
PREPARE_CODE_COV_ARTIFACT)
# llvm-cov and llvm-profdata need to match the host compiler. They can either be
# explicitly provided by the user, or we will look them up based on the install
# location of the C++ compiler.
get_filename_component(COMPILER_DIRECTORY ${CMAKE_CXX_COMPILER} DIRECTORY)
find_program(LLVM_COV "llvm-cov" ${COMPILER_DIRECTORY} NO_DEFAULT_PATH)
find_program(LLVM_PROFDATA "llvm-profdata" ${COMPILER_DIRECTORY} NO_DEFAULT_PATH)
if(NOT LLVM_COV OR NOT LLVM_PROFDATA)
message(WARNING "Could not find code coverage tools, skipping generating targets. You may explicitly specify LLVM_COV and LLVM_PROFDATA to work around this warning.")
return()
endif()
set(LLVM_CODE_COVERAGE_TARGETS "" CACHE STRING "Targets to run code coverage on (defaults to all exported targets if empty)")
mark_as_advanced(LLVM_CODE_COVERAGE_TARGETS)
if(NOT LLVM_CODE_COVERAGE_TARGETS)
# by default run the coverage report across all the exports provided
get_property(COV_TARGETS GLOBAL PROPERTY LLVM_EXPORTS)
endif()
file(TO_NATIVE_PATH
"${CMAKE_BINARY_DIR}/report/"
REPORT_DIR)
foreach(target ${LLVM_CODE_COVERAGE_TARGETS} ${COV_TARGETS})
get_target_property(target_type ${target} TYPE)
if("${target_type}" STREQUAL "SHARED_LIBRARY" OR "${target_type}" STREQUAL "EXECUTABLE")
list(APPEND coverage_binaries $<TARGET_FILE:${target}>)
endif()
endforeach()
set(LLVM_COVERAGE_SOURCE_DIRS "" CACHE STRING "Source directories to restrict coverage reports to.")
mark_as_advanced(LLVM_COVERAGE_SOURCE_DIRS)
foreach(dir ${LLVM_COVERAGE_SOURCE_DIRS})
list(APPEND restrict_flags -restrict ${dir})
endforeach()
# Utility target to clear out profile data.
# This isn't connected to any dependencies because it is a bit finacky to get
# working exactly how a user might want.
add_custom_target(clear-profile-data
COMMAND ${CMAKE_COMMAND} -E
remove_directory ${LLVM_PROFILE_DATA_DIR})
# This currently only works for LLVM, but could be expanded to work for all
# sub-projects. The current limitation is based on not having a good way to
# automaticall plumb through the targets that we want to run coverage against.
add_custom_target(generate-coverage-report
COMMAND ${Python3_EXECUTABLE} ${PREPARE_CODE_COV_ARTIFACT}
${LLVM_PROFDATA} ${LLVM_COV} ${LLVM_PROFILE_DATA_DIR}
${REPORT_DIR} ${coverage_binaries}
--unified-report ${restrict_flags}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS check-llvm) # Run tests

View File

@ -310,7 +310,23 @@ enabled sub-projects. Nearly all of these variable names begin with
**LLVM_BUILD_INSTRUMENTED_COVERAGE**:BOOL
If enabled, `source-based code coverage
<https://clang.llvm.org/docs/SourceBasedCodeCoverage.html>`_ instrumentation
is enabled while building llvm.
is enabled while building llvm. If CMake can locate the code coverage
scripts and the llvm-cov and llvm-profdata tools that pair to your compiler,
the build will also generate the `generate-coverage-report` target to generate
the code coverage report for LLVM, and the `clear-profile-data` utility target
to delete captured profile data. See documentation for
*LLVM_CODE_COVERAGE_TARGETS* and *LLVM_COVERAGE_SOURCE_DIRS* for more
information on configuring code coverage reports.
**LLVM_CODE_COVERAGE_TARGETS**:STRING
If set to a semicolon separated list of targets, those targets will be used
to drive the code coverage reports. If unset, the target list will be
constructed using the LLVM build's CMake export list.
**LLVM_COVERAGE_SOURCE_DIRS**:STRING
If set to a semicolon separated list of directories, the coverage reports
will limit code coverage summaries to just the listed directories. If unset,
coverage reports will include all sources identified by the tooling.
**LLVM_BUILD_LLVM_DYLIB**:BOOL
If enabled, the target for building the libLLVM shared library is added.