Consolidate reporting result of a dependency check

If successful, we should identify the method which was successful
If successful, we should report the version found (if known)
If failing, we should identify the methods we tried

Some dependency detectors which had no reporting now gain it

There's all kinds of complexities, inconsistencies and special cases hidden
in the existing behaviour, e.g.:

- boost reports modules requested, and BOOST_ROOT (if set)
- gtest/gmock report if they are a prebuilt library or header only
- mpi reports the language
- qt reports modules requested, and the config tool used or tried
- configtool reports the config tool used
- llvm reports if missing modules are optional (one per line)

We add some simple hooks to allow the dependency object to expose the
currently reported information into the consolidated reporting

Note that PkgConfigDependency() takes a silent: keyword which is used
internallly to suppress reporting.  This behaviour isn't needed in
find_external_dependency().
pull/3657/head
Jon Turney 7 years ago
parent 3576623b0f
commit f2673d9b57
No known key found for this signature in database
GPG Key ID: C7C86F0370285C81
  1. 97
      mesonbuild/dependencies/base.py
  2. 20
      mesonbuild/dependencies/boost.py
  3. 39
      mesonbuild/dependencies/dev.py
  4. 13
      mesonbuild/dependencies/misc.py
  5. 26
      mesonbuild/dependencies/ui.py

@ -266,6 +266,15 @@ class ExternalDependency(Dependency):
return new return new
def log_details(self):
return ''
def log_info(self):
return ''
def log_tried(self):
return ''
class NotFoundDependency(Dependency): class NotFoundDependency(Dependency):
def __init__(self, environment): def __init__(self, environment):
@ -391,11 +400,9 @@ class ConfigToolDependency(ExternalDependency):
else: else:
mlog.log('Found', mlog.bold(self.tool_name), repr(req_version), mlog.log('Found', mlog.bold(self.tool_name), repr(req_version),
mlog.red('NO')) mlog.red('NO'))
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
return False return False
mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)), mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)),
'({})'.format(version)) '({})'.format(version))
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
return True return True
def get_config_value(self, args, stage): def get_config_value(self, args, stage):
@ -423,6 +430,9 @@ class ConfigToolDependency(ExternalDependency):
mlog.debug('Got config-tool variable {} : {}'.format(variable_name, variable)) mlog.debug('Got config-tool variable {} : {}'.format(variable_name, variable))
return variable return variable
def log_tried(self):
return self.type_name
class PkgConfigDependency(ExternalDependency): class PkgConfigDependency(ExternalDependency):
# The class's copy of the pkg-config path. Avoids having to search for it # The class's copy of the pkg-config path. Avoids having to search for it
@ -464,17 +474,12 @@ class PkgConfigDependency(ExternalDependency):
if self.required: if self.required:
raise DependencyException('Pkg-config not found.') raise DependencyException('Pkg-config not found.')
return return
if self.want_cross:
self.type_string = 'Cross'
else:
self.type_string = 'Native'
mlog.debug('Determining dependency {!r} with pkg-config executable ' mlog.debug('Determining dependency {!r} with pkg-config executable '
'{!r}'.format(name, self.pkgbin.get_path())) '{!r}'.format(name, self.pkgbin.get_path()))
ret, self.version = self._call_pkgbin(['--modversion', name]) ret, self.version = self._call_pkgbin(['--modversion', name])
if ret != 0: if ret != 0:
return return
found_msg = [self.type_string + ' dependency', mlog.bold(name), 'found:']
if self.version_reqs is None: if self.version_reqs is None:
self.is_found = True self.is_found = True
else: else:
@ -485,14 +490,6 @@ class PkgConfigDependency(ExternalDependency):
(self.is_found, not_found, found) = \ (self.is_found, not_found, found) = \
version_compare_many(self.version, self.version_reqs) version_compare_many(self.version, self.version_reqs)
if not self.is_found: if not self.is_found:
found_msg += [mlog.red('NO'),
'found {!r} but need:'.format(self.version),
', '.join(["'{}'".format(e) for e in not_found])]
if found:
found_msg += ['; matched:',
', '.join(["'{}'".format(e) for e in found])]
if not self.silent:
mlog.log(*found_msg)
if self.required: if self.required:
m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
raise DependencyException(m.format(name, not_found, self.version)) raise DependencyException(m.format(name, not_found, self.version))
@ -503,7 +500,6 @@ class PkgConfigDependency(ExternalDependency):
self._set_cargs() self._set_cargs()
# Fetch the libraries and library paths needed for using this # Fetch the libraries and library paths needed for using this
self._set_libs() self._set_libs()
found_msg += [mlog.green('YES'), self.version]
except DependencyException as e: except DependencyException as e:
if self.required: if self.required:
raise raise
@ -511,12 +507,7 @@ class PkgConfigDependency(ExternalDependency):
self.compile_args = [] self.compile_args = []
self.link_args = [] self.link_args = []
self.is_found = False self.is_found = False
found_msg += [mlog.red('NO'), '; reason: {}'.format(str(e))] self.reason = e
# Print the found message only at the very end because fetching cflags
# and libs can also fail if other needed pkg-config files aren't found.
if not self.silent:
mlog.log(*found_msg)
def __repr__(self): def __repr__(self):
s = '<{0} {1}: {2} {3}>' s = '<{0} {1}: {2} {3}>'
@ -705,8 +696,8 @@ class PkgConfigDependency(ExternalDependency):
variable = '' variable = ''
if ret != 0: if ret != 0:
if self.required: if self.required:
raise DependencyException('%s dependency %s not found.' % raise DependencyException('dependency %s not found.' %
(self.type_string, self.name)) (self.name))
else: else:
variable = out.strip() variable = out.strip()
@ -790,6 +781,9 @@ class PkgConfigDependency(ExternalDependency):
# a path rather than the raw dlname # a path rather than the raw dlname
return os.path.basename(dlname) return os.path.basename(dlname)
def log_tried(self):
return self.type_name
class DubDependency(ExternalDependency): class DubDependency(ExternalDependency):
class_dubbin = None class_dubbin = None
@ -811,7 +805,6 @@ class DubDependency(ExternalDependency):
if self.required: if self.required:
raise DependencyException('DUB not found.') raise DependencyException('DUB not found.')
self.is_found = False self.is_found = False
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return return
mlog.debug('Determining dependency {!r} with DUB executable ' mlog.debug('Determining dependency {!r} with DUB executable '
@ -822,7 +815,6 @@ class DubDependency(ExternalDependency):
if ret != 0: if ret != 0:
self.is_found = False self.is_found = False
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return return
j = json.loads(res) j = json.loads(res)
@ -834,7 +826,6 @@ class DubDependency(ExternalDependency):
msg += [mlog.bold(j['compiler']), 'and we are using', mlog.bold(comp)] msg += [mlog.bold(j['compiler']), 'and we are using', mlog.bold(comp)]
mlog.error(*msg) mlog.error(*msg)
self.is_found = False self.is_found = False
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return return
self.version = package['version'] self.version = package['version']
@ -842,7 +833,6 @@ class DubDependency(ExternalDependency):
break break
# Check if package version meets the requirements # Check if package version meets the requirements
found_msg = ['Dependency', mlog.bold(name), 'found:']
if self.version_reqs is None: if self.version_reqs is None:
self.is_found = True self.is_found = True
else: else:
@ -853,21 +843,11 @@ class DubDependency(ExternalDependency):
(self.is_found, not_found, found) = \ (self.is_found, not_found, found) = \
version_compare_many(self.version, self.version_reqs) version_compare_many(self.version, self.version_reqs)
if not self.is_found: if not self.is_found:
found_msg += [mlog.red('NO'),
'found {!r} but need:'.format(self.version),
', '.join(["'{}'".format(e) for e in not_found])]
if found:
found_msg += ['; matched:',
', '.join(["'{}'".format(e) for e in found])]
if not self.silent:
mlog.log(*found_msg)
if self.required: if self.required:
m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' m = 'Invalid version of dependency, need {!r} {!r} found {!r}.'
raise DependencyException(m.format(name, not_found, self.version)) raise DependencyException(m.format(name, not_found, self.version))
return return
found_msg += [mlog.green('YES'), self.version]
if self.pkg['targetFileName'].endswith('.a'): if self.pkg['targetFileName'].endswith('.a'):
self.static = True self.static = True
@ -889,12 +869,8 @@ class DubDependency(ExternalDependency):
if not found: if not found:
self.is_found = False self.is_found = False
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return return
if not self.silent:
mlog.log(*found_msg)
def get_compiler(self): def get_compiler(self):
return self.compiler return self.compiler
@ -1216,10 +1192,6 @@ class ExtraFrameworkDependency(ExternalDependency):
if self.found(): if self.found():
self.compile_args = ['-I' + os.path.join(self.path, self.name, 'Headers')] self.compile_args = ['-I' + os.path.join(self.path, self.name, 'Headers')]
self.link_args = ['-F' + self.path, '-framework', self.name.split('.')[0]] self.link_args = ['-F' + self.path, '-framework', self.name.split('.')[0]]
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.green('YES'),
os.path.join(self.path, self.name))
else:
mlog.log('Dependency', name, 'found:', mlog.red('NO'))
def detect(self, name, path): def detect(self, name, path):
lname = name.lower() lname = name.lower()
@ -1242,6 +1214,12 @@ class ExtraFrameworkDependency(ExternalDependency):
def get_version(self): def get_version(self):
return 'unknown' return 'unknown'
def log_info(self):
return os.path.join(self.path, self.name)
def log_tried(self):
return 'framework'
def get_dep_identifier(name, kwargs, want_cross): def get_dep_identifier(name, kwargs, want_cross):
# Need immutable objects since the identifier will be used as a dict key # Need immutable objects since the identifier will be used as a dict key
@ -1277,6 +1255,8 @@ def find_external_dependency(name, env, kwargs):
pkg_exc = None pkg_exc = None
pkgdep = [] pkgdep = []
details = ''
for c in candidates: for c in candidates:
# try this dependency method # try this dependency method
try: try:
@ -1288,11 +1268,33 @@ def find_external_dependency(name, env, kwargs):
if not pkg_exc: if not pkg_exc:
pkg_exc = e pkg_exc = e
else: else:
details = d.log_details()
if details:
details = '(' + details + ') '
if 'language' in kwargs:
details += 'for ' + d.language + ' '
# if the dependency was found # if the dependency was found
if d.found(): if d.found():
info = d.log_info()
if info:
info = ', ' + info
mlog.log('Dependency', mlog.bold(name), details + 'found:', mlog.green('YES'), d.version + info)
return d return d
# otherwise, the dependency could not be found # otherwise, the dependency could not be found
tried_methods = [d.log_tried() for d in pkgdep if d.log_tried()]
if tried_methods:
tried = '{}'.format(mlog.format_list(tried_methods))
else:
tried = ''
mlog.log('Dependency', mlog.bold(name), details + 'found:', mlog.red('NO'),
'(tried {})'.format(tried) if tried else '')
if required: if required:
# if exception(s) occurred, re-raise the first one (on the grounds that # if exception(s) occurred, re-raise the first one (on the grounds that
# it came from a preferred dependency detection method) # it came from a preferred dependency detection method)
@ -1301,8 +1303,7 @@ def find_external_dependency(name, env, kwargs):
# we have a list of failed ExternalDependency objects, so we can report # we have a list of failed ExternalDependency objects, so we can report
# the methods we tried to find the dependency # the methods we tried to find the dependency
tried_methods = ','.join([d.type_name for d in pkgdep]) raise DependencyException('Dependency "%s" not found, tried %s' % (name, tried))
raise DependencyException('Dependency "%s" not found, tried %s' % (name, tried_methods))
# return the last failed dependency object # return the last failed dependency object
if pkgdep: if pkgdep:

@ -132,7 +132,6 @@ class BoostDependency(ExternalDependency):
self.incdir = self.detect_nix_incdir() self.incdir = self.detect_nix_incdir()
if self.check_invalid_modules(): if self.check_invalid_modules():
self.log_fail()
return return
mlog.debug('Boost library root dir is', mlog.bold(self.boost_root)) mlog.debug('Boost library root dir is', mlog.bold(self.boost_root))
@ -146,12 +145,6 @@ class BoostDependency(ExternalDependency):
self.detect_lib_modules() self.detect_lib_modules()
mlog.debug('Boost library directory is', mlog.bold(self.libdir)) mlog.debug('Boost library directory is', mlog.bold(self.libdir))
# 3. Report success or failure
if self.is_found:
self.log_success()
else:
self.log_fail()
def check_invalid_modules(self): def check_invalid_modules(self):
invalid_modules = [c for c in self.requested_modules if 'boost_' + c not in BOOST_LIBS] invalid_modules = [c for c in self.requested_modules if 'boost_' + c not in BOOST_LIBS]
@ -172,17 +165,14 @@ class BoostDependency(ExternalDependency):
else: else:
return False return False
def log_fail(self): def log_details(self):
module_str = ', '.join(self.requested_modules) module_str = ', '.join(self.requested_modules)
mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) return module_str
def log_success(self): def log_info(self):
module_str = ', '.join(self.requested_modules)
if self.boost_root: if self.boost_root:
info = self.version + ', ' + self.boost_root return self.boost_root
else: return ''
info = self.version
mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info)
def detect_nix_roots(self): def detect_nix_roots(self):
return [os.path.abspath(os.path.join(x, '..')) return [os.path.abspath(os.path.join(x, '..'))

@ -45,7 +45,7 @@ class GTestDependency(ExternalDependency):
if self.main: if self.main:
self.link_args += gtest_main_detect self.link_args += gtest_main_detect
self.sources = [] self.sources = []
mlog.log('Dependency GTest found:', mlog.green('YES'), '(prebuilt)') self.prebuilt = True
elif self.detect_srcdir(): elif self.detect_srcdir():
self.is_found = True self.is_found = True
self.compile_args = ['-I' + d for d in self.src_include_dirs] self.compile_args = ['-I' + d for d in self.src_include_dirs]
@ -54,9 +54,8 @@ class GTestDependency(ExternalDependency):
self.sources = [self.all_src, self.main_src] self.sources = [self.all_src, self.main_src]
else: else:
self.sources = [self.all_src] self.sources = [self.all_src]
mlog.log('Dependency GTest found:', mlog.green('YES'), '(building self)') self.prebuilt = False
else: else:
mlog.log('Dependency GTest found:', mlog.red('NO'))
self.is_found = False self.is_found = False
def detect_srcdir(self): def detect_srcdir(self):
@ -76,6 +75,12 @@ class GTestDependency(ExternalDependency):
def need_threads(self): def need_threads(self):
return True return True
def log_info(self):
if self.prebuilt:
return 'prebuilt'
else:
return 'building self'
class GMockDependency(ExternalDependency): class GMockDependency(ExternalDependency):
def __init__(self, environment, kwargs): def __init__(self, environment, kwargs):
@ -89,7 +94,7 @@ class GMockDependency(ExternalDependency):
self.compile_args = [] self.compile_args = []
self.link_args = gmock_detect self.link_args = gmock_detect
self.sources = [] self.sources = []
mlog.log('Dependency GMock found:', mlog.green('YES'), '(prebuilt)') self.prebuilt = True
return return
for d in ['/usr/src/googletest/googlemock/src', '/usr/src/gmock/src', '/usr/src/gmock']: for d in ['/usr/src/googletest/googlemock/src', '/usr/src/gmock/src', '/usr/src/gmock']:
@ -106,11 +111,17 @@ class GMockDependency(ExternalDependency):
self.sources = [all_src, main_src] self.sources = [all_src, main_src]
else: else:
self.sources = [all_src] self.sources = [all_src]
mlog.log('Dependency GMock found:', mlog.green('YES'), '(building self)') self.prebuilt = False
return return
mlog.log('Dependency GMock found:', mlog.red('NO'))
self.is_found = False self.is_found = False
def log_info(self):
if self.prebuilt:
return 'prebuilt'
else:
return 'building self'
class LLVMDependency(ConfigToolDependency): class LLVMDependency(ConfigToolDependency):
""" """
@ -145,6 +156,7 @@ class LLVMDependency(ConfigToolDependency):
super().__init__('LLVM', environment, 'cpp', kwargs) super().__init__('LLVM', environment, 'cpp', kwargs)
self.provided_modules = [] self.provided_modules = []
self.required_modules = set() self.required_modules = set()
self.module_details = []
if not self.is_found: if not self.is_found:
return return
self.static = kwargs.get('static', False) self.static = kwargs.get('static', False)
@ -237,21 +249,30 @@ class LLVMDependency(ConfigToolDependency):
is required. is required.
""" """
for mod in sorted(set(modules)): for mod in sorted(set(modules)):
status = ''
if mod not in self.provided_modules: if mod not in self.provided_modules:
mlog.log('LLVM module', mlog.bold(mod), 'found:', mlog.red('NO'),
'(optional)' if not required else '')
if required: if required:
self.is_found = False self.is_found = False
if self.required: if self.required:
raise DependencyException( raise DependencyException(
'Could not find required LLVM Component: {}'.format(mod)) 'Could not find required LLVM Component: {}'.format(mod))
status = '(missing)'
else:
status = '(missing but optional)'
else: else:
self.required_modules.add(mod) self.required_modules.add(mod)
mlog.log('LLVM module', mlog.bold(mod), 'found:', mlog.green('YES'))
self.module_details.append(mod + status)
def need_threads(self): def need_threads(self):
return True return True
def log_details(self):
if self.module_details:
return 'modules: ' + ', '.join(self.module_details)
return ''
class ValgrindDependency(PkgConfigDependency): class ValgrindDependency(PkgConfigDependency):
''' '''

@ -103,11 +103,6 @@ class MPIDependency(ExternalDependency):
self.is_found = True self.is_found = True
self.version, self.compile_args, self.link_args = result self.version, self.compile_args, self.link_args = result
if self.is_found:
mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.green('YES'), self.version)
else:
mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.red('NO'))
def _filter_compile_args(self, args): def _filter_compile_args(self, args):
""" """
MPI wrappers return a bunch of garbage args. MPI wrappers return a bunch of garbage args.
@ -265,10 +260,6 @@ class OpenMPDependency(ExternalDependency):
self.is_found = True self.is_found = True
else: else:
mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.') mlog.log(mlog.yellow('WARNING:'), 'OpenMP found but omp.h missing.')
if self.is_found:
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'), self.version)
else:
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
def need_openmp(self): def need_openmp(self):
return True return True
@ -324,10 +315,6 @@ class Python3Dependency(ExternalDependency):
self.compile_args = fw.get_compile_args() self.compile_args = fw.get_compile_args()
self.link_args = fw.get_link_args() self.link_args = fw.get_link_args()
self.is_found = True self.is_found = True
if self.is_found:
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES'))
else:
mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO'))
@staticmethod @staticmethod
def get_windows_python_arch(): def get_windows_python_arch():

@ -204,12 +204,10 @@ class QtBaseDependency(ExternalDependency):
self.bindir = None self.bindir = None
self.private_headers = kwargs.get('private_headers', False) self.private_headers = kwargs.get('private_headers', False)
mods = extract_as_list(kwargs, 'modules') mods = extract_as_list(kwargs, 'modules')
self.requested_modules = mods
if not mods: if not mods:
raise DependencyException('No ' + self.qtname + ' modules specified.') raise DependencyException('No ' + self.qtname + ' modules specified.')
type_text = 'cross' if env.is_cross_build() else 'native' self.from_text = 'pkg-config'
found_msg = '{} {} {{}} dependency (modules: {}) found:' \
''.format(self.qtname, type_text, ', '.join(mods))
from_text = 'pkg-config'
# Keep track of the detection methods used, for logging purposes. # Keep track of the detection methods used, for logging purposes.
methods = [] methods = []
@ -218,21 +216,15 @@ class QtBaseDependency(ExternalDependency):
self._pkgconfig_detect(mods, kwargs) self._pkgconfig_detect(mods, kwargs)
methods.append('pkgconfig') methods.append('pkgconfig')
if not self.is_found and DependencyMethods.QMAKE in self.methods: if not self.is_found and DependencyMethods.QMAKE in self.methods:
from_text = self._qmake_detect(mods, kwargs) self.from_text = self._qmake_detect(mods, kwargs)
methods.append('qmake-' + self.name) methods.append('qmake-' + self.name)
methods.append('qmake') methods.append('qmake')
if not self.is_found: if not self.is_found:
# Reset compile args and link args # Reset compile args and link args
self.compile_args = [] self.compile_args = []
self.link_args = [] self.link_args = []
from_text = '(checked {})'.format(mlog.format_list(methods)) self.from_text = mlog.format_list(methods)
self.version = 'none' self.version = 'none'
if not self.silent:
mlog.log(found_msg.format(from_text), mlog.red('NO'))
return
from_text = '`{}`'.format(from_text)
if not self.silent:
mlog.log(found_msg.format(from_text), mlog.green('YES'))
def compilers_detect(self): def compilers_detect(self):
"Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH" "Detect Qt (4 or 5) moc, uic, rcc in the specified bindir or in PATH"
@ -413,6 +405,16 @@ class QtBaseDependency(ExternalDependency):
def get_private_includes(self, mod_inc_dir, module): def get_private_includes(self, mod_inc_dir, module):
return tuple() return tuple()
def log_details(self):
module_str = ', '.join(self.requested_modules)
return 'modules: ' + module_str
def log_info(self):
return '`{}`'.format(self.from_text)
def log_tried(self):
return self.from_text
class Qt4Dependency(QtBaseDependency): class Qt4Dependency(QtBaseDependency):
def __init__(self, env, kwargs): def __init__(self, env, kwargs):

Loading…
Cancel
Save