Hello all,
I am learning CMake by making a sample C++ project, and I have succesfully integrated it with CDash, with both tests (using boost unit test) and coverage (using --coverage and gcov). I am using this CTest
Script to submit to CDash:
set(CTEST_SOURCE_DIRECTORY ${CTEST_SCRIPT_DIRECTORY}/src)
set(CTEST_BINARY_DIRECTORY ${CTEST_SCRIPT_DIRECTORY}/bin)
include(${CTEST_SOURCE_DIRECTORY}/CTestConfig.cmake)
set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
set(CTEST_COVERAGE_COMMAND gcov)
ctest_empty_binary_directory(${CTEST_BINARY_DIRECTORY})
ctest_start(Experimental)
ctest_configure()
ctest_build()
ctest_test()
ctest_coverage()
ctest_submit()
gcc coverage flags are not written in the above script because CMakeLists.txt contains coverage flags by default, as this is a sample project
However, I would like to exclude specific lines in each source file using GCOV_EXCL_LINE, GCOV_EXCL_START, and GCOV_EXCL_STOP, which is not happening with gcov.
I have looked at alternatives and found lcov, which takes the files generated by gcov and converts it into a .info file, which is then converted into a coverage report with genhtml. It is successfully excluding lines with GCOV_EXCL_LINE in the generated html file, but when I replace it with CTEST_COVERAGE_COMMAND in the script (in hopes of integrating it with CDash, instead of a html coverage report), it is throwing some errors, probably because it is not intended to use in such a manner. this is an output from ctest -VV -S run_experimental.cmake
:
.lcov -o /path/to/testThis.dir /path/to/testThis.dir/this.cpp.gcda
lcov: Need one of options -z, -c, -a, -e, -r, -l, --diff or --summary
Use lcov --help to get usage information
Coverage command returned: 2 while processing: /path/to/testThis.dir/this.cpp.gcda
Command produced error: 0
Another way I tried to fix this thing is to use a wrapper around gcov which will exclude all required lines in the files generated by gcov.
Add this line to ctest script:
set(CTEST_COVERAGE_COMMAND ${CTEST_SCRIPT_DIRECTORY}/gcovw)
This is gcovw:
#!/usr/bin/env python3
import re, subprocess, sys
if len(sys.argv) < 2:
exit(1)
else:
process = subprocess.Popen(
['/usr/bin/gcov'] + sys.argv[1:],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
out,err = process.communicate()
process.wait()
out,err = out.decode(),err.decode()
if (process.returncode != 0) or (err != ''):
print(out, end='')
print(err, end='', file=sys.stderr)
exit(process.returncode or 1)
else:
files = [x.group(1) for x in re.finditer('^Creating \'([^\']*)\'$', out, flags=re.MULTILINE)]
regex = re.compile(r'^[^:]*:(.*[GL]COVR?_EXCL_LINE.*)$', flags=re.MULTILINE)
for _file in files:
fp = open(_file, 'r')
data = fp.read()
data = regex.sub(' -:\g<1>', data)
fp.close()
fp = open(_file, 'w')
fp.write(data)
fp.close()
print(out, end='')
Although it works, I think this is a bit hacky, and I want a more elegant solution:
- Enable GCOV_EXCL_LINE in gcov (if it’s possible)
- Some other tool which can do this (needs to exclude GCOV_EXCL_LINE and should be able to show the coverage on cdash)
Could you show me how?