mirror of
https://github.com/Xahau/xahaud.git
synced 2026-06-03 08:46:36 +00:00
- CodeCoverageLLVM.cmake: BASE_DIRECTORY was parsed but never used (no analog to gcovr's -r in the llvm-cov commands we emit). dead arg. - xahau-ga-macos.yml.disabled: revert the conan_deps_cxxflags addition. the file is disabled so the edit was bit-rotting in unreachable code. whoever revives the macOS workflow can wire up the field then.
157 lines
6.4 KiB
CMake
157 lines
6.4 KiB
CMake
#[===================================================================[
|
|
Native LLVM source-based code coverage helper.
|
|
|
|
Drives the -fprofile-instr-generate / -fcoverage-mapping pipeline:
|
|
1. Run instrumented binary with LLVM_PROFILE_FILE=...%m-%p.profraw
|
|
2. llvm-profdata merge -sparse -> coverage.profdata
|
|
3. llvm-cov export/show/report -> final report
|
|
|
|
Output filename per coverage_format:
|
|
lcov -> coverage.lcov
|
|
json -> coverage.json
|
|
txt | text -> coverage.txt
|
|
html | html-details -> <NAME>/index.html
|
|
#]===================================================================]
|
|
|
|
include(CMakeParseArguments)
|
|
|
|
# Locate llvm-profdata / llvm-cov, preferring versioned variants matching the
|
|
# Clang we're building with so we don't accidentally pair clang-20 with
|
|
# llvm-cov-14 (profile format mismatch -> hard failure).
|
|
function(_find_llvm_cov_tools)
|
|
if(LLVM_PROFDATA_PATH AND LLVM_COV_PATH)
|
|
return()
|
|
endif()
|
|
|
|
string(REGEX MATCH "^[0-9]+" _major "${CMAKE_CXX_COMPILER_VERSION}")
|
|
|
|
set(_pd_names llvm-profdata)
|
|
set(_cov_names llvm-cov)
|
|
if(_major)
|
|
list(PREPEND _pd_names "llvm-profdata-${_major}")
|
|
list(PREPEND _cov_names "llvm-cov-${_major}")
|
|
endif()
|
|
|
|
# Only delegate to xcrun when the *compiler* is AppleClang. On macOS with
|
|
# Homebrew/system clang-N, xcrun would resolve to Xcode's llvm tools which
|
|
# could be a different version - exactly the mismatch we want to avoid.
|
|
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
|
|
execute_process(COMMAND xcrun -f llvm-profdata
|
|
OUTPUT_VARIABLE _pd_xcrun OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
ERROR_QUIET RESULT_VARIABLE _pd_rc)
|
|
if(_pd_rc EQUAL 0 AND _pd_xcrun)
|
|
set(LLVM_PROFDATA_PATH "${_pd_xcrun}" CACHE FILEPATH "llvm-profdata" FORCE)
|
|
endif()
|
|
execute_process(COMMAND xcrun -f llvm-cov
|
|
OUTPUT_VARIABLE _cov_xcrun OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
ERROR_QUIET RESULT_VARIABLE _cov_rc)
|
|
if(_cov_rc EQUAL 0 AND _cov_xcrun)
|
|
set(LLVM_COV_PATH "${_cov_xcrun}" CACHE FILEPATH "llvm-cov" FORCE)
|
|
endif()
|
|
endif()
|
|
|
|
if(NOT LLVM_PROFDATA_PATH)
|
|
find_program(LLVM_PROFDATA_PATH NAMES ${_pd_names})
|
|
endif()
|
|
if(NOT LLVM_COV_PATH)
|
|
find_program(LLVM_COV_PATH NAMES ${_cov_names})
|
|
endif()
|
|
endfunction()
|
|
|
|
function(setup_target_for_coverage_llvm)
|
|
set(oneValueArgs NAME FORMAT)
|
|
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
|
|
cmake_parse_arguments(Cov "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
|
|
|
_find_llvm_cov_tools()
|
|
if(NOT LLVM_PROFDATA_PATH)
|
|
message(FATAL_ERROR "llvm-profdata not found (needed for coverage_tool=llvm)")
|
|
endif()
|
|
if(NOT LLVM_COV_PATH)
|
|
message(FATAL_ERROR "llvm-cov not found (needed for coverage_tool=llvm)")
|
|
endif()
|
|
|
|
if(NOT Cov_FORMAT)
|
|
set(Cov_FORMAT lcov)
|
|
endif()
|
|
|
|
set(_profraw_dir "${PROJECT_BINARY_DIR}/${Cov_NAME}-profraw")
|
|
set(_profdata "${PROJECT_BINARY_DIR}/${Cov_NAME}.profdata")
|
|
|
|
# Resolve binary path: accept either an absolute path or a bare target name
|
|
# (resolved against PROJECT_BINARY_DIR). Splice the resolved path back into
|
|
# Cov_EXECUTABLE so the run command invokes it via absolute path - bare
|
|
# names aren't on PATH and the build dir isn't `.` either.
|
|
list(GET Cov_EXECUTABLE 0 _exec_name)
|
|
if(IS_ABSOLUTE "${_exec_name}")
|
|
set(_binary "${_exec_name}")
|
|
else()
|
|
set(_binary "${PROJECT_BINARY_DIR}/${_exec_name}")
|
|
list(REMOVE_AT Cov_EXECUTABLE 0)
|
|
list(PREPEND Cov_EXECUTABLE "${_binary}")
|
|
endif()
|
|
|
|
# llvm-cov takes a single -ignore-filename-regex; OR our excludes together.
|
|
set(_ignore_regex "")
|
|
foreach(EXC IN LISTS Cov_EXCLUDE)
|
|
if(_ignore_regex)
|
|
string(APPEND _ignore_regex "|")
|
|
endif()
|
|
string(APPEND _ignore_regex "${EXC}")
|
|
endforeach()
|
|
set(_filter "")
|
|
if(_ignore_regex)
|
|
set(_filter "-ignore-filename-regex='${_ignore_regex}'")
|
|
endif()
|
|
|
|
# Pick llvm-cov subcommand + output file for the requested format. Each
|
|
# branch builds a single shell command string that we'll hand to bash -c.
|
|
if(Cov_FORMAT STREQUAL "lcov")
|
|
set(_output "${PROJECT_BINARY_DIR}/coverage.lcov")
|
|
set(_report_sh "${LLVM_COV_PATH} export -instr-profile='${_profdata}' -format=lcov ${_filter} '${_binary}' > '${_output}'")
|
|
elseif(Cov_FORMAT STREQUAL "json")
|
|
set(_output "${PROJECT_BINARY_DIR}/coverage.json")
|
|
set(_report_sh "${LLVM_COV_PATH} export -instr-profile='${_profdata}' -format=text ${_filter} '${_binary}' > '${_output}'")
|
|
elseif(Cov_FORMAT STREQUAL "txt" OR Cov_FORMAT STREQUAL "text")
|
|
set(_output "${PROJECT_BINARY_DIR}/coverage.txt")
|
|
set(_report_sh "${LLVM_COV_PATH} report -instr-profile='${_profdata}' ${_filter} '${_binary}' > '${_output}'")
|
|
elseif(Cov_FORMAT STREQUAL "html" OR Cov_FORMAT STREQUAL "html-details")
|
|
set(_output "${PROJECT_BINARY_DIR}/${Cov_NAME}/index.html")
|
|
set(_report_sh "${LLVM_COV_PATH} show -instr-profile='${_profdata}' -format=html -output-dir='${PROJECT_BINARY_DIR}/${Cov_NAME}' ${_filter} '${_binary}'")
|
|
else()
|
|
message(FATAL_ERROR "coverage_tool=llvm: unsupported coverage_format '${Cov_FORMAT}' (use lcov|json|txt|html)")
|
|
endif()
|
|
|
|
set(_merge_sh "${LLVM_PROFDATA_PATH} merge -sparse -o '${_profdata}' '${_profraw_dir}'/*.profraw")
|
|
|
|
if(CODE_COVERAGE_VERBOSE)
|
|
message(STATUS "[coverage:llvm] binary: ${_binary}")
|
|
message(STATUS "[coverage:llvm] profraw: ${_profraw_dir}")
|
|
message(STATUS "[coverage:llvm] profdata: ${_profdata}")
|
|
message(STATUS "[coverage:llvm] format: ${Cov_FORMAT}")
|
|
message(STATUS "[coverage:llvm] output: ${_output}")
|
|
if(_ignore_regex)
|
|
message(STATUS "[coverage:llvm] ignore: ${_ignore_regex}")
|
|
endif()
|
|
message(STATUS "[coverage:llvm] merge: ${_merge_sh}")
|
|
message(STATUS "[coverage:llvm] report: ${_report_sh}")
|
|
endif()
|
|
|
|
# %m: hash of the binary, %p: pid. Wipe the dir up front so stale profraw
|
|
# files can't leak into a fresh merge.
|
|
add_custom_target(${Cov_NAME}
|
|
COMMAND ${CMAKE_COMMAND} -E rm -rf "${_profraw_dir}"
|
|
COMMAND ${CMAKE_COMMAND} -E make_directory "${_profraw_dir}"
|
|
COMMAND ${CMAKE_COMMAND} -E env
|
|
"LLVM_PROFILE_FILE=${_profraw_dir}/rippled-%m-%p.profraw"
|
|
${Cov_EXECUTABLE} ${Cov_EXECUTABLE_ARGS}
|
|
COMMAND bash -c "${_merge_sh}"
|
|
COMMAND bash -c "${_report_sh}"
|
|
BYPRODUCTS ${_output}
|
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
|
DEPENDS ${Cov_DEPENDENCIES}
|
|
VERBATIM
|
|
COMMENT "Running llvm-cov (${Cov_FORMAT}) -> ${_output}"
|
|
)
|
|
endfunction()
|