coverage generator: obey the documentation and only generate supported outputs

We say:

> If version 4.2 or higher of the first is found, targets coverage-text,
> coverage-xml, coverage-sonarqube and coverage-html are generated.

But this is totally untrue. Make it true, by actually checking (and
not generating broken coverage commands when older versions of gcovr are
found).

Fixes #9505
pull/9506/head
Eli Schwartz 3 years ago
parent 86df7dd627
commit 0f0b1f22d2
No known key found for this signature in database
GPG Key ID: CEB167EFB5722BD6
  1. 60
      mesonbuild/backend/ninjabackend.py
  2. 8
      mesonbuild/environment.py
  3. 12
      mesonbuild/scripts/coverage.py

@ -559,8 +559,14 @@ class NinjaBackend(backends.Backend):
key = OptionKey('b_coverage')
if (key in self.environment.coredata.options and
self.environment.coredata.options[key].value):
self.add_build_comment(NinjaComment('Coverage rules'))
self.generate_coverage_rules()
gcovr_exe, gcovr_version, lcov_exe, 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)
else:
# FIXME: since we explicitly opted in, should this be an error?
# The docs just say these targets will be created "if possible".
mlog.warning('Need gcovr or lcov/genhtml to generate any coverage reports')
self.add_build_comment(NinjaComment('Suffix'))
self.generate_utils()
self.generate_ending()
@ -1070,37 +1076,16 @@ class NinjaBackend(backends.Backend):
self.environment.get_log_dir()] +
(['--use_llvm_cov'] if use_llvm_cov else []))
def generate_coverage_rules(self):
def generate_coverage_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]):
e = NinjaBuildElement(self.all_outputs, 'meson-coverage', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, [])
e.add_item('description', 'Generates coverage reports')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage')
self.generate_coverage_legacy_rules()
def generate_coverage_legacy_rules(self):
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--xml'])
e.add_item('description', 'Generates XML coverage report')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-xml')
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-sonarqube', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--sonarqube'])
e.add_item('description', 'Generates Sonarqube XML coverage report')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-sonarqube')
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--text'])
e.add_item('description', 'Generates text coverage report')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-text')
self.generate_coverage_legacy_rules(gcovr_exe, gcovr_version)
def generate_coverage_legacy_rules(self, gcovr_exe: T.Optional[str], gcovr_version: T.Optional[str]):
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-html', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--html'])
e.add_item('description', 'Generates HTML coverage report')
@ -1108,6 +1093,29 @@ class NinjaBackend(backends.Backend):
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-html')
if gcovr_exe:
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-xml', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--xml'])
e.add_item('description', 'Generates XML coverage report')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-xml')
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-text', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--text'])
e.add_item('description', 'Generates text coverage report')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-text')
if mesonlib.version_compare(gcovr_version, '>=4.2'):
e = NinjaBuildElement(self.all_outputs, 'meson-coverage-sonarqube', 'CUSTOM_COMMAND', 'PHONY')
self.generate_coverage_command(e, ['--sonarqube'])
e.add_item('description', 'Generates Sonarqube XML coverage report')
self.add_build(e)
# Alias that runs the target defined above
self.create_target_alias('meson-coverage-sonarqube')
def generate_install(self):
self.create_install_data_files()
elem = NinjaBuildElement(self.all_outputs, 'meson-install', 'CUSTOM_COMMAND', 'PHONY')

@ -84,7 +84,7 @@ def _get_env_var(for_machine: MachineChoice, is_cross: bool, var_name: str) -> T
return value
def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
def detect_gcovr(min_version='3.3', log=False):
gcovr_exe = 'gcovr'
try:
p, found = Popen_safe([gcovr_exe, '--version'])[0:2]
@ -95,7 +95,7 @@ def detect_gcovr(min_version='3.3', new_rootdir_version='4.2', log=False):
if p.returncode == 0 and mesonlib.version_compare(found, '>=' + min_version):
if log:
mlog.log('Found gcovr-{} at {}'.format(found, quote_arg(shutil.which(gcovr_exe))))
return gcovr_exe, mesonlib.version_compare(found, '>=' + new_rootdir_version)
return gcovr_exe, found
return None, None
def detect_llvm_cov():
@ -106,7 +106,7 @@ def detect_llvm_cov():
return None
def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str], T.Optional[str]]:
gcovr_exe, gcovr_new_rootdir = detect_gcovr()
gcovr_exe, gcovr_version = detect_gcovr()
llvm_cov_exe = detect_llvm_cov()
@ -118,7 +118,7 @@ def find_coverage_tools() -> T.Tuple[T.Optional[str], T.Optional[str], T.Optiona
if not mesonlib.exe_exists([genhtml_exe, '--version']):
genhtml_exe = None
return gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe, llvm_cov_exe
return gcovr_exe, gcovr_version, lcov_exe, 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)

@ -21,10 +21,10 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
outfiles = []
exitcode = 0
(gcovr_exe, gcovr_new_rootdir, lcov_exe, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
(gcovr_exe, gcovr_version, lcov_exe, genhtml_exe, llvm_cov_exe) = environment.find_coverage_tools()
# gcovr >= 4.2 requires a different syntax for out of source builds
if gcovr_new_rootdir:
if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=4.2'):
gcovr_base_cmd = [gcovr_exe, '-r', source_root, build_root]
else:
gcovr_base_cmd = [gcovr_exe, '-r', build_root]
@ -35,7 +35,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
gcov_exe_args = []
if not outputs or 'xml' in outputs:
if gcovr_exe:
if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
subprocess.check_call(gcovr_base_cmd +
['-x',
'-e', re.escape(subproject_root),
@ -47,7 +47,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
exitcode = 1
if not outputs or 'sonarqube' in outputs:
if gcovr_exe:
if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=4.2'):
subprocess.check_call(gcovr_base_cmd +
['--sonarqube',
'-o', os.path.join(log_dir, 'sonarqube.xml'),
@ -59,7 +59,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
exitcode = 1
if not outputs or 'text' in outputs:
if gcovr_exe:
if gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
subprocess.check_call(gcovr_base_cmd +
['-e', re.escape(subproject_root),
'-o', os.path.join(log_dir, 'coverage.txt')
@ -132,7 +132,7 @@ def coverage(outputs: T.List[str], source_root: str, subproject_root: str, build
'--branch-coverage',
covinfo])
outfiles.append(('Html', pathlib.Path(htmloutdir, 'index.html')))
elif gcovr_exe:
elif gcovr_exe and mesonlib.version_compare(gcovr_version, '>=3.3'):
htmloutdir = os.path.join(log_dir, 'coveragereport')
if not os.path.isdir(htmloutdir):
os.mkdir(htmloutdir)

Loading…
Cancel
Save