Merge pull request #3657 from jon-turney/consolidate-dependency-check-report

Consolidate reporting the result of a dependency check
pull/4014/head
Nirbheek Chauhan 6 years ago committed by GitHub
commit 41bb5941e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 241
      mesonbuild/dependencies/base.py
  2. 20
      mesonbuild/dependencies/boost.py
  3. 39
      mesonbuild/dependencies/dev.py
  4. 130
      mesonbuild/dependencies/misc.py
  5. 231
      mesonbuild/dependencies/ui.py
  6. 14
      run_unittests.py

@ -16,6 +16,7 @@
# Custom logic for several other packages are in separate files. # Custom logic for several other packages are in separate files.
import copy import copy
import functools
import os import os
import re import re
import stat import stat
@ -265,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):
@ -296,6 +306,8 @@ class ConfigToolDependency(ExternalDependency):
self.config = None self.config = None
return return
self.version = version self.version = version
if getattr(self, 'finish_init', None):
self.finish_init(self)
def _sanitize_version(self, version): def _sanitize_version(self, version):
"""Remove any non-numeric, non-point version suffixes.""" """Remove any non-numeric, non-point version suffixes."""
@ -307,7 +319,7 @@ class ConfigToolDependency(ExternalDependency):
return version return version
@classmethod @classmethod
def factory(cls, name, environment, language, kwargs, tools, tool_name): def factory(cls, name, environment, language, kwargs, tools, tool_name, finish_init=None):
"""Constructor for use in dependencies that can be found multiple ways. """Constructor for use in dependencies that can be found multiple ways.
In addition to the standard constructor values, this constructor sets In addition to the standard constructor values, this constructor sets
@ -322,7 +334,7 @@ class ConfigToolDependency(ExternalDependency):
def reduce(self): def reduce(self):
return (cls._unpickle, (), self.__dict__) return (cls._unpickle, (), self.__dict__)
sub = type('{}Dependency'.format(name.capitalize()), (cls, ), sub = type('{}Dependency'.format(name.capitalize()), (cls, ),
{'tools': tools, 'tool_name': tool_name, '__reduce__': reduce}) {'tools': tools, 'tool_name': tool_name, '__reduce__': reduce, 'finish_init': staticmethod(finish_init)})
return sub(name, environment, language, kwargs) return sub(name, environment, language, kwargs)
@ -388,13 +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'))
if self.required:
raise DependencyException('Dependency {} not found'.format(self.name))
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):
@ -422,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
@ -463,20 +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:
if self.required:
raise DependencyException('{} dependency {!r} not found'
''.format(self.type_string, name))
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:
@ -487,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))
@ -505,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
@ -513,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}>'
@ -712,8 +701,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()
@ -797,6 +786,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
@ -818,7 +810,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 '
@ -828,10 +819,7 @@ class DubDependency(ExternalDependency):
ret, res = self._call_dubbin(['describe', name]) ret, res = self._call_dubbin(['describe', name])
if ret != 0: if ret != 0:
if self.required:
raise DependencyException('Dependency {!r} not found'.format(name))
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)
@ -842,10 +830,7 @@ class DubDependency(ExternalDependency):
msg = ['Dependency', mlog.bold(name), 'found but it was compiled with'] msg = ['Dependency', mlog.bold(name), 'found but it was compiled with']
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)
if self.required:
raise DependencyException('Dependency {!r} not found'.format(name))
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']
@ -853,7 +838,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:
@ -864,21 +848,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
@ -899,14 +873,8 @@ class DubDependency(ExternalDependency):
self.link_args.append(file) self.link_args.append(file)
if not found: if not found:
if self.required: self.is_found = False
raise DependencyException('Dependency {!r} not found'.format(name)) return
self.is_found = False
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return
if not self.silent:
mlog.log(*found_msg)
def get_compiler(self): def get_compiler(self):
return self.compiler return self.compiler
@ -952,7 +920,7 @@ class DubDependency(ExternalDependency):
@staticmethod @staticmethod
def get_methods(): def get_methods():
return [DependencyMethods.PKGCONFIG, DependencyMethods.DUB] return [DependencyMethods.DUB]
class ExternalProgram: class ExternalProgram:
windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd') windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd')
@ -1229,10 +1197,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()
@ -1251,12 +1215,16 @@ class ExtraFrameworkDependency(ExternalDependency):
self.name = d self.name = d
self.is_found = True self.is_found = True
return return
if not self.found() and self.required:
raise DependencyException('Framework dependency %s not found.' % (name, ))
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,54 +1245,131 @@ def get_dep_identifier(name, kwargs, want_cross):
identifier += (key, value) identifier += (key, value)
return identifier return identifier
display_name_map = {
'boost': 'Boost',
'dub': 'DUB',
'gmock': 'GMock',
'gtest': 'GTest',
'llvm': 'LLVM',
'mpi': 'MPI',
'openmp': 'OpenMP',
'wxwidgets': 'WxWidgets',
}
def find_external_dependency(name, env, kwargs): def find_external_dependency(name, env, kwargs):
assert(name)
required = kwargs.get('required', True) required = kwargs.get('required', True)
if not isinstance(required, bool): if not isinstance(required, bool):
raise DependencyException('Keyword "required" must be a boolean.') raise DependencyException('Keyword "required" must be a boolean.')
if not isinstance(kwargs.get('method', ''), str): if not isinstance(kwargs.get('method', ''), str):
raise DependencyException('Keyword "method" must be a string.') raise DependencyException('Keyword "method" must be a string.')
method = kwargs.get('method', '') lname = name.lower()
if lname not in _packages_accept_language and 'language' in kwargs:
raise DependencyException('%s dependency does not accept "language" keyword argument' % (name, ))
# display the dependency name with correct casing
display_name = display_name_map.get(lname, lname)
# if this isn't a cross-build, it's uninteresting if native: is used or not
if not env.is_cross_build():
type_text = 'Dependency'
else:
type_text = 'Native' if kwargs.get('native', False) else 'Cross'
type_text += ' dependency'
# build a list of dependency methods to try
candidates = _build_external_dependency_list(name, env, kwargs)
pkg_exc = None
pkgdep = []
details = ''
for c in candidates:
# try this dependency method
try:
d = c()
pkgdep.append(d)
except Exception as e:
mlog.debug(str(e))
# store the first exception we see
if not pkg_exc:
pkg_exc = e
else:
details = d.log_details()
if details:
details = '(' + details + ') '
if 'language' in kwargs:
details += 'for ' + d.language + ' '
# if the dependency was found
if d.found():
info = d.log_info()
if info:
info = ', ' + info
mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.green('YES'), d.version + info)
return d
# 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(type_text, mlog.bold(display_name), details + 'found:', mlog.red('NO'),
'(tried {})'.format(tried) if tried else '')
if required:
# if exception(s) occurred, re-raise the first one (on the grounds that
# it came from a preferred dependency detection method)
if pkg_exc:
raise pkg_exc
# we have a list of failed ExternalDependency objects, so we can report
# the methods we tried to find the dependency
raise DependencyException('Dependency "%s" not found, tried %s' % (name, tried))
# return the last failed dependency object
if pkgdep:
return pkgdep[-1]
# this should never happen
raise DependencyException('Dependency "%s" not found, but no dependency object to return' % (name))
def _build_external_dependency_list(name, env, kwargs):
# Is there a specific dependency detector for this dependency?
lname = name.lower() lname = name.lower()
if lname in packages: if lname in packages:
if lname not in _packages_accept_language and 'language' in kwargs: # Create the list of dependency object constructors using a factory
raise DependencyException('%s dependency does not accept "language" keyword argument' % (lname, )) # class method, if one exists, otherwise the list just consists of the
# Create the dependency object using a factory class method, if one # constructor
# exists, otherwise it is just constructed directly.
if getattr(packages[lname], '_factory', None): if getattr(packages[lname], '_factory', None):
dep = packages[lname]._factory(env, kwargs) dep = packages[lname]._factory(env, kwargs)
else: else:
dep = packages[lname](env, kwargs) dep = [functools.partial(packages[lname], env, kwargs)]
if required and not dep.found():
raise DependencyException('Dependency "%s" not found' % name)
return dep return dep
if 'language' in kwargs:
# Remove check when PkgConfigDependency supports language. candidates = []
raise DependencyException('%s dependency does not accept "language" keyword argument' % (lname, ))
if 'dub' == method: # If it's explicitly requested, use the dub detection method (only)
dubdep = DubDependency(name, env, kwargs) if 'dub' == kwargs.get('method', ''):
if required and not dubdep.found(): candidates.append(functools.partial(DubDependency, name, env, kwargs))
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return candidates
return dubdep # TBD: other values of method should control what method(s) are used
pkg_exc = None
pkgdep = None # Otherwise, just use the pkgconfig dependency detector
try: candidates.append(functools.partial(PkgConfigDependency, name, env, kwargs))
pkgdep = PkgConfigDependency(name, env, kwargs)
if pkgdep.found(): # On OSX, also try framework dependency detector
return pkgdep
except Exception as e:
pkg_exc = e
if mesonlib.is_osx(): if mesonlib.is_osx():
fwdep = ExtraFrameworkDependency(name, False, None, env, None, kwargs) candidates.append(functools.partial(ExtraFrameworkDependency, name,
if required and not fwdep.found(): False, None, env, None, kwargs))
m = 'Dependency {!r} not found, tried Extra Frameworks ' \
'and Pkg-Config:\n\n' + str(pkg_exc) return candidates
raise DependencyException(m.format(name))
return fwdep
if pkg_exc is not None:
raise pkg_exc
mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO'))
return pkgdep
def strip_system_libdirs(environment, link_args): def strip_system_libdirs(environment, link_args):

@ -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):
''' '''

@ -14,6 +14,7 @@
# This file contains the detection logic for miscellaneous external dependencies. # This file contains the detection logic for miscellaneous external dependencies.
import functools
import os import os
import re import re
import shlex import shlex
@ -37,7 +38,6 @@ class MPIDependency(ExternalDependency):
def __init__(self, environment, kwargs): def __init__(self, environment, kwargs):
language = kwargs.get('language', 'c') language = kwargs.get('language', 'c')
super().__init__('mpi', environment, language, kwargs) super().__init__('mpi', environment, language, kwargs)
required = kwargs.pop('required', True)
kwargs['required'] = False kwargs['required'] = False
kwargs['silent'] = True kwargs['silent'] = True
self.is_found = False self.is_found = False
@ -103,13 +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'))
if required:
raise DependencyException('MPI dependency {!r} not found'.format(self.name))
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.
@ -267,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
@ -326,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():
@ -436,33 +421,29 @@ class PcapDependency(ExternalDependency):
@classmethod @classmethod
def _factory(cls, environment, kwargs): def _factory(cls, environment, kwargs):
methods = cls._process_method_kw(kwargs) methods = cls._process_method_kw(kwargs)
candidates = []
if DependencyMethods.PKGCONFIG in methods: if DependencyMethods.PKGCONFIG in methods:
try: candidates.append(functools.partial(PkgConfigDependency, 'pcap', environment, kwargs))
pcdep = PkgConfigDependency('pcap', environment, kwargs)
if pcdep.found():
return pcdep
except Exception as e:
mlog.debug('Pcap not found via pkgconfig. Trying next, error was:', str(e))
if DependencyMethods.CONFIG_TOOL in methods: if DependencyMethods.CONFIG_TOOL in methods:
try: candidates.append(functools.partial(ConfigToolDependency.factory,
ctdep = ConfigToolDependency.factory( 'pcap', environment, None,
'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config') kwargs, ['pcap-config'],
if ctdep.found(): 'pcap-config',
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') PcapDependency.tool_finish_init))
ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
ctdep.version = cls.get_pcap_lib_version(ctdep) return candidates
return ctdep
except Exception as e: @staticmethod
mlog.debug('Pcap not found via pcap-config. Trying next, error was:', str(e)) def tool_finish_init(ctdep):
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
return PcapDependency(environment, kwargs) ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
ctdep.version = PcapDependency.get_pcap_lib_version(ctdep)
@staticmethod @staticmethod
def get_methods(): def get_methods():
if mesonlib.is_osx(): return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
else:
return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
@staticmethod @staticmethod
def get_pcap_lib_version(ctdep): def get_pcap_lib_version(ctdep):
@ -477,32 +458,29 @@ class CupsDependency(ExternalDependency):
@classmethod @classmethod
def _factory(cls, environment, kwargs): def _factory(cls, environment, kwargs):
methods = cls._process_method_kw(kwargs) methods = cls._process_method_kw(kwargs)
candidates = []
if DependencyMethods.PKGCONFIG in methods: if DependencyMethods.PKGCONFIG in methods:
try: candidates.append(functools.partial(PkgConfigDependency, 'cups', environment, kwargs))
pcdep = PkgConfigDependency('cups', environment, kwargs)
if pcdep.found():
return pcdep
except Exception as e:
mlog.debug('cups not found via pkgconfig. Trying next, error was:', str(e))
if DependencyMethods.CONFIG_TOOL in methods: if DependencyMethods.CONFIG_TOOL in methods:
try: candidates.append(functools.partial(ConfigToolDependency.factory,
ctdep = ConfigToolDependency.factory( 'cups', environment, None,
'cups', environment, None, kwargs, ['cups-config'], 'cups-config') kwargs, ['cups-config'],
if ctdep.found(): 'cups-config', CupsDependency.tool_finish_init))
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
ctdep.link_args = ctdep.get_config_value(['--ldflags', '--libs'], 'link_args')
return ctdep
except Exception as e:
mlog.debug('cups not found via cups-config. Trying next, error was:', str(e))
if DependencyMethods.EXTRAFRAMEWORK in methods: if DependencyMethods.EXTRAFRAMEWORK in methods:
if mesonlib.is_osx(): if mesonlib.is_osx():
fwdep = ExtraFrameworkDependency('cups', False, None, environment, candidates.append(functools.partial(
kwargs.get('language', None), kwargs) ExtraFrameworkDependency, 'cups', False, None, environment,
if fwdep.found(): kwargs.get('language', None), kwargs))
return fwdep
mlog.log('Dependency', mlog.bold('cups'), 'found:', mlog.red('NO'))
return CupsDependency(environment, kwargs) return candidates
@staticmethod
def tool_finish_init(ctdep):
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
ctdep.link_args = ctdep.get_config_value(['--ldflags', '--libs'], 'link_args')
@staticmethod @staticmethod
def get_methods(): def get_methods():
@ -519,30 +497,22 @@ class LibWmfDependency(ExternalDependency):
@classmethod @classmethod
def _factory(cls, environment, kwargs): def _factory(cls, environment, kwargs):
methods = cls._process_method_kw(kwargs) methods = cls._process_method_kw(kwargs)
candidates = []
if DependencyMethods.PKGCONFIG in methods: if DependencyMethods.PKGCONFIG in methods:
try: candidates.append(functools.partial(PkgConfigDependency, 'libwmf', environment, kwargs))
kwargs['required'] = False
pcdep = PkgConfigDependency('libwmf', environment, kwargs)
if pcdep.found():
return pcdep
except Exception as e:
mlog.debug('LibWmf not found via pkgconfig. Trying next, error was:', str(e))
if DependencyMethods.CONFIG_TOOL in methods: if DependencyMethods.CONFIG_TOOL in methods:
try: candidates.append(functools.partial(ConfigToolDependency.factory,
ctdep = ConfigToolDependency.factory( 'libwmf', environment, None, kwargs, ['libwmf-config'], 'libwmf-config', LibWmfDependency.tool_finish_init))
'libwmf', environment, None, kwargs, ['libwmf-config'], 'libwmf-config')
if ctdep.found():
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
return ctdep
except Exception as e:
mlog.debug('cups not found via libwmf-config. Trying next, error was:', str(e))
return LibWmfDependency(environment, kwargs) return candidates
@staticmethod
def tool_finish_init(ctdep):
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
@staticmethod @staticmethod
def get_methods(): def get_methods():
if mesonlib.is_osx(): return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]
return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK]
else:
return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL]

@ -15,6 +15,7 @@
# This file contains the detection logic for external dependencies that # This file contains the detection logic for external dependencies that
# are UI-related. # are UI-related.
import functools
import os import os
import re import re
import subprocess import subprocess
@ -37,32 +38,34 @@ from .base import ConfigToolDependency
class GLDependency(ExternalDependency): class GLDependency(ExternalDependency):
def __init__(self, environment, kwargs): def __init__(self, environment, kwargs):
super().__init__('gl', environment, None, kwargs) super().__init__('gl', environment, None, kwargs)
if DependencyMethods.SYSTEM in self.methods:
if mesonlib.is_osx(): if mesonlib.is_osx():
self.is_found = True self.is_found = True
# FIXME: Use AppleFrameworks dependency # FIXME: Use AppleFrameworks dependency
self.link_args = ['-framework', 'OpenGL'] self.link_args = ['-framework', 'OpenGL']
# FIXME: Detect version using self.clib_compiler # FIXME: Detect version using self.clib_compiler
self.version = '1' self.version = '1'
return return
if mesonlib.is_windows(): if mesonlib.is_windows():
self.is_found = True self.is_found = True
# FIXME: Use self.clib_compiler.find_library() # FIXME: Use self.clib_compiler.find_library()
self.link_args = ['-lopengl32'] self.link_args = ['-lopengl32']
# FIXME: Detect version using self.clib_compiler # FIXME: Detect version using self.clib_compiler
self.version = '1' self.version = '1'
return return
@classmethod @classmethod
def _factory(cls, environment, kwargs): def _factory(cls, environment, kwargs):
if DependencyMethods.PKGCONFIG in cls._process_method_kw(kwargs): methods = cls._process_method_kw(kwargs)
try: candidates = []
pcdep = PkgConfigDependency('gl', environment, kwargs)
if pcdep.found(): if DependencyMethods.PKGCONFIG in methods:
return pcdep candidates.append(functools.partial(PkgConfigDependency, 'gl', environment, kwargs))
except Exception:
pass if DependencyMethods.SYSTEM in methods:
return GLDependency(environment, kwargs) candidates.append(functools.partial(GLDependency), environment, kwargs)
return candidates
@staticmethod @staticmethod
def get_methods(): def get_methods():
@ -201,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 = []
@ -215,25 +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 self.required:
err_msg = '{} {} dependency not found {}' \
''.format(self.qtname, type_text, from_text)
raise DependencyException(err_msg)
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"
@ -414,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):
@ -452,33 +453,29 @@ class SDL2Dependency(ExternalDependency):
@classmethod @classmethod
def _factory(cls, environment, kwargs): def _factory(cls, environment, kwargs):
methods = cls._process_method_kw(kwargs) methods = cls._process_method_kw(kwargs)
candidates = []
if DependencyMethods.PKGCONFIG in methods: if DependencyMethods.PKGCONFIG in methods:
try: candidates.append(functools.partial(PkgConfigDependency, 'sdl2', environment, kwargs))
pcdep = PkgConfigDependency('sdl2', environment, kwargs)
if pcdep.found():
return pcdep
except Exception as e:
mlog.debug('SDL 2 not found via pkgconfig. Trying next, error was:', str(e))
if DependencyMethods.CONFIG_TOOL in methods: if DependencyMethods.CONFIG_TOOL in methods:
try: candidates.append(functools.partial(ConfigToolDependency.factory,
ctdep = ConfigToolDependency.factory( 'sdl2', environment, None,
'sdl2', environment, None, kwargs, ['sdl2-config'], 'sdl2-config') kwargs, ['sdl2-config'],
if ctdep.found(): 'sdl2-config', SDL2Dependency.tool_finish_init))
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
return ctdep
except Exception as e:
mlog.debug('SDL 2 not found via sdl2-config. Trying next, error was:', str(e))
if DependencyMethods.EXTRAFRAMEWORK in methods: if DependencyMethods.EXTRAFRAMEWORK in methods:
if mesonlib.is_osx(): if mesonlib.is_osx():
fwdep = ExtraFrameworkDependency('sdl2', False, None, environment, candidates.append(functools.partial(ExtraFrameworkDependency,
kwargs.get('language', None), kwargs) 'sdl2', False, None, environment,
if fwdep.found(): kwargs.get('language', None), kwargs))
fwdep.version = '2' # FIXME # fwdep.version = '2' # FIXME
return fwdep return candidates
mlog.log('Dependency', mlog.bold('sdl2'), 'found:', mlog.red('NO'))
return SDL2Dependency(environment, kwargs) @staticmethod
def tool_finish_init(ctdep):
ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args')
ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args')
@staticmethod @staticmethod
def get_methods(): def get_methods():
@ -518,73 +515,73 @@ class VulkanDependency(ExternalDependency):
def __init__(self, environment, kwargs): def __init__(self, environment, kwargs):
super().__init__('vulkan', environment, None, kwargs) super().__init__('vulkan', environment, None, kwargs)
if DependencyMethods.SYSTEM in self.methods: try:
try: self.vulkan_sdk = os.environ['VULKAN_SDK']
self.vulkan_sdk = os.environ['VULKAN_SDK'] if not os.path.isabs(self.vulkan_sdk):
if not os.path.isabs(self.vulkan_sdk): raise DependencyException('VULKAN_SDK must be an absolute path.')
raise DependencyException('VULKAN_SDK must be an absolute path.') except KeyError:
except KeyError: self.vulkan_sdk = None
self.vulkan_sdk = None
if self.vulkan_sdk:
if self.vulkan_sdk: # TODO: this config might not work on some platforms, fix bugs as reported
# TODO: this config might not work on some platforms, fix bugs as reported # we should at least detect other 64-bit platforms (e.g. armv8)
# we should at least detect other 64-bit platforms (e.g. armv8) lib_name = 'vulkan'
if mesonlib.is_windows():
lib_name = 'vulkan-1'
lib_dir = 'Lib32'
inc_dir = 'Include'
if detect_cpu({}) == 'x86_64':
lib_dir = 'Lib'
else:
lib_name = 'vulkan' lib_name = 'vulkan'
if mesonlib.is_windows(): lib_dir = 'lib'
lib_name = 'vulkan-1' inc_dir = 'include'
lib_dir = 'Lib32'
inc_dir = 'Include'
if detect_cpu({}) == 'x86_64':
lib_dir = 'Lib'
else:
lib_name = 'vulkan'
lib_dir = 'lib'
inc_dir = 'include'
# make sure header and lib are valid # make sure header and lib are valid
inc_path = os.path.join(self.vulkan_sdk, inc_dir) inc_path = os.path.join(self.vulkan_sdk, inc_dir)
header = os.path.join(inc_path, 'vulkan', 'vulkan.h') header = os.path.join(inc_path, 'vulkan', 'vulkan.h')
lib_path = os.path.join(self.vulkan_sdk, lib_dir) lib_path = os.path.join(self.vulkan_sdk, lib_dir)
find_lib = self.clib_compiler.find_library(lib_name, environment, lib_path) find_lib = self.clib_compiler.find_library(lib_name, environment, lib_path)
if not find_lib: if not find_lib:
raise DependencyException('VULKAN_SDK point to invalid directory (no lib)') raise DependencyException('VULKAN_SDK point to invalid directory (no lib)')
if not os.path.isfile(header): if not os.path.isfile(header):
raise DependencyException('VULKAN_SDK point to invalid directory (no include)') raise DependencyException('VULKAN_SDK point to invalid directory (no include)')
self.type_name = 'vulkan_sdk' self.type_name = 'vulkan_sdk'
self.is_found = True self.is_found = True
self.compile_args.append('-I' + inc_path) self.compile_args.append('-I' + inc_path)
self.link_args.append('-L' + lib_path) self.link_args.append('-L' + lib_path)
self.link_args.append('-l' + lib_name) self.link_args.append('-l' + lib_name)
# TODO: find a way to retrieve the version from the sdk? # TODO: find a way to retrieve the version from the sdk?
# Usually it is a part of the path to it (but does not have to be) # Usually it is a part of the path to it (but does not have to be)
self.version = '1' self.version = '1'
return
else:
# simply try to guess it, usually works on linux
libs = self.clib_compiler.find_library('vulkan', environment, [])
if libs is not None and self.clib_compiler.has_header('vulkan/vulkan.h', '', environment):
self.type_name = 'system'
self.is_found = True
self.version = 1 # TODO
for lib in libs:
self.link_args.append(lib)
return return
else:
# simply try to guess it, usually works on linux
libs = self.clib_compiler.find_library('vulkan', environment, [])
if libs is not None and self.clib_compiler.has_header('vulkan/vulkan.h', '', environment):
self.type_name = 'system'
self.is_found = True
self.version = 1 # TODO
for lib in libs:
self.link_args.append(lib)
return
@classmethod @classmethod
def _factory(cls, environment, kwargs): def _factory(cls, environment, kwargs):
if DependencyMethods.PKGCONFIG in cls._process_method_kw(kwargs): methods = cls._process_method_kw(kwargs)
try: candidates = []
pcdep = PkgConfigDependency('vulkan', environment, kwargs)
if pcdep.found(): if DependencyMethods.PKGCONFIG in methods:
return pcdep candidates.append(functools.partial(PkgConfigDependency, 'vulkan', environment, kwargs))
except Exception:
pass
return VulkanDependency(environment, kwargs) if DependencyMethods.PKGCONFIG in methods:
candidates.append(functools.partial(VulkanDependency, environment, kwargs))
return candidates
@staticmethod @staticmethod
def get_methods(): def get_methods():

@ -3025,11 +3025,12 @@ class LinuxlikeTests(BasePlatformTests):
raise unittest.SkipTest('Qt not found with pkg-config') raise unittest.SkipTest('Qt not found with pkg-config')
testdir = os.path.join(self.framework_test_dir, '4 qt') testdir = os.path.join(self.framework_test_dir, '4 qt')
self.init(testdir, ['-Dmethod=pkg-config']) self.init(testdir, ['-Dmethod=pkg-config'])
# Confirm that the dependency was found with qmake # Confirm that the dependency was found with pkg-config
msg = 'Qt4 native `pkg-config` dependency (modules: Core, Gui) found: YES\n'
msg2 = 'Qt5 native `pkg-config` dependency (modules: Core, Gui) found: YES\n'
mesonlog = self.get_meson_log() mesonlog = self.get_meson_log()
self.assertTrue(msg in mesonlog or msg2 in mesonlog) self.assertRegex('\n'.join(mesonlog),
r'Dependency qt4 \(modules: Core\) found: YES .*, `pkg-config`\n')
self.assertRegex('\n'.join(mesonlog),
r'Dependency qt5 \(modules: Core\) found: YES .*, `pkg-config`\n')
def test_qt5dependency_qmake_detection(self): def test_qt5dependency_qmake_detection(self):
''' '''
@ -3047,10 +3048,9 @@ class LinuxlikeTests(BasePlatformTests):
testdir = os.path.join(self.framework_test_dir, '4 qt') testdir = os.path.join(self.framework_test_dir, '4 qt')
self.init(testdir, ['-Dmethod=qmake']) self.init(testdir, ['-Dmethod=qmake'])
# Confirm that the dependency was found with qmake # Confirm that the dependency was found with qmake
msg = 'Qt5 native `qmake-qt5` dependency (modules: Core) found: YES\n'
msg2 = 'Qt5 native `qmake` dependency (modules: Core) found: YES\n'
mesonlog = self.get_meson_log() mesonlog = self.get_meson_log()
self.assertTrue(msg in mesonlog or msg2 in mesonlog) self.assertRegex('\n'.join(mesonlog),
r'Dependency qt5 \(modules: Core\) found: YES .*, `(qmake|qmake-qt5)`\n')
def _test_soname_impl(self, libpath, install): def _test_soname_impl(self, libpath, install):
if is_cygwin() or is_osx(): if is_cygwin() or is_osx():

Loading…
Cancel
Save