diff options
-rw-r--r-- | .appveyor.yml | 11 | ||||
-rw-r--r-- | docs/markdown/Reference-tables.md | 1 | ||||
-rw-r--r-- | mesonbuild/compilers/c.py | 11 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 3 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 253 | ||||
-rw-r--r-- | mesonbuild/dependencies/boost.py | 20 | ||||
-rw-r--r-- | mesonbuild/dependencies/dev.py | 39 | ||||
-rw-r--r-- | mesonbuild/dependencies/misc.py | 130 | ||||
-rw-r--r-- | mesonbuild/dependencies/ui.py | 231 | ||||
-rw-r--r-- | mesonbuild/environment.py | 9 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 6 | ||||
-rw-r--r-- | mesonbuild/interpreterbase.py | 5 | ||||
-rw-r--r-- | mesonbuild/mtest.py | 14 | ||||
-rwxr-xr-x | run_unittests.py | 49 | ||||
-rw-r--r-- | test cases/common/38 run program/get-version.py | 3 | ||||
-rw-r--r-- | test cases/common/38 run program/meson.build | 2 |
16 files changed, 431 insertions, 356 deletions
diff --git a/.appveyor.yml b/.appveyor.yml index 6461831..c8e601e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -17,14 +17,6 @@ environment: backend: ninja - arch: x86 - compiler: msvc2010 - backend: ninja - - - arch: x86 - compiler: msvc2010 - backend: vs2010 - - - arch: x86 compiler: msvc2015 backend: ninja BOOST_ROOT: C:\Libraries\Boost_1_60_0 @@ -57,7 +49,7 @@ branches: init: - ps: | - If($Env:compiler -like 'msvc2010') { + If($Env:compiler -like 'msvc2015') { Set-WinSystemLocale de-DE Start-Sleep -s 5 Restart-Computer @@ -98,7 +90,6 @@ install: - cmd: if %compiler%==msvc2017 ( if %arch%==x86 ( set "PATH=%PATH%;%BOOST_ROOT%\lib32-msvc-14.1" ) else ( set "PATH=%PATH%;%BOOST_ROOT%\lib64-msvc-14.1" ) ) # Set paths and config for each build type. - - cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% ) - cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% ) - cmd: if %compiler%==msvc2017 ( call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat" -arch=%arch% ) - cmd: if %compiler%==cygwin ( set PYTHON=python3 ) else ( set PYTHON=python ) diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index 989e649..9aa8609 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -57,6 +57,7 @@ set in the cross file. | riscv64 | 64 bit RISC-V Open ISA| | sparc | 32 bit SPARC | | sparc64 | SPARC v9 processor | +| s390x | IBM zSystem s390x | Any cpu family not listed in the above list is not guaranteed to remain stable in future releases. diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 2530adf..2dfe794 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -47,11 +47,14 @@ from .compilers import ( RunResult, ) +gnu_compiler_internal_libs = ('m', 'c', 'pthread', 'dl', 'rt') + class CCompiler(Compiler): library_dirs_cache = {} program_dirs_cache = {} find_library_cache = {} + internal_libs = gnu_compiler_internal_libs def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwargs): # If a child ObjC or CPP class has already set it, don't set it ourselves @@ -905,10 +908,13 @@ class CCompiler(Compiler): # First try if we can just add the library as -l. # Gcc + co seem to prefer builtin lib dirs to -L dirs. # Only try to find std libs if no extra dirs specified. - if not extra_dirs: + if not extra_dirs or libname in self.internal_libs: args = ['-l' + libname] if self.links(code, env, extra_args=args): return args + # Don't do a manual search for internal libs + if libname in self.internal_libs: + return None # Not found or we want to use a specific libtype? Try to find the # library file itself. patterns = self.get_library_naming(env, libtype) @@ -1188,7 +1194,8 @@ class IntelCCompiler(IntelCompiler, CCompiler): class VisualStudioCCompiler(CCompiler): std_warn_args = ['/W3'] std_opt_args = ['/O2'] - ignore_libs = ('m', 'c', 'pthread') + ignore_libs = gnu_compiler_internal_libs + internal_libs = () def __init__(self, exelist, version, is_cross, exe_wrap, is_64): CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index b62bc4a..ea0fc2c 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -669,6 +669,9 @@ class Compiler: # Libraries to ignore in find_library() since they are provided by the # compiler or the C library. Currently only used for MSVC. ignore_libs = () + # Libraries that are internal compiler implementations, and must not be + # manually searched. + internal_libs = () # Cache for the result of compiler checks which can be cached compiler_check_cache = {} diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index b9a6c6f..c4f9630 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 @@ -265,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): @@ -296,6 +306,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.""" @@ -307,7 +319,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 @@ -322,7 +334,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) @@ -388,13 +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')) - 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)) - mlog.log('Dependency', mlog.bold(self.name), 'found:', mlog.green('YES')) return True def get_config_value(self, args, stage): @@ -422,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 @@ -463,20 +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: - 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: self.is_found = True else: @@ -487,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)) @@ -505,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 @@ -513,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}>' @@ -623,12 +612,16 @@ class PkgConfigDependency(ExternalDependency): # arguments as-is and then adding the libpaths at the end. else: args = None - if args: + if args is not None: libs_found.add(lib) # Replace -l arg with full path to library if available - # else, library is provided by the compiler and can't be resolved - if not args[0].startswith('-l'): - lib = args[0] + # else, library is either to be ignored, or is provided by + # the compiler, can't be resolved, and should be used as-is + if args: + if not args[0].startswith('-l'): + lib = args[0] + else: + continue else: # Library wasn't found, maybe we're looking in the wrong # places or the library will be provided with LDFLAGS or @@ -708,8 +701,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() @@ -793,6 +786,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 @@ -814,7 +810,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 ' @@ -824,10 +819,7 @@ 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 j = json.loads(res) @@ -838,10 +830,7 @@ 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 self.version = package['version'] @@ -849,7 +838,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: @@ -860,21 +848,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 @@ -895,14 +873,8 @@ 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 - - if not self.silent: - mlog.log(*found_msg) + self.is_found = False + return def get_compiler(self): return self.compiler @@ -948,7 +920,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') @@ -1225,10 +1197,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() @@ -1247,12 +1215,16 @@ 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' + 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 @@ -1273,54 +1245,131 @@ 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): + assert(name) required = kwargs.get('required', True) if not isinstance(required, bool): 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', '') + 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() 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/boost.py b/mesonbuild/dependencies/boost.py index 7acde2d..17f9240 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 4ea3385..0cd3c2b 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 745dff0..78ce51b 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 @@ -37,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 @@ -103,13 +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')) - if required: - raise DependencyException('MPI dependency {!r} not found'.format(self.name)) - def _filter_compile_args(self, args): """ MPI wrappers return a bunch of garbage args. @@ -267,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 @@ -326,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(): @@ -436,33 +421,29 @@ 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', + 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(): - 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): @@ -477,32 +458,29 @@ 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', CupsDependency.tool_finish_init)) + 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 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(): @@ -519,30 +497,22 @@ 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)) + candidates.append(functools.partial(ConfigToolDependency.factory, + 'libwmf', environment, None, kwargs, ['libwmf-config'], 'libwmf-config', LibWmfDependency.tool_finish_init)) - 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 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] diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 197d22c..c877f51 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(): @@ -201,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 = [] @@ -215,25 +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 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): "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): 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): @@ -452,33 +453,29 @@ 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', SDL2Dependency.tool_finish_init)) + 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')) + candidates.append(functools.partial(ExtraFrameworkDependency, + 'sdl2', False, None, environment, + kwargs.get('language', None), kwargs)) + # fwdep.version = '2' # FIXME + return candidates - 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 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 = [] + + if DependencyMethods.PKGCONFIG in methods: + candidates.append(functools.partial(PkgConfigDependency, 'vulkan', environment, kwargs)) - return VulkanDependency(environment, kwargs) + if DependencyMethods.PKGCONFIG in methods: + candidates.append(functools.partial(VulkanDependency, environment, kwargs)) + + return candidates @staticmethod def get_methods(): diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index 099e5b9..6688c62 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -86,6 +86,7 @@ known_cpu_families = ( 'ppc64', 'riscv32', 'riscv64', + 's390x', 'sparc', 'sparc64', 'x86', @@ -983,12 +984,10 @@ class CrossBuildInfo: def __init__(self, filename): self.config = {'properties': {}} self.parse_datafile(filename) - if 'target_machine' in self.config: - return - if 'host_machine' not in self.config: + if 'host_machine' not in self.config and 'target_machine' not in self.config: raise mesonlib.MesonException('Cross info file must have either host or a target machine.') - if 'binaries' not in self.config: - raise mesonlib.MesonException('Cross file is missing "binaries".') + if 'host_machine' in self.config and 'binaries' not in self.config: + raise mesonlib.MesonException('Cross file with "host_machine" is missing "binaries".') def ok_type(self, i): return isinstance(i, (str, int, bool)) diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index c02201e..1cf20f8 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -3098,7 +3098,7 @@ root and issuing %s. regex_selector] + vcs_cmd kwargs.setdefault('build_by_default', True) kwargs.setdefault('build_always_stale', True) - return self.func_custom_target(node, [kwargs['output']], kwargs) + return self._func_custom_target_impl(node, [kwargs['output']], kwargs) @FeatureNew('subdir_done', '0.46.0') @stringArgs @@ -3119,6 +3119,10 @@ root and issuing %s. raise InterpreterException('custom_target: Only one positional argument is allowed, and it must be a string name') if 'depfile' in kwargs and ('@BASENAME@' in kwargs['depfile'] or '@PLAINNAME@' in kwargs['depfile']): FeatureNew('substitutions in custom_target depfile', '0.47.0').use(self.subproject) + return self._func_custom_target_impl(node, args, kwargs) + + def _func_custom_target_impl(self, node, args, kwargs): + 'Implementation-only, without FeatureNew checks, for internal use' name = args[0] kwargs['install_mode'] = self._get_kwarg_install_mode(kwargs) tg = CustomTargetHolder(build.CustomTarget(name, self.subdir, self.subproject, kwargs), self) diff --git a/mesonbuild/interpreterbase.py b/mesonbuild/interpreterbase.py index 64177ab..fd732bc 100644 --- a/mesonbuild/interpreterbase.py +++ b/mesonbuild/interpreterbase.py @@ -172,6 +172,9 @@ class FeatureCheckBase: @staticmethod def get_target_version(subproject): + # Don't do any checks if project() has not been parsed yet + if subproject not in mesonlib.project_meson_versions: + return '' return mesonlib.project_meson_versions[subproject] def use(self, subproject): @@ -225,7 +228,7 @@ class FeatureNew(FeatureCheckBase): @staticmethod def get_warning_str_prefix(tv): - return 'Project specifies a minimum meson_version \'{}\' which conflicts with:'.format(tv) + return 'Project specifies a minimum meson_version \'{}\' but uses features which were added in newer versions:'.format(tv) def log_usage_warning(self, tv): mlog.warning('Project targetting \'{}\' but tried to use feature introduced ' diff --git a/mesonbuild/mtest.py b/mesonbuild/mtest.py index 8ebef04..3d3d2f5 100644 --- a/mesonbuild/mtest.py +++ b/mesonbuild/mtest.py @@ -20,7 +20,7 @@ import pickle from mesonbuild import build from mesonbuild import environment from mesonbuild.dependencies import ExternalProgram -from mesonbuild import mesonlib +from mesonbuild.mesonlib import substring_is_in_list, MesonException from mesonbuild import mlog import time, datetime, multiprocessing, json @@ -130,8 +130,11 @@ def returncode_to_status(retcode): signame = 'SIGinvalid' return '(exit status %d or signal %d %s)' % (retcode, signum, signame) +def env_tuple_to_str(env): + return ''.join(["%s='%s' " % (k, v) for k, v in env]) -class TestException(mesonlib.MesonException): + +class TestException(MesonException): pass @@ -162,7 +165,8 @@ class TestRun: if self.cmd is None: res += 'NONE\n' else: - res += '%s%s\n' % (''.join(["%s='%s' " % (k, v) for k, v in self.env.items()]), ' ' .join(self.cmd)) + test_only_env = set(self.env.items()) - set(os.environ.items()) + res += '{}{}\n'.format(env_tuple_to_str(test_only_env), ' '.join(self.cmd)) if self.stdo: res += '--- stdout ---\n' res += self.stdo @@ -266,7 +270,7 @@ class SingleTestRunner: if len(self.test.extra_paths) > 0: self.env['PATH'] = os.pathsep.join(self.test.extra_paths + ['']) + self.env['PATH'] - if mesonlib.substring_is_in_list('wine', cmd): + if substring_is_in_list('wine', cmd): wine_paths = ['Z:' + p for p in self.test.extra_paths] wine_path = ';'.join(wine_paths) # Don't accidentally end with an `;` because that will add the @@ -605,6 +609,8 @@ TIMEOUT: %4d self.logfile.write('Log of Meson test suite run on %s\n\n' % datetime.datetime.now().isoformat()) + inherit_env = env_tuple_to_str(os.environ.items()) + self.logfile.write('Inherited environment: {}\n\n'.format(inherit_env)) @staticmethod def get_wrapper(options): diff --git a/run_unittests.py b/run_unittests.py index e0f2fe5..45b48f3 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -51,11 +51,15 @@ from run_tests import get_builddir_target_args, get_backend_commands, Backend from run_tests import ensure_backend_detects_changes, run_configure_inprocess from run_tests import run_mtest_inprocess -# Fake class for mocking +# Fake classes for mocking class FakeBuild: def __init__(self, env): self.environment = env +class FakeCompilerOptions: + def __init__(self): + self.value = [] + def get_dynamic_section_entry(fname, entry): if is_cygwin() or is_osx(): raise unittest.SkipTest('Test only applicable to ELF platforms') @@ -605,6 +609,7 @@ class InternalTests(unittest.TestCase): env = Environment('', '', get_fake_options('')) compiler = env.detect_c_compiler(False) env.coredata.compilers = {'c': compiler} + env.coredata.compiler_options['c_link_args'] = FakeCompilerOptions() p1 = Path(tmpdir) / '1' p2 = Path(tmpdir) / '2' p1.mkdir() @@ -614,6 +619,12 @@ class InternalTests(unittest.TestCase): # libbar.a is in both prefixes (p1 / 'libbar.a').open('w').close() (p2 / 'libbar.a').open('w').close() + # Ensure that we never statically link to these + (p1 / 'libpthread.a').open('w').close() + (p1 / 'libm.a').open('w').close() + (p1 / 'libc.a').open('w').close() + (p1 / 'libdl.a').open('w').close() + (p1 / 'librt.a').open('w').close() def fake_call_pkgbin(self, args, env=None): if '--libs' not in args: @@ -622,6 +633,8 @@ class InternalTests(unittest.TestCase): return 0, '-L{} -lfoo -L{} -lbar'.format(p1.as_posix(), p2.as_posix()) if args[0] == 'bar': return 0, '-L{} -lbar'.format(p2.as_posix()) + if args[0] == 'internal': + return 0, '-L{} -lpthread -lm -lc -lrt -ldl'.format(p1.as_posix()) old_call = PkgConfigDependency._call_pkgbin old_check = PkgConfigDependency.check_pkgconfig @@ -634,6 +647,14 @@ class InternalTests(unittest.TestCase): [(p1 / 'libfoo.a').as_posix(), (p2 / 'libbar.a').as_posix()]) bar_dep = PkgConfigDependency('bar', env, kwargs) self.assertEqual(bar_dep.get_link_args(), [(p2 / 'libbar.a').as_posix()]) + internal_dep = PkgConfigDependency('internal', env, kwargs) + if compiler.get_id() == 'msvc': + self.assertEqual(internal_dep.get_link_args(), []) + else: + link_args = internal_dep.get_link_args() + for link_arg in link_args: + for lib in ('pthread', 'm', 'c', 'dl', 'rt'): + self.assertNotIn('lib{}.a'.format(lib), link_arg, msg=link_args) # Test ends PkgConfigDependency._call_pkgbin = old_call PkgConfigDependency.check_pkgconfig = old_check @@ -2740,6 +2761,16 @@ class FailureTests(BasePlatformTests): ".*WARNING.*Project targetting.*but.*", meson_version='>= 0.41.0') + def test_vcs_tag_featurenew_build_always_stale(self): + 'https://github.com/mesonbuild/meson/issues/3904' + vcs_tag = '''version_data = configuration_data() + version_data.set('PROJVER', '@VCS_TAG@') + vf = configure_file(output : 'version.h.in', configuration: version_data) + f = vcs_tag(input : vf, output : 'version.h') + ''' + msg = '.*WARNING:.*feature.*build_always_stale.*custom_target.*' + self.assertMesonDoesNotOutput(vcs_tag, msg, meson_version='>=0.43') + class WindowsTests(BasePlatformTests): ''' @@ -2797,7 +2828,7 @@ class WindowsTests(BasePlatformTests): if cc.id != 'msvc': raise unittest.SkipTest('Not using MSVC') # To force people to update this test, and also test - self.assertEqual(set(cc.ignore_libs), {'c', 'm', 'pthread'}) + self.assertEqual(set(cc.ignore_libs), {'c', 'm', 'pthread', 'dl', 'rt'}) for l in cc.ignore_libs: self.assertEqual(cc.find_library(l, env, []), []) @@ -3004,11 +3035,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): ''' @@ -3026,10 +3058,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(): diff --git a/test cases/common/38 run program/get-version.py b/test cases/common/38 run program/get-version.py new file mode 100644 index 0000000..a22d559 --- /dev/null +++ b/test cases/common/38 run program/get-version.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 + +print('1.2') diff --git a/test cases/common/38 run program/meson.build b/test cases/common/38 run program/meson.build index ab800ef..a05cea3 100644 --- a/test cases/common/38 run program/meson.build +++ b/test cases/common/38 run program/meson.build @@ -1,4 +1,4 @@ -project('run command', 'c') +project('run command', version : run_command('get-version.py', check : true).stdout().strip()) if build_machine.system() == 'windows' c = run_command('cmd', '/c', 'echo', 'hello') |