aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/coredata.py2
-rw-r--r--mesonbuild/dependencies.py38
-rw-r--r--mesonbuild/interpreter.py78
-rw-r--r--mesonbuild/mesonlib.py2
-rw-r--r--mesonbuild/mintro.py6
5 files changed, 72 insertions, 54 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 2dd57a9..6c091c8 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -160,7 +160,7 @@ class CoreData:
self.wrap_mode = options.wrap_mode
self.compilers = OrderedDict()
self.cross_compilers = OrderedDict()
- self.deps = {}
+ self.deps = OrderedDict()
self.modules = {}
# Only to print a warning if it changes between Meson invocations.
self.pkgconf_envvar = os.environ.get('PKG_CONFIG_PATH', '')
diff --git a/mesonbuild/dependencies.py b/mesonbuild/dependencies.py
index 18d418e..d9a7c9c 100644
--- a/mesonbuild/dependencies.py
+++ b/mesonbuild/dependencies.py
@@ -27,9 +27,10 @@ import subprocess
import sysconfig
from enum import Enum
from collections import OrderedDict
-from . mesonlib import MesonException, version_compare, version_compare_many, Popen_safe
from . import mlog
from . import mesonlib
+from .mesonlib import Popen_safe, flatten
+from .mesonlib import MesonException, version_compare, version_compare_many
from .environment import detect_cpu_family, for_windows
class DependencyException(MesonException):
@@ -103,6 +104,7 @@ class InternalDependency(Dependency):
def __init__(self, version, incdirs, compile_args, link_args, libraries, sources, ext_deps):
super().__init__('internal', {})
self.version = version
+ self.is_found = True
self.include_directories = incdirs
self.compile_args = compile_args
self.link_args = link_args
@@ -127,6 +129,7 @@ class PkgConfigDependency(Dependency):
def __init__(self, name, environment, kwargs):
Dependency.__init__(self, 'pkgconfig', kwargs)
self.is_libtool = False
+ self.version_reqs = kwargs.get('version', None)
self.required = kwargs.get('required', True)
self.static = kwargs.get('static', False)
self.silent = kwargs.get('silent', False)
@@ -187,7 +190,6 @@ class PkgConfigDependency(Dependency):
''.format(self.type_string, name))
return
found_msg = [self.type_string + ' dependency', mlog.bold(name), 'found:']
- self.version_reqs = kwargs.get('version', None)
if self.version_reqs is None:
self.is_found = True
else:
@@ -1743,21 +1745,23 @@ class LLVMDependency(Dependency):
return True
-def get_dep_identifier(name, kwargs):
- elements = [name]
- modlist = kwargs.get('modules', [])
- if isinstance(modlist, str):
- modlist = [modlist]
- for module in modlist:
- elements.append(module)
- # We use a tuple because we need a non-mutable structure to use as the key
- # of a dictionary and a string has potential for name collisions
- identifier = tuple(elements)
- identifier += ('main', kwargs.get('main', False))
- identifier += ('static', kwargs.get('static', False))
- if 'fallback' in kwargs:
- f = kwargs.get('fallback')
- identifier += ('fallback', f[0], f[1])
+def get_dep_identifier(name, kwargs, want_cross):
+ # Need immutable objects since the identifier will be used as a dict key
+ version_reqs = flatten(kwargs.get('version', []))
+ if isinstance(version_reqs, list):
+ version_reqs = frozenset(version_reqs)
+ identifier = (name, version_reqs, want_cross)
+ for key, value in kwargs.items():
+ # 'version' is embedded above as the second element for easy access
+ # 'native' is handled above with `want_cross`
+ # 'required' is irrelevant for caching; the caller handles it separately
+ # 'fallback' subprojects cannot be cached -- they must be initialized
+ if key in ('version', 'native', 'required', 'fallback',):
+ continue
+ # All keyword arguments are strings, ints, or lists (or lists of lists)
+ if isinstance(value, list):
+ value = frozenset(flatten(value))
+ identifier += (key, value)
return identifier
def find_external_dependency(name, environment, kwargs):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 80d482e..5df26cc 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -23,7 +23,8 @@ from . import compilers
from .wrap import wrap, WrapMode
from . import mesonlib
from .mesonlib import FileMode, Popen_safe, get_meson_script
-from .dependencies import InternalDependency, Dependency, ExternalProgram
+from .dependencies import ExternalProgram
+from .dependencies import InternalDependency, Dependency, DependencyException
from .interpreterbase import InterpreterBase
from .interpreterbase import check_stringlist, noPosargs, noKwargs, stringArgs
from .interpreterbase import InterpreterException, InvalidArguments, InvalidCode
@@ -1852,13 +1853,7 @@ class Interpreter(InterpreterBase):
def func_find_library(self, node, args, kwargs):
mlog.log(mlog.red('DEPRECATION:'), 'find_library() is removed, use the corresponding method in compiler object instead.')
- def func_dependency(self, node, args, kwargs):
- self.validate_arguments(args, 1, [str])
- name = args[0]
- if '<' in name or '>' in name or '=' in name:
- raise InvalidArguments('Characters <, > and = are forbidden in dependency names. To specify'
- 'version\n requirements use the \'version\' keyword argument instead.')
- identifier = dependencies.get_dep_identifier(name, kwargs)
+ def _find_cached_dep(self, name, kwargs):
# Check if we want this as a cross-dep or a native-dep
# FIXME: Not all dependencies support such a distinction right now,
# and we repeat this check inside dependencies that do. We need to
@@ -1868,60 +1863,79 @@ class Interpreter(InterpreterBase):
want_cross = not kwargs['native']
else:
want_cross = is_cross
- # Check if we've already searched for and found this dep
+ identifier = dependencies.get_dep_identifier(name, kwargs, want_cross)
cached_dep = None
+ # Check if we've already searched for and found this dep
if identifier in self.coredata.deps:
cached_dep = self.coredata.deps[identifier]
- if 'version' in kwargs:
- wanted = kwargs['version']
- found = cached_dep.get_version()
- if not cached_dep.found() or \
- not mesonlib.version_compare_many(found, wanted)[0]:
- # Cached dep has the wrong version. Check if an external
- # dependency or a fallback dependency provides it.
- cached_dep = None
- # Don't re-use cached dep if it wasn't required but this one is,
- # so we properly go into fallback/error code paths
- if kwargs.get('required', True) and not getattr(cached_dep, 'required', False):
- cached_dep = None
- # Don't reuse cached dep if one is a cross-dep and the other is a native dep
- if not getattr(cached_dep, 'want_cross', is_cross) == want_cross:
- cached_dep = None
+ else:
+ # Check if exactly the same dep with different version requirements
+ # was found already.
+ wanted = identifier[1]
+ for trial, trial_dep in self.coredata.deps.items():
+ # trial[1], identifier[1] are the version requirements
+ if trial[0] != identifier[0] or trial[2:] != identifier[2:]:
+ continue
+ found = trial_dep.get_version()
+ if not wanted or mesonlib.version_compare_many(found, wanted)[0]:
+ # We either don't care about the version, or our
+ # version requirements matched the trial dep's version.
+ cached_dep = trial_dep
+ break
+ return identifier, cached_dep
+
+ def func_dependency(self, node, args, kwargs):
+ self.validate_arguments(args, 1, [str])
+ name = args[0]
+ if '<' in name or '>' in name or '=' in name:
+ raise InvalidArguments('Characters <, > and = are forbidden in dependency names. To specify'
+ 'version\n requirements use the \'version\' keyword argument instead.')
+ identifier, cached_dep = self._find_cached_dep(name, kwargs)
if cached_dep:
+ if kwargs.get('required', True) and not cached_dep.found():
+ m = 'Dependency {!r} was already checked and was not found'
+ raise DependencyException(m.format(name))
dep = cached_dep
else:
# We need to actually search for this dep
exception = None
dep = None
- # If the fallback has already been configured (possibly by a higher level project)
- # try to use it before using the native version
+ # If the dependency has already been configured, possibly by
+ # a higher level project, try to use it first.
if 'fallback' in kwargs:
dirname, varname = self.get_subproject_infos(kwargs)
if dirname in self.subprojects:
+ subproject = self.subprojects[dirname]
try:
- dep = self.subprojects[dirname].get_variable_method([varname], {})
- dep = dep.held_object
+ # Never add fallback deps to self.coredata.deps
+ return subproject.get_variable_method([varname], {})
except KeyError:
pass
+ # Search for it outside the project
if not dep:
try:
dep = dependencies.find_external_dependency(name, self.environment, kwargs)
- except dependencies.DependencyException as e:
+ except DependencyException as e:
exception = e
pass
+ # Search inside the projects list
if not dep or not dep.found():
if 'fallback' in kwargs:
fallback_dep = self.dependency_fallback(name, kwargs)
if fallback_dep:
+ # Never add fallback deps to self.coredata.deps since we
+ # cannot cache them. They must always be evaluated else
+ # we won't actually read all the build files.
return fallback_dep
-
if not dep:
raise exception
- self.coredata.deps[identifier] = dep
+ # Only store found-deps in the cache
+ if dep.found():
+ self.coredata.deps[identifier] = dep
return DependencyHolder(dep)
def get_subproject_infos(self, kwargs):
@@ -2230,7 +2244,7 @@ class Interpreter(InterpreterBase):
absname = os.path.join(self.environment.get_source_dir(), buildfilename)
if not os.path.isfile(absname):
self.subdir = prev_subdir
- raise InterpreterException('Nonexistent build def file %s.' % buildfilename)
+ raise InterpreterException('Non-existent build file {!r}'.format(buildfilename))
with open(absname, encoding='utf8') as f:
code = f.read()
assert(isinstance(code, str))
diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py
index 7248be9..54e8016 100644
--- a/mesonbuild/mesonlib.py
+++ b/mesonbuild/mesonlib.py
@@ -305,7 +305,7 @@ def version_compare(vstr1, vstr2, strict=False):
return cmpop(varr1, varr2)
def version_compare_many(vstr1, conditions):
- if not isinstance(conditions, (list, tuple)):
+ if not isinstance(conditions, (list, tuple, frozenset)):
conditions = [conditions]
found = []
not_found = []
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index c12c4dd..88ea16e 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -161,12 +161,12 @@ def list_buildsystem_files(coredata, builddata):
print(json.dumps(filelist))
def list_deps(coredata):
- result = {}
- for d in coredata.deps.values():
+ result = []
+ for d in coredata.deps:
if d.found():
args = {'compile_args': d.get_compile_args(),
'link_args': d.get_link_args()}
- result[d.name] = args
+ result += [d.name, args]
print(json.dumps(result))
def list_tests(testdata):