Add support for lcov 2.0

lcov 2.0 deprecates `--rc lcov_branch_coverage=1` for `--rc branch_coverage=1` and
gives an error when an exclude is used on a non existing directory.

I added a version check for lcov and removed the subprojects directory from the
exclusion list if it does not exist.

Fixes #11995
pull/12347/head
Nigel Kukard 1 year ago committed by Eli Schwartz
parent 583d2815d1
commit 2c4a1b6324
  1. 2
      mesonbuild/backend/ninjabackend.py
  2. 22
      mesonbuild/environment.py
  3. 20
      mesonbuild/scripts/coverage.py

@ -640,7 +640,7 @@ class NinjaBackend(backends.Backend):
key = OptionKey('b_coverage')
if (key in self.environment.coredata.options and
self.environment.coredata.options[key].value):
gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, _ = environment.find_coverage_tools()
gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, _ = environment.find_coverage_tools()
if gcovr_exe or (lcov_exe and genhtml_exe):
self.add_build_comment(NinjaComment('Coverage rules'))
self.generate_coverage_rules(gcovr_exe, gcovr_version)

@ -96,6 +96,20 @@ def detect_gcovr(min_version: str = '3.3', log: bool = False):
return gcovr_exe, found
return None, None
def detect_lcov(log: bool = False):
lcov_exe = 'lcov'
try:
p, found = Popen_safe([lcov_exe, '--version'])[0:2]
except (FileNotFoundError, PermissionError):
# Doesn't exist in PATH or isn't executable
return None, None
found = search_version(found)
if p.returncode == 0 and found:
if log:
mlog.log('Found lcov-{} at {}'.format(found, quote_arg(shutil.which(lcov_exe))))
return lcov_exe, found
return None, None
def detect_llvm_cov():
tools = get_llvm_tool_names('llvm-cov')
for tool in tools:
@ -103,20 +117,18 @@ def detect_llvm_cov():
return tool
return None
def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]:
def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]:
gcovr_exe, gcovr_version = detect_gcovr()
llvm_cov_exe = detect_llvm_cov()
lcov_exe = 'lcov'
lcov_exe, lcov_version = detect_lcov()
genhtml_exe = 'genhtml'
if not mesonlib.exe_exists([lcov_exe, '--version']):
lcov_exe = None
if not mesonlib.exe_exists([genhtml_exe, '--version']):
genhtml_exe = None
return gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, llvm_cov_exe
return gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe
def detect_ninja(version: str = '1.8.2', log: bool = False) -> T.List[str]:
r = detect_ninja_command_and_version(version, log)

@ -22,7 +22,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
outfiles = []
exitcode = 0
(gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
(gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
# load config files for tools if available in the source tree
# - lcov requires manually specifying a per-project config
@ -35,6 +35,11 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
else:
lcov_config = []
if lcov_exe and mesonlib.version_compare(lcov_version, '>=2.0'):
lcov_exe_rc_branch_coverage = ['--rc', 'branch_coverage=1']
else:
lcov_exe_rc_branch_coverage = ['--rc', 'lcov_branch_coverage=1']
gcovr_config = ['-e', re.escape(subproject_root)]
# gcovr >= 4.2 requires a different syntax for out of source builds
@ -90,6 +95,9 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
initial_tracefile = covinfo + '.initial'
run_tracefile = covinfo + '.run'
raw_tracefile = covinfo + '.raw'
lcov_subpoject_exclude = []
if os.path.exists(subproject_root):
lcov_subpoject_exclude.append(os.path.join(subproject_root, '*'))
if use_llvm_cov:
# Create a shim to allow using llvm-cov as a gcov tool.
if mesonlib.is_windows():
@ -117,26 +125,26 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
'--capture',
'--output-file', run_tracefile,
'--no-checksum',
'--rc', 'lcov_branch_coverage=1'] +
*lcov_exe_rc_branch_coverage] +
lcov_config +
gcov_tool_args)
# Join initial and test results.
subprocess.check_call([lcov_exe,
'-a', initial_tracefile,
'-a', run_tracefile,
'--rc', 'lcov_branch_coverage=1',
*lcov_exe_rc_branch_coverage,
'-o', raw_tracefile] + lcov_config)
# Remove all directories outside the source_root from the covinfo
subprocess.check_call([lcov_exe,
'--extract', raw_tracefile,
os.path.join(source_root, '*'),
'--rc', 'lcov_branch_coverage=1',
*lcov_exe_rc_branch_coverage,
'--output-file', covinfo] + lcov_config)
# Remove all directories inside subproject dir
subprocess.check_call([lcov_exe,
'--remove', covinfo,
os.path.join(subproject_root, '*'),
'--rc', 'lcov_branch_coverage=1',
*lcov_subpoject_exclude,
*lcov_exe_rc_branch_coverage,
'--output-file', covinfo] + lcov_config)
subprocess.check_call([genhtml_exe,
'--prefix', build_root,

Loading…
Cancel
Save