Skip to content

Commit 361812c

Browse files
nkukardnirbheek
authored andcommitted
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 mesonbuild#11995
1 parent 2d01821 commit 361812c

File tree

3 files changed

+32
-12
lines changed

3 files changed

+32
-12
lines changed

mesonbuild/backend/ninjabackend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ def generate(self, capture: bool = False, vslite_ctx: dict = None) -> T.Optional
636636
key = OptionKey('b_coverage')
637637
if (key in self.environment.coredata.options and
638638
self.environment.coredata.options[key].value):
639-
gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, _ = environment.find_coverage_tools()
639+
gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, _ = environment.find_coverage_tools()
640640
if gcovr_exe or (lcov_exe and genhtml_exe):
641641
self.add_build_comment(NinjaComment('Coverage rules'))
642642
self.generate_coverage_rules(gcovr_exe, gcovr_version)

mesonbuild/environment.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,27 +96,39 @@ def detect_gcovr(min_version='3.3', log=False):
9696
return gcovr_exe, found
9797
return None, None
9898

99+
def detect_lcov(log: bool = False):
100+
lcov_exe = 'lcov'
101+
try:
102+
p, found = Popen_safe([lcov_exe, '--version'])[0:2]
103+
except (FileNotFoundError, PermissionError):
104+
# Doesn't exist in PATH or isn't executable
105+
return None, None
106+
found = search_version(found)
107+
if p.returncode == 0 and found:
108+
if log:
109+
mlog.log('Found lcov-{} at {}'.format(found, quote_arg(shutil.which(lcov_exe))))
110+
return lcov_exe, found
111+
return None, None
112+
99113
def detect_llvm_cov():
100114
tools = get_llvm_tool_names('llvm-cov')
101115
for tool in tools:
102116
if mesonlib.exe_exists([tool, '--version']):
103117
return tool
104118
return None
105119

106-
def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]:
120+
def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]:
107121
gcovr_exe, gcovr_version = detect_gcovr()
108122

109123
llvm_cov_exe = detect_llvm_cov()
110124

111-
lcov_exe = 'lcov'
125+
lcov_exe, lcov_version = detect_lcov()
112126
genhtml_exe = 'genhtml'
113127

114-
if not mesonlib.exe_exists([lcov_exe, '--version']):
115-
lcov_exe = None
116128
if not mesonlib.exe_exists([genhtml_exe, '--version']):
117129
genhtml_exe = None
118130

119-
return gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, llvm_cov_exe
131+
return gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe
120132

121133
def detect_ninja(version: str = '1.8.2', log: bool = False) -> T.List[str]:
122134
r = detect_ninja_command_and_version(version, log)

mesonbuild/scripts/coverage.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
2222
outfiles = []
2323
exitcode = 0
2424

25-
(gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
25+
(gcovr_exe, gcovr_version, lcov_exe, lcov_version, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
2626

2727
# load config files for tools if available in the source tree
2828
# - 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
3535
else:
3636
lcov_config = []
3737

38+
if lcov_exe and mesonlib.version_compare(lcov_version, '>=2.0'):
39+
lcov_exe_rc_branch_coverage = ['--rc', 'branch_coverage=1']
40+
else:
41+
lcov_exe_rc_branch_coverage = ['--rc', 'lcov_branch_coverage=1']
42+
3843
gcovr_config = ['-e', re.escape(subproject_root)]
3944

4045
# 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
9095
initial_tracefile = covinfo + '.initial'
9196
run_tracefile = covinfo + '.run'
9297
raw_tracefile = covinfo + '.raw'
98+
lcov_subpoject_exclude = []
99+
if os.path.exists(subproject_root):
100+
lcov_subpoject_exclude.append(os.path.join(subproject_root, '*'))
93101
if use_llvm_cov:
94102
# Create a shim to allow using llvm-cov as a gcov tool.
95103
if mesonlib.is_windows():
@@ -117,26 +125,26 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
117125
'--capture',
118126
'--output-file', run_tracefile,
119127
'--no-checksum',
120-
'--rc', 'lcov_branch_coverage=1'] +
128+
*lcov_exe_rc_branch_coverage] +
121129
lcov_config +
122130
gcov_tool_args)
123131
# Join initial and test results.
124132
subprocess.check_call([lcov_exe,
125133
'-a', initial_tracefile,
126134
'-a', run_tracefile,
127-
'--rc', 'lcov_branch_coverage=1',
135+
*lcov_exe_rc_branch_coverage,
128136
'-o', raw_tracefile] + lcov_config)
129137
# Remove all directories outside the source_root from the covinfo
130138
subprocess.check_call([lcov_exe,
131139
'--extract', raw_tracefile,
132140
os.path.join(source_root, '*'),
133-
'--rc', 'lcov_branch_coverage=1',
141+
*lcov_exe_rc_branch_coverage,
134142
'--output-file', covinfo] + lcov_config)
135143
# Remove all directories inside subproject dir
136144
subprocess.check_call([lcov_exe,
137145
'--remove', covinfo,
138-
os.path.join(subproject_root, '*'),
139-
'--rc', 'lcov_branch_coverage=1',
146+
*lcov_subpoject_exclude,
147+
*lcov_exe_rc_branch_coverage,
140148
'--output-file', covinfo] + lcov_config)
141149
subprocess.check_call([genhtml_exe,
142150
'--prefix', build_root,

0 commit comments

Comments
 (0)