aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.appveyor.yml11
-rw-r--r--docs/markdown/Reference-tables.md1
-rw-r--r--mesonbuild/compilers/c.py11
-rw-r--r--mesonbuild/compilers/compilers.py3
-rw-r--r--mesonbuild/dependencies/base.py253
-rw-r--r--mesonbuild/dependencies/boost.py20
-rw-r--r--mesonbuild/dependencies/dev.py39
-rw-r--r--mesonbuild/dependencies/misc.py130
-rw-r--r--mesonbuild/dependencies/ui.py231
-rw-r--r--mesonbuild/environment.py9
-rw-r--r--mesonbuild/interpreter.py6
-rw-r--r--mesonbuild/interpreterbase.py5
-rw-r--r--mesonbuild/mtest.py14
-rwxr-xr-xrun_unittests.py49
-rw-r--r--test cases/common/38 run program/get-version.py3
-rw-r--r--test cases/common/38 run program/meson.build2
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')