From fce4f351701efa0ff95c7966b83289fc24092452 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 31 May 2018 23:48:19 +0100 Subject: [PATCH 01/10] Remove do-nothing extraframework method from libwmf and pcap libwmf and pcap allegedly support method:extraframework, but this does nothing but return not-found. Possibly cut-and-pasted from elsewhere? --- mesonbuild/dependencies/misc.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 745dff011..19874fc80 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -459,10 +459,7 @@ class PcapDependency(ExternalDependency): @staticmethod def get_methods(): - if mesonlib.is_osx(): - return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK] - else: - return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] + return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] @staticmethod def get_pcap_lib_version(ctdep): @@ -542,7 +539,4 @@ class LibWmfDependency(ExternalDependency): @staticmethod def get_methods(): - if mesonlib.is_osx(): - return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK] - else: - return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] + return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] From 983263e82cee812b32b2863d2725027c779bf81d Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Tue, 31 Jul 2018 19:53:18 +0100 Subject: [PATCH 02/10] Remove do-nothing pkgconfig method from dub dub dependencies allegedly support method:pkgconfig, but this is meaningless as it's only ever used when the dub method is explicitly requested. Possibly cut-and-pasted from elsewhere? --- mesonbuild/dependencies/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 9d7e24c42..15dbd62ba 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -947,7 +947,7 @@ class DubDependency(ExternalDependency): @staticmethod def get_methods(): - return [DependencyMethods.PKGCONFIG, DependencyMethods.DUB] + return [DependencyMethods.DUB] class ExternalProgram: windows_exts = ('exe', 'msc', 'com', 'bat', 'cmd') From 82bdf07a9d1ca6c62d4645a8c996975a5cef2989 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 31 May 2018 21:23:17 +0100 Subject: [PATCH 03/10] Hoist trying several dependency detection methods up to find_external_dependency() find_external_dependency() now makes and iterates over a list of callables which are constructors with bound arguments for the dependency objects we are going to attempt to make, so we can consolidate reporting on these attempts and handling failures in that function. --- mesonbuild/dependencies/base.py | 101 ++++++++++------ mesonbuild/dependencies/misc.py | 100 +++++++--------- mesonbuild/dependencies/ui.py | 201 ++++++++++++++++---------------- 3 files changed, 209 insertions(+), 193 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 15dbd62ba..c34146f4e 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -16,6 +16,7 @@ # Custom logic for several other packages are in separate files. import copy +import functools import os import re import stat @@ -1279,47 +1280,79 @@ def find_external_dependency(name, env, kwargs): raise DependencyException('Keyword "required" must be a boolean.') if not isinstance(kwargs.get('method', ''), str): raise DependencyException('Keyword "method" must be a string.') - method = kwargs.get('method', '') + if name.lower() not in _packages_accept_language and 'language' in kwargs: + raise DependencyException('%s dependency does not accept "language" keyword argument' % (name, )) + + # build a list of dependency methods to try + candidates = _build_external_dependency_list(name, env, kwargs) + + pkg_exc = None + pkgdep = [] + 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: + # if the dependency was found + if d.found(): + return d + + # otherwise, the dependency could not be found + 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 + tried_methods = ','.join([d.type_name for d in pkgdep]) + raise DependencyException('Dependency "%s" not found, tried %s' % (name, tried_methods)) + + # 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() if lname in packages: - if lname not in _packages_accept_language and 'language' in kwargs: - raise DependencyException('%s dependency does not accept "language" keyword argument' % (lname, )) - # Create the dependency object using a factory class method, if one - # exists, otherwise it is just constructed directly. + # Create the list of dependency object constructors using a factory + # class method, if one exists, otherwise the list just consists of the + # constructor if getattr(packages[lname], '_factory', None): dep = packages[lname]._factory(env, kwargs) else: - dep = packages[lname](env, kwargs) - if required and not dep.found(): - raise DependencyException('Dependency "%s" not found' % name) + dep = [functools.partial(packages[lname], env, kwargs)] return dep - if 'language' in kwargs: - # Remove check when PkgConfigDependency supports language. - raise DependencyException('%s dependency does not accept "language" keyword argument' % (lname, )) - if 'dub' == method: - dubdep = DubDependency(name, env, kwargs) - if required and not dubdep.found(): - mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) - return dubdep - pkg_exc = None - pkgdep = None - try: - pkgdep = PkgConfigDependency(name, env, kwargs) - if pkgdep.found(): - return pkgdep - except Exception as e: - pkg_exc = e + + candidates = [] + + # If it's explicitly requested, use the dub detection method (only) + if 'dub' == kwargs.get('method', ''): + candidates.append(functools.partial(DubDependency, name, env, kwargs)) + return candidates + # TBD: other values of method should control what method(s) are used + + # Otherwise, just use the pkgconfig dependency detector + candidates.append(functools.partial(PkgConfigDependency, name, env, kwargs)) + + # On OSX, also try framework dependency detector if mesonlib.is_osx(): - fwdep = ExtraFrameworkDependency(name, False, None, env, None, kwargs) - if required and not fwdep.found(): - m = 'Dependency {!r} not found, tried Extra Frameworks ' \ - 'and Pkg-Config:\n\n' + str(pkg_exc) - 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 + candidates.append(functools.partial(ExtraFrameworkDependency, name, + False, None, env, None, kwargs)) + + return candidates def strip_system_libdirs(environment, link_args): diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 19874fc80..607643352 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -14,6 +14,7 @@ # This file contains the detection logic for miscellaneous external dependencies. +import functools import os import re import shlex @@ -436,26 +437,21 @@ class PcapDependency(ExternalDependency): @classmethod def _factory(cls, environment, kwargs): methods = cls._process_method_kw(kwargs) + candidates = [] + if DependencyMethods.PKGCONFIG in methods: - try: - 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)) + candidates.append(functools.partial(PkgConfigDependency, 'pcap', environment, kwargs)) + if DependencyMethods.CONFIG_TOOL in methods: - try: - ctdep = ConfigToolDependency.factory( - 'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config') - if ctdep.found(): - ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') - ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args') - ctdep.version = cls.get_pcap_lib_version(ctdep) - return ctdep - except Exception as e: - mlog.debug('Pcap not found via pcap-config. Trying next, error was:', str(e)) - - return PcapDependency(environment, kwargs) + candidates.append(functools.partial(ConfigToolDependency.factory, + 'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config')) +# if ctdep.found(): +# ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') +# ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args') +# ctdep.version = cls.get_pcap_lib_version(ctdep) +# return ctdep + + return candidates @staticmethod def get_methods(): @@ -474,32 +470,27 @@ class CupsDependency(ExternalDependency): @classmethod def _factory(cls, environment, kwargs): methods = cls._process_method_kw(kwargs) + candidates = [] + if DependencyMethods.PKGCONFIG in methods: - try: - 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)) + candidates.append(functools.partial(PkgConfigDependency, 'cups', environment, kwargs)) + if DependencyMethods.CONFIG_TOOL in methods: - try: - ctdep = ConfigToolDependency.factory( - 'cups', environment, None, kwargs, ['cups-config'], 'cups-config') - if ctdep.found(): - 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)) + candidates.append(functools.partial(ConfigToolDependency.factory, + 'cups', environment, None, + kwargs, ['cups-config'], + 'cups-config')) +# if ctdep.found(): +# ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') +# ctdep.link_args = ctdep.get_config_value(['--ldflags', '--libs'], 'link_args') + if DependencyMethods.EXTRAFRAMEWORK in methods: if mesonlib.is_osx(): - fwdep = ExtraFrameworkDependency('cups', False, None, environment, - kwargs.get('language', None), kwargs) - if fwdep.found(): - return fwdep - mlog.log('Dependency', mlog.bold('cups'), 'found:', mlog.red('NO')) + candidates.append(functools.partial( + ExtraFrameworkDependency, 'cups', False, None, environment, + kwargs.get('language', None), kwargs)) - return CupsDependency(environment, kwargs) + return candidates @staticmethod def get_methods(): @@ -516,26 +507,21 @@ class LibWmfDependency(ExternalDependency): @classmethod def _factory(cls, environment, kwargs): methods = cls._process_method_kw(kwargs) + candidates = [] + if DependencyMethods.PKGCONFIG in methods: - try: - 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)) + candidates.append(functools.partial(PkgConfigDependency, 'libwmf', environment, kwargs)) + if DependencyMethods.CONFIG_TOOL in methods: - try: - ctdep = ConfigToolDependency.factory( - '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) + candidates.append(functools.partial(ConfigToolDependency.factory, + '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 + + return candidates @staticmethod def get_methods(): diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 197d22cb1..e25d135b7 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -15,6 +15,7 @@ # This file contains the detection logic for external dependencies that # are UI-related. +import functools import os import re import subprocess @@ -37,32 +38,34 @@ from .base import ConfigToolDependency class GLDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('gl', environment, None, kwargs) - if DependencyMethods.SYSTEM in self.methods: - if mesonlib.is_osx(): - self.is_found = True - # FIXME: Use AppleFrameworks dependency - self.link_args = ['-framework', 'OpenGL'] - # FIXME: Detect version using self.clib_compiler - self.version = '1' - return - if mesonlib.is_windows(): - self.is_found = True - # FIXME: Use self.clib_compiler.find_library() - self.link_args = ['-lopengl32'] - # FIXME: Detect version using self.clib_compiler - self.version = '1' - return + + if mesonlib.is_osx(): + self.is_found = True + # FIXME: Use AppleFrameworks dependency + self.link_args = ['-framework', 'OpenGL'] + # FIXME: Detect version using self.clib_compiler + self.version = '1' + return + if mesonlib.is_windows(): + self.is_found = True + # FIXME: Use self.clib_compiler.find_library() + self.link_args = ['-lopengl32'] + # FIXME: Detect version using self.clib_compiler + self.version = '1' + return @classmethod def _factory(cls, environment, kwargs): - if DependencyMethods.PKGCONFIG in cls._process_method_kw(kwargs): - try: - pcdep = PkgConfigDependency('gl', environment, kwargs) - if pcdep.found(): - return pcdep - except Exception: - pass - return GLDependency(environment, kwargs) + methods = cls._process_method_kw(kwargs) + candidates = [] + + if DependencyMethods.PKGCONFIG in methods: + candidates.append(functools.partial(PkgConfigDependency, 'gl', environment, kwargs)) + + if DependencyMethods.SYSTEM in methods: + candidates.append(functools.partial(GLDependency), environment, kwargs) + + return candidates @staticmethod def get_methods(): @@ -452,33 +455,27 @@ class SDL2Dependency(ExternalDependency): @classmethod def _factory(cls, environment, kwargs): methods = cls._process_method_kw(kwargs) + candidates = [] + if DependencyMethods.PKGCONFIG in methods: - try: - 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)) + candidates.append(functools.partial(PkgConfigDependency, 'sdl2', environment, kwargs)) + if DependencyMethods.CONFIG_TOOL in methods: - try: - ctdep = ConfigToolDependency.factory( - 'sdl2', environment, None, kwargs, ['sdl2-config'], 'sdl2-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('SDL 2 not found via sdl2-config. Trying next, error was:', str(e)) + candidates.append(functools.partial(ConfigToolDependency.factory, + 'sdl2', environment, None, + kwargs, ['sdl2-config'], + 'sdl2-config')) +# if ctdep.found(): +# ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') +# ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args') + if DependencyMethods.EXTRAFRAMEWORK in methods: if mesonlib.is_osx(): - fwdep = ExtraFrameworkDependency('sdl2', False, None, environment, - kwargs.get('language', None), kwargs) - if fwdep.found(): - fwdep.version = '2' # FIXME - return fwdep - mlog.log('Dependency', mlog.bold('sdl2'), 'found:', mlog.red('NO')) - - return SDL2Dependency(environment, kwargs) + candidates.append(functools.partial(ExtraFrameworkDependency, + 'sdl2', False, None, environment, + kwargs.get('language', None), kwargs)) + # fwdep.version = '2' # FIXME + return candidates @staticmethod def get_methods(): @@ -518,73 +515,73 @@ class VulkanDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('vulkan', environment, None, kwargs) - if DependencyMethods.SYSTEM in self.methods: - try: - self.vulkan_sdk = os.environ['VULKAN_SDK'] - if not os.path.isabs(self.vulkan_sdk): - raise DependencyException('VULKAN_SDK must be an absolute path.') - except KeyError: - self.vulkan_sdk = None - - if self.vulkan_sdk: - # 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) + try: + self.vulkan_sdk = os.environ['VULKAN_SDK'] + if not os.path.isabs(self.vulkan_sdk): + raise DependencyException('VULKAN_SDK must be an absolute path.') + except KeyError: + self.vulkan_sdk = None + + if self.vulkan_sdk: + # 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) + 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' - 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_dir = 'lib' - inc_dir = 'include' + lib_dir = 'lib' + inc_dir = 'include' - # make sure header and lib are valid - inc_path = os.path.join(self.vulkan_sdk, inc_dir) - header = os.path.join(inc_path, 'vulkan', 'vulkan.h') - lib_path = os.path.join(self.vulkan_sdk, lib_dir) - find_lib = self.clib_compiler.find_library(lib_name, environment, lib_path) + # make sure header and lib are valid + inc_path = os.path.join(self.vulkan_sdk, inc_dir) + header = os.path.join(inc_path, 'vulkan', 'vulkan.h') + lib_path = os.path.join(self.vulkan_sdk, lib_dir) + find_lib = self.clib_compiler.find_library(lib_name, environment, lib_path) - if not find_lib: - raise DependencyException('VULKAN_SDK point to invalid directory (no lib)') + if not find_lib: + raise DependencyException('VULKAN_SDK point to invalid directory (no lib)') - if not os.path.isfile(header): - raise DependencyException('VULKAN_SDK point to invalid directory (no include)') + if not os.path.isfile(header): + raise DependencyException('VULKAN_SDK point to invalid directory (no include)') - self.type_name = 'vulkan_sdk' - self.is_found = True - self.compile_args.append('-I' + inc_path) - self.link_args.append('-L' + lib_path) - self.link_args.append('-l' + lib_name) + self.type_name = 'vulkan_sdk' + self.is_found = True + self.compile_args.append('-I' + inc_path) + self.link_args.append('-L' + lib_path) + self.link_args.append('-l' + lib_name) - # 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) - self.version = '1' + # 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) + 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 - 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 def _factory(cls, environment, kwargs): - if DependencyMethods.PKGCONFIG in cls._process_method_kw(kwargs): - try: - pcdep = PkgConfigDependency('vulkan', environment, kwargs) - if pcdep.found(): - return pcdep - except Exception: - pass + methods = cls._process_method_kw(kwargs) + candidates = [] - return VulkanDependency(environment, kwargs) + if DependencyMethods.PKGCONFIG in methods: + candidates.append(functools.partial(PkgConfigDependency, 'vulkan', environment, kwargs)) + + if DependencyMethods.PKGCONFIG in methods: + candidates.append(functools.partial(VulkanDependency, environment, kwargs)) + + return candidates @staticmethod def get_methods(): From 01118ce2a45ec3111b29f2de70bc127b3400ebb2 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 1 Jun 2018 11:55:18 +0100 Subject: [PATCH 04/10] Add a finish_init callback to ConfigToolDependency() Give ConfigToolDependency() a finish_init callback, so that tool-specific initialization can be called from the constructor, rather than after construction in the factory class. v2: finalize -> finish_init for clarity --- mesonbuild/dependencies/base.py | 6 ++++-- mesonbuild/dependencies/misc.py | 38 +++++++++++++++++++-------------- mesonbuild/dependencies/ui.py | 10 +++++---- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index c34146f4e..6af11f011 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -297,6 +297,8 @@ class ConfigToolDependency(ExternalDependency): self.config = None return self.version = version + if getattr(self, 'finish_init', None): + self.finish_init(self) def _sanitize_version(self, version): """Remove any non-numeric, non-point version suffixes.""" @@ -308,7 +310,7 @@ class ConfigToolDependency(ExternalDependency): return version @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. In addition to the standard constructor values, this constructor sets @@ -323,7 +325,7 @@ class ConfigToolDependency(ExternalDependency): def reduce(self): return (cls._unpickle, (), self.__dict__) 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) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 607643352..bf6018612 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -444,15 +444,19 @@ class PcapDependency(ExternalDependency): if DependencyMethods.CONFIG_TOOL in methods: candidates.append(functools.partial(ConfigToolDependency.factory, - 'pcap', environment, None, kwargs, ['pcap-config'], 'pcap-config')) -# if ctdep.found(): -# ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') -# ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args') -# ctdep.version = cls.get_pcap_lib_version(ctdep) -# return ctdep + 'pcap', environment, None, + kwargs, ['pcap-config'], + 'pcap-config', + PcapDependency.tool_finish_init)) 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') + ctdep.version = PcapDependency.get_pcap_lib_version(ctdep) + @staticmethod def get_methods(): return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] @@ -479,10 +483,7 @@ class CupsDependency(ExternalDependency): candidates.append(functools.partial(ConfigToolDependency.factory, 'cups', environment, None, kwargs, ['cups-config'], - 'cups-config')) -# if ctdep.found(): -# ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') -# ctdep.link_args = ctdep.get_config_value(['--ldflags', '--libs'], 'link_args') + 'cups-config', CupsDependency.tool_finish_init)) if DependencyMethods.EXTRAFRAMEWORK in methods: if mesonlib.is_osx(): @@ -492,6 +493,11 @@ class CupsDependency(ExternalDependency): 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 def get_methods(): if mesonlib.is_osx(): @@ -514,15 +520,15 @@ class LibWmfDependency(ExternalDependency): if DependencyMethods.CONFIG_TOOL in methods: candidates.append(functools.partial(ConfigToolDependency.factory, - '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 + 'libwmf', environment, None, kwargs, ['libwmf-config'], 'libwmf-config', LibWmfDependency.tool_finish_init)) 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 def get_methods(): return [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL] diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index e25d135b7..ca7db3fef 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -464,10 +464,7 @@ class SDL2Dependency(ExternalDependency): candidates.append(functools.partial(ConfigToolDependency.factory, 'sdl2', environment, None, kwargs, ['sdl2-config'], - 'sdl2-config')) -# if ctdep.found(): -# ctdep.compile_args = ctdep.get_config_value(['--cflags'], 'compile_args') -# ctdep.link_args = ctdep.get_config_value(['--libs'], 'link_args') + 'sdl2-config', SDL2Dependency.tool_finish_init)) if DependencyMethods.EXTRAFRAMEWORK in methods: if mesonlib.is_osx(): @@ -477,6 +474,11 @@ class SDL2Dependency(ExternalDependency): # fwdep.version = '2' # FIXME 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 def get_methods(): if mesonlib.is_osx(): From 3576623b0f46dab27fbb243f6d5595916187642f Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 1 Jun 2018 01:27:40 +0100 Subject: [PATCH 05/10] Consolidate raising a DependencyException() if required but not-found This is now done by find_external_dependency() in all cases I can't help but think this perhaps should be in a few more places... --- mesonbuild/dependencies/base.py | 19 +++---------------- mesonbuild/dependencies/misc.py | 3 --- mesonbuild/dependencies/ui.py | 4 ---- 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 6af11f011..e3faacd63 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -392,8 +392,6 @@ class ConfigToolDependency(ExternalDependency): mlog.log('Found', mlog.bold(self.tool_name), repr(req_version), 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 mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)), '({})'.format(version)) @@ -475,9 +473,6 @@ class PkgConfigDependency(ExternalDependency): '{!r}'.format(name, self.pkgbin.get_path())) ret, self.version = self._call_pkgbin(['--modversion', name]) if ret != 0: - if self.required: - raise DependencyException('{} dependency {!r} not found' - ''.format(self.type_string, name)) return found_msg = [self.type_string + ' dependency', mlog.bold(name), 'found:'] if self.version_reqs is None: @@ -826,8 +821,6 @@ class DubDependency(ExternalDependency): ret, res = self._call_dubbin(['describe', name]) if ret != 0: - if self.required: - raise DependencyException('Dependency {!r} not found'.format(name)) self.is_found = False mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return @@ -840,8 +833,6 @@ class DubDependency(ExternalDependency): msg = ['Dependency', mlog.bold(name), 'found but it was compiled with'] msg += [mlog.bold(j['compiler']), 'and we are using', mlog.bold(comp)] mlog.error(*msg) - if self.required: - raise DependencyException('Dependency {!r} not found'.format(name)) self.is_found = False mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return @@ -897,11 +888,9 @@ class DubDependency(ExternalDependency): self.link_args.append(file) if not found: - if self.required: - raise DependencyException('Dependency {!r} not found'.format(name)) - self.is_found = False - mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) - return + self.is_found = False + mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) + return if not self.silent: mlog.log(*found_msg) @@ -1249,8 +1238,6 @@ class ExtraFrameworkDependency(ExternalDependency): self.name = d self.is_found = True return - if not self.found() and self.required: - raise DependencyException('Framework dependency %s not found.' % (name, )) def get_version(self): return 'unknown' diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index bf6018612..389157a3f 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -38,7 +38,6 @@ class MPIDependency(ExternalDependency): def __init__(self, environment, kwargs): language = kwargs.get('language', 'c') super().__init__('mpi', environment, language, kwargs) - required = kwargs.pop('required', True) kwargs['required'] = False kwargs['silent'] = True self.is_found = False @@ -108,8 +107,6 @@ class MPIDependency(ExternalDependency): 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): """ diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index ca7db3fef..904c37f44 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -227,10 +227,6 @@ class QtBaseDependency(ExternalDependency): self.link_args = [] from_text = '(checked {})'.format(mlog.format_list(methods)) 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 f2673d9b57d0134c293e7acf5af5a0b3364523fb Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 18 May 2018 20:50:03 +0100 Subject: [PATCH 06/10] 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(). --- mesonbuild/dependencies/base.py | 97 ++++++++++++++++---------------- mesonbuild/dependencies/boost.py | 20 ++----- mesonbuild/dependencies/dev.py | 39 ++++++++++--- mesonbuild/dependencies/misc.py | 13 ----- mesonbuild/dependencies/ui.py | 26 +++++---- 5 files changed, 98 insertions(+), 97 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index e3faacd63..8fdc10e30 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -266,6 +266,15 @@ class ExternalDependency(Dependency): return new + def log_details(self): + return '' + + def log_info(self): + return '' + + def log_tried(self): + return '' + class NotFoundDependency(Dependency): def __init__(self, environment): @@ -391,11 +400,9 @@ class ConfigToolDependency(ExternalDependency): else: mlog.log('Found', mlog.bold(self.tool_name), repr(req_version), mlog.red('NO')) - mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.red('NO')) return False mlog.log('Found {}:'.format(self.tool_name), mlog.bold(shutil.which(self.config)), '({})'.format(version)) - mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES')) return True def get_config_value(self, args, stage): @@ -423,6 +430,9 @@ class ConfigToolDependency(ExternalDependency): mlog.debug('Got config-tool variable {} : {}'.format(variable_name, variable)) return variable + def log_tried(self): + return self.type_name + class PkgConfigDependency(ExternalDependency): # 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: raise DependencyException('Pkg-config not found.') return - if self.want_cross: - self.type_string = 'Cross' - else: - self.type_string = 'Native' mlog.debug('Determining dependency {!r} with pkg-config executable ' '{!r}'.format(name, self.pkgbin.get_path())) ret, self.version = self._call_pkgbin(['--modversion', name]) if ret != 0: return - found_msg = [self.type_string + ' dependency', mlog.bold(name), 'found:'] if self.version_reqs is None: self.is_found = True else: @@ -485,14 +490,6 @@ class PkgConfigDependency(ExternalDependency): (self.is_found, not_found, found) = \ version_compare_many(self.version, self.version_reqs) 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: m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' raise DependencyException(m.format(name, not_found, self.version)) @@ -503,7 +500,6 @@ class PkgConfigDependency(ExternalDependency): self._set_cargs() # Fetch the libraries and library paths needed for using this self._set_libs() - found_msg += [mlog.green('YES'), self.version] except DependencyException as e: if self.required: raise @@ -511,12 +507,7 @@ class PkgConfigDependency(ExternalDependency): self.compile_args = [] self.link_args = [] self.is_found = False - found_msg += [mlog.red('NO'), '; reason: {}'.format(str(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) + self.reason = e def __repr__(self): s = '<{0} {1}: {2} {3}>' @@ -705,8 +696,8 @@ class PkgConfigDependency(ExternalDependency): variable = '' if ret != 0: if self.required: - raise DependencyException('%s dependency %s not found.' % - (self.type_string, self.name)) + raise DependencyException('dependency %s not found.' % + (self.name)) else: variable = out.strip() @@ -790,6 +781,9 @@ class PkgConfigDependency(ExternalDependency): # a path rather than the raw dlname return os.path.basename(dlname) + def log_tried(self): + return self.type_name + class DubDependency(ExternalDependency): class_dubbin = None @@ -811,7 +805,6 @@ class DubDependency(ExternalDependency): if self.required: raise DependencyException('DUB not found.') self.is_found = False - mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return mlog.debug('Determining dependency {!r} with DUB executable ' @@ -822,7 +815,6 @@ class DubDependency(ExternalDependency): if ret != 0: self.is_found = False - mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return j = json.loads(res) @@ -834,7 +826,6 @@ class DubDependency(ExternalDependency): msg += [mlog.bold(j['compiler']), 'and we are using', mlog.bold(comp)] mlog.error(*msg) self.is_found = False - mlog.log('Dependency', mlog.bold(name), 'found:', mlog.red('NO')) return self.version = package['version'] @@ -842,7 +833,6 @@ class DubDependency(ExternalDependency): break # Check if package version meets the requirements - found_msg = ['Dependency', mlog.bold(name), 'found:'] if self.version_reqs is None: self.is_found = True else: @@ -853,21 +843,11 @@ class DubDependency(ExternalDependency): (self.is_found, not_found, found) = \ version_compare_many(self.version, self.version_reqs) 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: m = 'Invalid version of dependency, need {!r} {!r} found {!r}.' raise DependencyException(m.format(name, not_found, self.version)) return - found_msg += [mlog.green('YES'), self.version] - if self.pkg['targetFileName'].endswith('.a'): self.static = True @@ -889,12 +869,8 @@ class DubDependency(ExternalDependency): if not found: 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): return self.compiler @@ -1216,10 +1192,6 @@ class ExtraFrameworkDependency(ExternalDependency): if self.found(): self.compile_args = ['-I' + os.path.join(self.path, self.name, 'Headers')] 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): lname = name.lower() @@ -1242,6 +1214,12 @@ class ExtraFrameworkDependency(ExternalDependency): def get_version(self): 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): # 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 pkgdep = [] + details = '' + for c in candidates: # try this dependency method try: @@ -1288,11 +1268,33 @@ def find_external_dependency(name, env, kwargs): 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('Dependency', mlog.bold(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('Dependency', mlog.bold(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) @@ -1301,8 +1303,7 @@ def find_external_dependency(name, env, kwargs): # we have a list of failed ExternalDependency objects, so we can report # 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_methods)) + raise DependencyException('Dependency "%s" not found, tried %s' % (name, tried)) # return the last failed dependency object if pkgdep: diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 7acde2dc1..17f92400f 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -132,7 +132,6 @@ class BoostDependency(ExternalDependency): self.incdir = self.detect_nix_incdir() if self.check_invalid_modules(): - self.log_fail() return mlog.debug('Boost library root dir is', mlog.bold(self.boost_root)) @@ -146,12 +145,6 @@ class BoostDependency(ExternalDependency): self.detect_lib_modules() 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): invalid_modules = [c for c in self.requested_modules if 'boost_' + c not in BOOST_LIBS] @@ -172,17 +165,14 @@ class BoostDependency(ExternalDependency): else: return False - def log_fail(self): + def log_details(self): module_str = ', '.join(self.requested_modules) - mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) + return module_str - def log_success(self): - module_str = ', '.join(self.requested_modules) + def log_info(self): if self.boost_root: - info = self.version + ', ' + self.boost_root - else: - info = self.version - mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info) + return self.boost_root + return '' def detect_nix_roots(self): return [os.path.abspath(os.path.join(x, '..')) diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 4ea338575..0cd3c2bcb 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -45,7 +45,7 @@ class GTestDependency(ExternalDependency): if self.main: self.link_args += gtest_main_detect self.sources = [] - mlog.log('Dependency GTest found:', mlog.green('YES'), '(prebuilt)') + self.prebuilt = True elif self.detect_srcdir(): self.is_found = True 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] else: self.sources = [self.all_src] - mlog.log('Dependency GTest found:', mlog.green('YES'), '(building self)') + self.prebuilt = False else: - mlog.log('Dependency GTest found:', mlog.red('NO')) self.is_found = False def detect_srcdir(self): @@ -76,6 +75,12 @@ class GTestDependency(ExternalDependency): def need_threads(self): return True + def log_info(self): + if self.prebuilt: + return 'prebuilt' + else: + return 'building self' + class GMockDependency(ExternalDependency): def __init__(self, environment, kwargs): @@ -89,7 +94,7 @@ class GMockDependency(ExternalDependency): self.compile_args = [] self.link_args = gmock_detect self.sources = [] - mlog.log('Dependency GMock found:', mlog.green('YES'), '(prebuilt)') + self.prebuilt = True return 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] else: self.sources = [all_src] - mlog.log('Dependency GMock found:', mlog.green('YES'), '(building self)') + self.prebuilt = False return - mlog.log('Dependency GMock found:', mlog.red('NO')) + self.is_found = False + def log_info(self): + if self.prebuilt: + return 'prebuilt' + else: + return 'building self' + class LLVMDependency(ConfigToolDependency): """ @@ -145,6 +156,7 @@ class LLVMDependency(ConfigToolDependency): super().__init__('LLVM', environment, 'cpp', kwargs) self.provided_modules = [] self.required_modules = set() + self.module_details = [] if not self.is_found: return self.static = kwargs.get('static', False) @@ -237,21 +249,30 @@ class LLVMDependency(ConfigToolDependency): is required. """ for mod in sorted(set(modules)): + status = '' + 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: self.is_found = False if self.required: raise DependencyException( 'Could not find required LLVM Component: {}'.format(mod)) + status = '(missing)' + else: + status = '(missing but optional)' else: 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): return True + def log_details(self): + if self.module_details: + return 'modules: ' + ', '.join(self.module_details) + return '' + class ValgrindDependency(PkgConfigDependency): ''' diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 389157a3f..78ce51b67 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -103,11 +103,6 @@ class MPIDependency(ExternalDependency): self.is_found = True 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): """ MPI wrappers return a bunch of garbage args. @@ -265,10 +260,6 @@ class OpenMPDependency(ExternalDependency): self.is_found = True else: 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): return True @@ -324,10 +315,6 @@ class Python3Dependency(ExternalDependency): self.compile_args = fw.get_compile_args() self.link_args = fw.get_link_args() 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 def get_windows_python_arch(): diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 904c37f44..c877f510c 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -204,12 +204,10 @@ class QtBaseDependency(ExternalDependency): self.bindir = None self.private_headers = kwargs.get('private_headers', False) mods = extract_as_list(kwargs, 'modules') + self.requested_modules = mods if not mods: raise DependencyException('No ' + self.qtname + ' modules specified.') - type_text = 'cross' if env.is_cross_build() else 'native' - found_msg = '{} {} {{}} dependency (modules: {}) found:' \ - ''.format(self.qtname, type_text, ', '.join(mods)) - from_text = 'pkg-config' + self.from_text = 'pkg-config' # Keep track of the detection methods used, for logging purposes. methods = [] @@ -218,21 +216,15 @@ class QtBaseDependency(ExternalDependency): self._pkgconfig_detect(mods, kwargs) methods.append('pkgconfig') 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') if not self.is_found: # Reset compile args and link args self.compile_args = [] self.link_args = [] - from_text = '(checked {})'.format(mlog.format_list(methods)) + self.from_text = mlog.format_list(methods) 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): "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): 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): def __init__(self, env, kwargs): From b744d56fc7ee7ec7ca738489f694fdc5b719d3a2 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 1 Jun 2018 12:08:07 +0100 Subject: [PATCH 07/10] Restore and improve cross/native dependency type reporting If we aren't cross-building, this distinction isn't very interesting (Most dependencies didn't bother reporting this. pkgconfig did it unconditionally, and Qt reported as 'native' or 'cross' depending on is_cross_build(), i.e. ignoring the native: keyword) --- mesonbuild/dependencies/base.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 8fdc10e30..c44f6e397 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1250,6 +1250,13 @@ def find_external_dependency(name, env, kwargs): if name.lower() not in _packages_accept_language and 'language' in kwargs: raise DependencyException('%s dependency does not accept "language" keyword argument' % (name, )) + # 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) @@ -1281,7 +1288,7 @@ def find_external_dependency(name, env, kwargs): if info: info = ', ' + info - mlog.log('Dependency', mlog.bold(name), details + 'found:', mlog.green('YES'), d.version + info) + mlog.log(type_text, mlog.bold(name), details + 'found:', mlog.green('YES'), d.version + info) return d @@ -1292,7 +1299,7 @@ def find_external_dependency(name, env, kwargs): else: tried = '' - mlog.log('Dependency', mlog.bold(name), details + 'found:', mlog.red('NO'), + mlog.log(type_text, mlog.bold(name), details + 'found:', mlog.red('NO'), '(tried {})'.format(tried) if tried else '') if required: From f6b3567fcced39acf81bace8df616cf7035f1a69 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 1 Jun 2018 14:27:06 +0100 Subject: [PATCH 08/10] Update a unit test which relies on specific dependency check output --- run_unittests.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/run_unittests.py b/run_unittests.py index 7c8d230ed..dee108636 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -2939,11 +2939,12 @@ class LinuxlikeTests(BasePlatformTests): raise unittest.SkipTest('Qt not found with pkg-config') testdir = os.path.join(self.framework_test_dir, '4 qt') self.init(testdir, ['-Dmethod=pkg-config']) - # Confirm that the dependency was found with qmake - msg = 'Qt4 native `pkg-config` dependency (modules: Core, Gui) found: YES\n' - msg2 = 'Qt5 native `pkg-config` dependency (modules: Core, Gui) found: YES\n' + # Confirm that the dependency was found with pkg-config 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): ''' @@ -2961,10 +2962,9 @@ class LinuxlikeTests(BasePlatformTests): testdir = os.path.join(self.framework_test_dir, '4 qt') self.init(testdir, ['-Dmethod=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() - 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): if is_cygwin() or is_osx(): From 60b66a7752a2cec734ede6fde251df389097ad57 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 1 Jun 2018 15:04:56 +0100 Subject: [PATCH 09/10] Restore and improve displaying dependency name with correct casing Display dependency name with the correct casing, for the (extended) list of dependencies we have a preferred casing for. --- mesonbuild/dependencies/base.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index c44f6e397..a86ccf2b6 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1240,6 +1240,16 @@ def get_dep_identifier(name, kwargs, want_cross): identifier += (key, value) 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): required = kwargs.get('required', True) @@ -1247,9 +1257,13 @@ def find_external_dependency(name, env, kwargs): raise DependencyException('Keyword "required" must be a boolean.') if not isinstance(kwargs.get('method', ''), str): raise DependencyException('Keyword "method" must be a string.') - if name.lower() not in _packages_accept_language and 'language' in kwargs: + 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' @@ -1288,7 +1302,7 @@ def find_external_dependency(name, env, kwargs): if info: info = ', ' + info - mlog.log(type_text, mlog.bold(name), details + 'found:', mlog.green('YES'), d.version + info) + mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.green('YES'), d.version + info) return d @@ -1299,7 +1313,7 @@ def find_external_dependency(name, env, kwargs): else: tried = '' - mlog.log(type_text, mlog.bold(name), details + 'found:', mlog.red('NO'), + mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.red('NO'), '(tried {})'.format(tried) if tried else '') if required: From c3335615e242fdb2a7bdf814d6e6ee0d564f5423 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Sun, 24 Jun 2018 12:18:51 +0100 Subject: [PATCH 10/10] Assert name isn't the empty string in find_external_dependency() Invariant since 87e62012 --- mesonbuild/dependencies/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index a86ccf2b6..6021ddd4c 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -1252,6 +1252,7 @@ display_name_map = { } def find_external_dependency(name, env, kwargs): + assert(name) required = kwargs.get('required', True) if not isinstance(required, bool): raise DependencyException('Keyword "required" must be a boolean.')