uniform scan-build detection process

Detect scan-build the same way when trying to launch it and when
generating the target.
The detection method is:
  1. look within SCANBUILD env variable
  2. shutil.which('scan-build')
  3. *on non-linux platforms only*: go through all the possible
     name candidates and test them individually.

The third step is added following this comment
https://github.com/mesonbuild/meson/pull/5857#issuecomment-528305788
However, going through a list of all the possible candidates is neither
easily maintainable nor performant, and is therefore skipped on
platforms that should not require such a step (currently, only Linux
platforms).

This is a follow-up to the issue raised by @lantw44 during PR:
https://github.com/mesonbuild/meson/pull/5857
pull/5924/head
Gabriel Ganne 5 years ago committed by Jussi Pakkanen
parent 9e04450eb6
commit e7197895b2
  1. 3
      mesonbuild/backend/ninjabackend.py
  2. 49
      mesonbuild/environment.py
  3. 40
      mesonbuild/scripts/scanbuild.py

@ -2646,8 +2646,7 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485'''))
self.create_target_alias('meson-dist')
def generate_scanbuild(self):
import shutil
if shutil.which('scan-build') is None:
if not environment.detect_scanbuild():
return
cmd = self.environment.get_build_command() + \
['--internal', 'scanbuild', self.environment.source_dir, self.environment.build_dir] + \

@ -163,6 +163,55 @@ def detect_ninja(version: str = '1.5', log: bool = False) -> str:
mlog.log('Found {}-{} at {}'.format(name, found, quote_arg(n)))
return n
def detect_scanbuild():
""" Look for scan-build binary on build platform
First, if a SCANBUILD env variable has been provided, give it precedence
on all platforms.
For most platforms, scan-build is found is the PATH contains a binary
named "scan-build". However, some distribution's package manager (FreeBSD)
don't. For those, loop through a list of candidates to see if one is
available.
Since this is a costly operation, limit it to the impacted platforms
(currently all non-linux platforms)
Return: a single-element list of the found scan-build binary ready to be
passed to Popen()
"""
exelist = []
if 'SCANBUILD' in os.environ:
exelist = split_args(os.environ['SCANBUILD'])
elif shutil.which('scan-build') is not None:
exelist = [shutil.which('scan-build')]
elif platform.system() != 'Linux':
tools = [
'scan-build', # base
'scan-build-8.0', 'scan-build80',
'scan-build-7.0', 'scan-build70',
'scan-build-6.0', 'scan-build60',
'scan-build-5.0', 'scan-build50',
'scan-build-4.0', 'scan-build40',
'scan-build-3.9', 'scan-build39',
'scan-build-3.8', 'scan-build38',
'scan-build-3.7', 'scan-build37',
'scan-build-3.6', 'scan-build36',
'scan-build-3.5', 'scan-build35',
'scan-build-9.0', 'scan-build-devel', # development snapshot
]
for tool in tools:
if shutil.which(tool) is not None:
exelist = [shutil.which(tool)]
break
if exelist:
tool = exelist[0]
if os.path.isfile(tool) and os.access(tool, os.X_OK):
return [tool]
return []
def detect_native_windows_arch():
"""
The architecture of Windows itself: x86, amd64 or arm64

@ -16,9 +16,10 @@ import os
import subprocess
import shutil
import tempfile
from ..environment import detect_ninja
from ..environment import detect_ninja, detect_scanbuild
from ..mesonlib import Popen_safe, split_args
def scanbuild(exelist, srcdir, blddir, privdir, logdir, args):
with tempfile.TemporaryDirectory(dir=privdir) as scandir:
meson_cmd = exelist + args
@ -28,6 +29,7 @@ def scanbuild(exelist, srcdir, blddir, privdir, logdir, args):
return rc
return subprocess.call(build_cmd)
def run(args):
srcdir = args[0]
blddir = args[1]
@ -35,40 +37,10 @@ def run(args):
privdir = os.path.join(blddir, 'meson-private')
logdir = os.path.join(blddir, 'meson-logs/scanbuild')
shutil.rmtree(logdir, ignore_errors=True)
tools = [
'scan-build', # base
'scan-build-8.0', 'scan-build80',
'scan-build-7.0', 'scan-build70',
'scan-build-6.0', 'scan-build60',
'scan-build-5.0', 'scan-build50',
'scan-build-4.0', 'scan-build40',
'scan-build-3.9', 'scan-build39',
'scan-build-3.8', 'scan-build38',
'scan-build-3.7', 'scan-build37',
'scan-build-3.6', 'scan-build36',
'scan-build-3.5', 'scan-build35',
'scan-build-9.0', 'scan-build-devel', # development snapshot
]
toolname = 'scan-build'
for tool in tools:
try:
p, out = Popen_safe([tool, '--help'])[:2]
except (FileNotFoundError, PermissionError):
continue
if p.returncode != 0:
continue
else:
toolname = tool
break
if 'SCANBUILD' in os.environ:
exelist = split_args(os.environ['SCANBUILD'])
else:
exelist = [toolname]
try:
Popen_safe(exelist + ['--help'])
except OSError:
exelist = detect_scanbuild()
if not exelist:
print('Could not execute scan-build "%s"' % ' '.join(exelist))
return 1
return scanbuild(exelist, srcdir, blddir, privdir, logdir, meson_cmd)

Loading…
Cancel
Save