xo-cmake: xo-cmake-config helper script + streamline coverage gen
This commit is contained in:
parent
c8ac0ceb49
commit
6a702ed88a
5 changed files with 319 additions and 5 deletions
|
|
@ -3,13 +3,26 @@ cmake_minimum_required(VERSION 3.10)
|
|||
project(xo_macros VERSION 1.0)
|
||||
|
||||
# if any are useful for this project..
|
||||
#include (cmake/foo.cmake)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# cmake export
|
||||
include (GNUInstallDirs)
|
||||
|
||||
set(XO_PROJECT_NAME xo_macros)
|
||||
|
||||
# LCOV_EXECUTABLE,GENHTML_EXECUTABLE: needed by xo-cmake-lcov-harness.in
|
||||
find_program(LCOV_EXECUTABLE NAMES lcov)
|
||||
find_program(GENHTML_EXECUTABLE NAMES genhtml)
|
||||
|
||||
configure_file(
|
||||
${PROJECT_SOURCE_DIR}/bin/xo-cmake-lcov-harness.in
|
||||
${PROJECT_BINARY_DIR}/xo-cmake-lcov-harness
|
||||
@ONLY
|
||||
)
|
||||
|
||||
configure_file(
|
||||
${PROJECT_SOURCE_DIR}/bin/xo-cmake-config.in
|
||||
${PROJECT_BINARY_DIR}/xo-cmake-config
|
||||
@ONLY
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"cmake/xo_macros/xo-project-macros.cmake"
|
||||
|
|
@ -18,3 +31,21 @@ install(
|
|||
PERMISSIONS OWNER_READ GROUP_READ WORLD_READ
|
||||
DESTINATION share/cmake/xo_macros
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/xo-cmake-lcov-harness"
|
||||
"${PROJECT_BINARY_DIR}/xo-cmake-config"
|
||||
PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# The cmake template gen-ccov.in should be expanded in downstream project;
|
||||
# to pickup downstream project's PROJECT_SOURCE_DIR / PROJECT_BINARY_DIR
|
||||
#
|
||||
install(
|
||||
FILES
|
||||
"share/xo-macros/gen-ccov.in"
|
||||
PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/xo-macros
|
||||
)
|
||||
|
|
|
|||
74
bin/xo-cmake-config.in
Executable file
74
bin/xo-cmake-config.in
Executable file
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
usage() {
|
||||
echo "$0 [-u|--usage|-h|--help|--lcov-exe|--genhtml-exe|--lcov-harness-exe|--gen-ccov-template|--cmake-module-path]" 1>&2
|
||||
}
|
||||
|
||||
help() {
|
||||
usage
|
||||
|
||||
cat <<EOF
|
||||
|
||||
display xo-cmake configuration variables
|
||||
|
||||
Options:
|
||||
-u | --usage brief help message
|
||||
--help this help message
|
||||
--lcov-exe report path to 'lcov' executable
|
||||
--genhtml-exe report path to 'genhtml' executable
|
||||
--lcov-harness-exe report path to 'xo-cmake-lcov-harness' executable
|
||||
--gen-ccov-template report path to 'gen-ccov.in' template
|
||||
--cmake-module-path report directory providing xo-cmake macros (will use/appear-in CMAKE_MODULE_PATH)
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# > 0 ]]; do
|
||||
case "$1" in
|
||||
-u | --usage)
|
||||
cmd='usage'
|
||||
;;
|
||||
-h | --help)
|
||||
cmd='help'
|
||||
;;
|
||||
--lcov-exe)
|
||||
cmd='lcov_exe'
|
||||
;;
|
||||
--genhtml-exe)
|
||||
cmd='genhtml_exe'
|
||||
;;
|
||||
--lcov-harness-exe)
|
||||
cmd='lcov_harness_exe'
|
||||
;;
|
||||
--gen-ccov-template)
|
||||
cmd='gen_ccov_template'
|
||||
;;
|
||||
--cmake-module-path)
|
||||
cmd='cmake_module_path'
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
shift
|
||||
done
|
||||
|
||||
if [[ $cmd == 'usage' ]]; then
|
||||
echo -n "usage: "
|
||||
usage
|
||||
elif [[ $cmd == 'help' ]]; then
|
||||
echo -n "help: "
|
||||
help
|
||||
elif [[ $cmd == 'lcov_exe' ]]; then
|
||||
echo -n @LCOV_EXECUTABLE@
|
||||
elif [[ $cmd == 'genhtml_exe' ]]; then
|
||||
echo -n @GENHTML_EXECUTABLE@
|
||||
elif [[ $cmd == 'lcov_harness_exe' ]]; then
|
||||
echo -n @CMAKE_INSTALL_FULL_BINDIR@/xo-cmake-lcov-harness
|
||||
elif [[ $cmd == 'gen_ccov_template' ]]; then
|
||||
echo -n @CMAKE_INSTALL_FULL_DATADIR@/xo-macros/gen-ccov.in
|
||||
elif [[ $cmd == 'cmake_module_path' ]]; then
|
||||
echo -n @CMAKE_MODULE_PATH@
|
||||
fi
|
||||
121
bin/xo-cmake-lcov-harness.in
Executable file
121
bin/xo-cmake-lcov-harness.in
Executable file
|
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
srcdir=$1
|
||||
builddir=$2
|
||||
outputstem=$3 # optional
|
||||
lcov=$4 # optional
|
||||
genhtml=$5 # optional
|
||||
|
||||
if [[ -z "${srcdir}" ]]; then
|
||||
echo "xo-cmake-lcov-harness: expected non-empty srcdir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${builddir}" ]]; then
|
||||
echo "xo-cmake-lcov-harness: expected non-empty builddir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z ${outputstem} ]]; then
|
||||
outputstem=$builddir/ccov/out
|
||||
fi
|
||||
|
||||
if [[ -z ${lcov} ]]; then
|
||||
lcov=@LCOV_EXECUTABLE@
|
||||
if [[ $lcov == "LCOV_EXECUTABLE-NOTFOUND" ]]; then
|
||||
echo "xo-cmake-lcov-harness: lcov executable not found during xo-cmake build/install"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z ${genhtml} ]]; then
|
||||
genhtml=@GENHTML_EXECUTABLE@
|
||||
if [[ $genhtml == "GENHTML_EXECUTABLE-NOTFOUND" ]]; then
|
||||
echo "xo-cmake-lcov-harness: genhtml executable not found during xo-cmake build/install"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p $builddir/ccov
|
||||
|
||||
# directory stems for location of {.gcda, gcno} coverage information,
|
||||
#
|
||||
# if we have source tree:
|
||||
#
|
||||
# ${srcdir}
|
||||
# +- foo
|
||||
# | \- foo.cpp
|
||||
# \- bar
|
||||
# \- quux
|
||||
# +- quux.cpp
|
||||
# \- quux_main.cpp
|
||||
#
|
||||
# then we expect build tree:
|
||||
#
|
||||
# ${builddir}
|
||||
# +- foo
|
||||
# | \- CMakeFiles
|
||||
# | \- foo_target.dir
|
||||
# | +- foo.cpp.gcda
|
||||
# | \- foo.cpp.gcno
|
||||
# +- bar
|
||||
# \- quux
|
||||
# \- CMakeFiles
|
||||
# \- target4quux.dir
|
||||
# +- quux.cpp.gcda
|
||||
# +- quux.cpp.gcno
|
||||
# +- quux_main.cpp.gcda
|
||||
# \- quux_main.cpp.gcno
|
||||
#
|
||||
# in which case will have cmd_body:
|
||||
#
|
||||
# ${primarydirs}
|
||||
# ./foo/CMakeFiles/foo_target.dir
|
||||
# ./bar/quux/CMakeFiles/target4quux.dir
|
||||
#
|
||||
# here foo_target, quux_target are whatever build is using for corresponding cmake target names.
|
||||
#
|
||||
# We want to invoke lcov like:
|
||||
#
|
||||
# lcov --capture \
|
||||
# --output ${builddir}/ccov \
|
||||
# --exclude /utest/ \
|
||||
# --base-directory ${srcdir}/foo --directory ${builddir}/foo/CMakeFiles/foo_target.dir \
|
||||
# --base-directory ${srcdir}/bar/quux --directory ${builddir}/bar/quux/CMakeFiles/target4quux.dir
|
||||
#
|
||||
primarydirs=$(cd ${builddir} && find -name '*.gcno' \
|
||||
| xargs --replace=xx dirname xx \
|
||||
| uniq \
|
||||
| sed -e 's:^\./::')
|
||||
|
||||
#echo "primarydirs=${primarydirs}"
|
||||
|
||||
cmd="${lcov} --output ${outputstem}.info --capture --ignore-errors source"
|
||||
|
||||
for bdir in ${primarydirs}; do
|
||||
sdir=$(dirname $(dirname ${bdir}))
|
||||
|
||||
cmd="${cmd} --base-directory ${srcdir}/${sdir} --directory ${builddir}/${bdir}"
|
||||
done
|
||||
|
||||
#echo cmd=${cmd}
|
||||
|
||||
set -x
|
||||
|
||||
# capture
|
||||
${cmd}
|
||||
|
||||
# keep only files with paths under source tree
|
||||
# (don't want coverage for external libraries such as libstdc++ etc)
|
||||
${lcov} --extract ${outputstem}.info "${srcdir}/*" --output ${outputstem}2.info
|
||||
|
||||
# remove unit test dirs
|
||||
# (we're interested in coverage of our installed code, not of the unit tests that exercise it)
|
||||
${lcov} --remove ${outputstem}2.info '*/utest/*' --output ${outputstem}3.info
|
||||
|
||||
# generate .html tree
|
||||
mkdir -p ${builddir}/ccov/html
|
||||
${genhtml} --ignore-errors source --show-details --prefix ${srcdir} --output-directory ${builddir}/ccov/html ${outputstem}3.info
|
||||
|
||||
# also send report to stdout
|
||||
${lcov} --list ${outputstem}3.info
|
||||
|
|
@ -1,5 +1,19 @@
|
|||
|
||||
macro(xo_cxx_config_message)
|
||||
message(STATUS "GUESSED_CMAKE_CMD=cmake -DXO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE} -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} -DCMAKE_MODULE_PATH=${CMAKE_MODULE_PATH} -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_DOCDIR=${CMAKE_INSTALL_DOCDIR} -B ${CMAKE_BINARY_DIR}")
|
||||
message(STATUS "XO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE}")
|
||||
message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
|
||||
endmacro()
|
||||
|
||||
macro(xo_cxx_bootstrap_message)
|
||||
if (NOT XO_SUBMODULE_BUILD)
|
||||
xo_cxx_config_message()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# deprecated -- prefer xo_cxx_toplevel_options2()
|
||||
macro(xo_cxx_toplevel_options)
|
||||
message(WARNING "deprecated: prefer xo_cxx_toplevel_options2")
|
||||
enable_language(CXX)
|
||||
xo_toplevel_compile_options()
|
||||
xo_toplevel_testing_options()
|
||||
|
|
@ -11,6 +25,50 @@ macro(xo_toplevel_testing_options)
|
|||
add_code_coverage_all_targets(EXCLUDE /nix/store* utest/*)
|
||||
endmacro()
|
||||
|
||||
macro(xo_cxx_toplevel_options2)
|
||||
enable_language(CXX)
|
||||
xo_toplevel_compile_options()
|
||||
enable_testing()
|
||||
endmacro()
|
||||
|
||||
# coverage build:
|
||||
# 0.
|
||||
# (cmake -DCMAKE_BUILD_TYPE=coverage ..)
|
||||
# 1. invoke instrumented executables for which you want coverage:
|
||||
# (cmake --build path/to/build -- test)
|
||||
# 2. post-process low-level coverage data
|
||||
# (path/to/build/gen-ccov)
|
||||
# 3. point browser to generated html data
|
||||
# file:///path/to/build/ccov/html/index.html
|
||||
#
|
||||
macro(xo_toplevel_coverage_config2)
|
||||
#find_program(LCOV_EXECUTABLE NAMES lcov)
|
||||
#find_program(GENHTML_EXECUTABLE NAMES genhtml)
|
||||
# see bin/xo-cmake-lcov-harness in this repo
|
||||
execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --lcov-harness-exe OUTPUT_VARIABLE XO_CMAKE_LCOV_HARNESS_EXECUTABLE)
|
||||
execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --gen-ccov-template OUTPUT_VARIABLE XO_CMAKE_GEN_CCOV_TEMPLATE)
|
||||
|
||||
if (NOT DEFINED PROJECT_CXX_FLAGS_COVERAGE)
|
||||
# note: for clang would use -fprofile-instr-generate -fcoverage-mapping here instead and also at link time
|
||||
set(PROJECT_CXX_FLAGS_COVERAGE -ggdb -Og -fprofile-arcs -ftest-coverage
|
||||
CACHE STRING "coverage c++ compiler flags")
|
||||
endif()
|
||||
message("-- PROJECT_CXX_FLAGS_COVERAGE: coverage c++ flags are [${PROJECT_CXX_FLAGS_COVERAGE}]")
|
||||
|
||||
add_compile_options("$<$<CONFIG:COVERAGE>:${PROJECT_CXX_FLAGS_COVERAGE}>")
|
||||
# when -DCMAKE_BUILD_TYPE=coverage, must also link executables with gcov
|
||||
link_libraries("$<$<CONFIG:COVERAGE>:gcov>")
|
||||
|
||||
if("${XO_CMAKE_GEN_CCOV_TEMPLATE}" STREQUAL "")
|
||||
message(ERROR "xo_toplevel_testing_config2: XO_CMAKE_GEN_CCOV_TEMPLATE not set")
|
||||
message(ERROR "see xo_toplevel_testing_options2()")
|
||||
else()
|
||||
message(DEBUG "XO_CMAKE_GEN_CCOV_TEMPLATE=${XO_CMAKE_GEN_CCOV_TEMPLATE}")
|
||||
configure_file(${XO_CMAKE_GEN_CCOV_TEMPLATE} ${PROJECT_BINARY_DIR}/gen-ccov @ONLY)
|
||||
file(CHMOD ${PROJECT_BINARY_DIR}/gen-ccov PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(xo_toplevel_compile_options)
|
||||
define_property(
|
||||
TARGET
|
||||
|
|
@ -557,7 +615,7 @@ macro(xo_dependency_helper target visibility dep)
|
|||
xo_dependency_helper1(${target} ${visibility} repo/${_nxo_dep}/include)
|
||||
endif()
|
||||
else()
|
||||
message("-- [${target}] find_package(${dep}) (xo_dependency_helper)")
|
||||
message(STATUS "[${target}] find_package(${dep}) (xo_dependency_helper)")
|
||||
find_package(${dep} CONFIG REQUIRED)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
30
share/xo-macros/gen-ccov.in
Normal file
30
share/xo-macros/gen-ccov.in
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
srcdir=@PROJECT_SOURCE_DIR@
|
||||
builddir=@PROJECT_BINARY_DIR@
|
||||
|
||||
#lcov=@LCOV_EXECUTABLE@
|
||||
#genhtml=@GENHTML_EXECUTABLE@
|
||||
#
|
||||
#if [[ $lcov == "LCOV_EXECUTABLE-NOTFOUND" ]]; then
|
||||
# echo "gen-ccov: lcov executable not found"
|
||||
# exit 1
|
||||
#fi
|
||||
#
|
||||
#if [[ $genhtml == "GENHTML_EXECUTABLE-NOTFOUND" ]]; then
|
||||
# echo "gen-ccov: genhtml executable not found"
|
||||
# exit 1
|
||||
#fi
|
||||
|
||||
lcovharness=@XO_CMAKE_LCOV_HARNESS_EXECUTABLE@
|
||||
|
||||
if [[ -z $lcovharness ]]; then
|
||||
echo "gen-ccov: lcov-harness executable (XO_CMAKE_LCOV_HARNESS_EXECUTABLE) not configured"
|
||||
echo "gen-ccov: expect value of path/to/xo-cmake-config --lcov-harness-exe"
|
||||
echo "gen-ccov: stored in XO_CMAKE_LCOV_HARNESS_EXECUTABLE by xo_toplevel_testing_options2()"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# TODO: allow providing LCOV_EXECUTABLE GENHTML_EXECUTABLE here
|
||||
|
||||
$lcovharness $srcdir $builddir
|
||||
Loading…
Add table
Add a link
Reference in a new issue