aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/coredata.py127
-rw-r--r--mesonbuild/dependencies/base.py4
-rw-r--r--mesonbuild/environment.py2
-rw-r--r--mesonbuild/interpreter.py17
-rw-r--r--mesonbuild/mconf.py3
-rw-r--r--mesonbuild/mintro.py2
-rw-r--r--mesonbuild/modules/rpm.py2
-rw-r--r--mesonbuild/munstable_coredata.py22
8 files changed, 152 insertions, 27 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index b8f0578..ac620d7 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -27,6 +27,11 @@ import ast
import argparse
import configparser
from typing import Optional, Any, TypeVar, Generic, Type, List, Union
+import typing
+import enum
+
+if typing.TYPE_CHECKING:
+ from . import dependencies
version = '0.50.999'
backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode']
@@ -221,6 +226,112 @@ def load_configs(filenames: List[str]) -> configparser.ConfigParser:
return config
+if typing.TYPE_CHECKING:
+ CacheKeyType = typing.Tuple[typing.Tuple[typing.Any, ...], ...]
+ SubCacheKeyType = typing.Tuple[typing.Any, ...]
+
+
+class DependencyCacheType(enum.Enum):
+
+ OTHER = 0
+ PKG_CONFIG = 1
+
+ @classmethod
+ def from_type(cls, dep: 'dependencies.Dependency') -> 'DependencyCacheType':
+ from . import dependencies
+ # As more types gain search overrides they'll need to be added here
+ if isinstance(dep, dependencies.PkgConfigDependency):
+ return cls.PKG_CONFIG
+ return cls.OTHER
+
+
+class DependencySubCache:
+
+ def __init__(self, type_: DependencyCacheType):
+ self.types = [type_]
+ self.__cache = {} # type: typing.Dict[SubCacheKeyType, dependencies.Dependency]
+
+ def __getitem__(self, key: 'SubCacheKeyType') -> 'dependencies.Dependency':
+ return self.__cache[key]
+
+ def __setitem__(self, key: 'SubCacheKeyType', value: 'dependencies.Dependency') -> None:
+ self.__cache[key] = value
+
+ def __contains__(self, key: 'SubCacheKeyType') -> bool:
+ return key in self.__cache
+
+ def values(self) -> typing.Iterable['dependencies.Dependency']:
+ return self.__cache.values()
+
+
+class DependencyCache:
+
+ """Class that stores a cache of dependencies.
+
+ This class is meant to encapsulate the fact that we need multiple keys to
+ successfully lookup by providing a simple get/put interface.
+ """
+
+ def __init__(self, builtins: typing.Dict[str, UserOption[typing.Any]], cross: bool):
+ self.__cache = OrderedDict() # type: typing.MutableMapping[CacheKeyType, DependencySubCache]
+ self.__builtins = builtins
+ self.__is_cross = cross
+
+ def __calculate_subkey(self, type_: DependencyCacheType) -> typing.Tuple[typing.Any, ...]:
+ if type_ is DependencyCacheType.PKG_CONFIG:
+ if self.__is_cross:
+ return tuple(self.__builtins['cross_pkg_config_path'].value)
+ return tuple(self.__builtins['pkg_config_path'].value)
+ assert type_ is DependencyCacheType.OTHER, 'Someone forgot to update subkey calculations for a new type'
+ return tuple()
+
+ def __iter__(self) -> typing.Iterator['CacheKeyType']:
+ return self.keys()
+
+ def put(self, key: 'CacheKeyType', dep: 'dependencies.Dependency') -> None:
+ t = DependencyCacheType.from_type(dep)
+ if key not in self.__cache:
+ self.__cache[key] = DependencySubCache(t)
+ subkey = self.__calculate_subkey(t)
+ self.__cache[key][subkey] = dep
+
+ def get(self, key: 'CacheKeyType') -> typing.Optional['dependencies.Dependency']:
+ """Get a value from the cache.
+
+ If there is no cache entry then None will be returned.
+ """
+ try:
+ val = self.__cache[key]
+ except KeyError:
+ return None
+
+ for t in val.types:
+ subkey = self.__calculate_subkey(t)
+ try:
+ return val[subkey]
+ except KeyError:
+ pass
+ return None
+
+ def values(self) -> typing.Iterator['dependencies.Dependency']:
+ for c in self.__cache.values():
+ yield from c.values()
+
+ def keys(self) -> typing.Iterator['CacheKeyType']:
+ return iter(self.__cache.keys())
+
+ def items(self) -> typing.Iterator[typing.Tuple['CacheKeyType', typing.List['dependencies.Dependency']]]:
+ for k, v in self.__cache.items():
+ vs = []
+ for t in v.types:
+ subkey = self.__calculate_subkey(t)
+ if subkey in v:
+ vs.append(v[subkey])
+ yield k, vs
+
+ def clear(self) -> None:
+ self.__cache.clear()
+
# This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as
# cmakecache.
@@ -248,7 +359,14 @@ class CoreData:
self.cross_files = self.__load_config_files(options.cross_file, 'cross')
self.compilers = OrderedDict()
self.cross_compilers = OrderedDict()
- self.deps = OrderedDict()
+
+ build_cache = DependencyCache(self.builtins, False)
+ if self.cross_files:
+ host_cache = DependencyCache(self.builtins, True)
+ else:
+ host_cache = build_cache
+ self.deps = PerMachine(build_cache, host_cache) # type: PerMachine[DependencyCache]
+
self.compiler_check_cache = OrderedDict()
# Only to print a warning if it changes between Meson invocations.
self.config_files = self.__load_config_files(options.native_file, 'native')
@@ -510,8 +628,11 @@ class CoreData:
# Some options default to environment variables if they are
# unset, set those now. These will either be overwritten
- # below, or they won't.
- options['pkg_config_path'] = os.environ.get('PKG_CONFIG_PATH', '').split(':')
+ # below, or they won't. These should only be set on the first run.
+ if env.first_invocation:
+ p_env = os.environ.get('PKG_CONFIG_PATH')
+ if p_env:
+ options['pkg_config_path'] = p_env.split(':')
for k, v in env.cmd_line_options.items():
if subproject:
diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py
index f2397e2..7836099 100644
--- a/mesonbuild/dependencies/base.py
+++ b/mesonbuild/dependencies/base.py
@@ -2358,8 +2358,8 @@ class ExtraFrameworkDependency(ExternalDependency):
return 'framework'
-def get_dep_identifier(name, kwargs, want_cross: bool) -> Tuple:
- identifier = (name, want_cross)
+def get_dep_identifier(name, kwargs) -> Tuple:
+ identifier = (name, )
for key, value in kwargs.items():
# 'version' is irrelevant for caching; the caller must check version matches
# 'native' is handled above with `want_cross`
diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py
index 1ccdf98..6b536a4 100644
--- a/mesonbuild/environment.py
+++ b/mesonbuild/environment.py
@@ -535,7 +535,7 @@ class Environment:
self.coredata.meson_command = mesonlib.meson_command
self.first_invocation = True
- def is_cross_build(self):
+ def is_cross_build(self) -> bool:
return not self.machines.matches_build_machine(MachineChoice.HOST)
def dump_coredata(self):
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index ea99a43..678560f 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -2859,14 +2859,13 @@ external dependencies (including libraries) must go to "dependencies".''')
# FIXME: Not all dependencies support such a distinction right now,
# and we repeat this check inside dependencies that do. We need to
# consolidate this somehow.
- is_cross = self.environment.is_cross_build()
- if 'native' in kwargs and is_cross:
- want_cross = not kwargs['native']
+ if self.environment.is_cross_build() and kwargs.get('native', False):
+ for_machine = MachineChoice.BUILD
else:
- want_cross = is_cross
+ for_machine = MachineChoice.HOST
- identifier = dependencies.get_dep_identifier(name, kwargs, want_cross)
- cached_dep = self.coredata.deps.get(identifier)
+ identifier = dependencies.get_dep_identifier(name, kwargs)
+ cached_dep = self.coredata.deps[for_machine].get(identifier)
if cached_dep:
if not cached_dep.found():
mlog.log('Dependency', mlog.bold(name),
@@ -3018,7 +3017,11 @@ external dependencies (including libraries) must go to "dependencies".''')
# cannot cache them. They must always be evaluated else
# we won't actually read all the build files.
if dep.found():
- self.coredata.deps[identifier] = dep
+ if self.environment.is_cross_build() and kwargs.get('native', False):
+ for_machine = MachineChoice.BUILD
+ else:
+ for_machine = MachineChoice.HOST
+ self.coredata.deps[for_machine].put(identifier, dep)
return DependencyHolder(dep, self.subproject)
if has_fallback:
diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py
index 3b50d55..6e0d2d0 100644
--- a/mesonbuild/mconf.py
+++ b/mesonbuild/mconf.py
@@ -63,7 +63,8 @@ class Conf:
raise ConfException('Directory {} is neither a Meson build directory nor a project source directory.'.format(build_dir))
def clear_cache(self):
- self.coredata.deps = {}
+ self.coredata.deps.host.clear()
+ self.coredata.deps.build.clear()
def set_options(self, options):
self.coredata.set_options(options)
diff --git a/mesonbuild/mintro.py b/mesonbuild/mintro.py
index cf55b6f..1d716ef 100644
--- a/mesonbuild/mintro.py
+++ b/mesonbuild/mintro.py
@@ -282,7 +282,7 @@ def list_deps_from_source(intr: IntrospectionInterpreter):
def list_deps(coredata: cdata.CoreData):
result = []
- for d in coredata.deps.values():
+ for d in coredata.deps.host.values():
if d.found():
result += [{'name': d.name,
'compile_args': d.get_compile_args(),
diff --git a/mesonbuild/modules/rpm.py b/mesonbuild/modules/rpm.py
index 7c1cefb..b99ae8d 100644
--- a/mesonbuild/modules/rpm.py
+++ b/mesonbuild/modules/rpm.py
@@ -83,7 +83,7 @@ class RPMModule(ExtensionModule):
fn.write('BuildRequires: meson\n')
for compiler in required_compilers:
fn.write('BuildRequires: %s\n' % compiler)
- for dep in coredata.environment.coredata.deps:
+ for dep in coredata.environment.coredata.deps.host:
fn.write('BuildRequires: pkgconfig(%s)\n' % dep[0])
# ext_libs and ext_progs have been removed from coredata so the following code
# no longer works. It is kept as a reminder of the idea should anyone wish
diff --git a/mesonbuild/munstable_coredata.py b/mesonbuild/munstable_coredata.py
index f16468c..864df04 100644
--- a/mesonbuild/munstable_coredata.py
+++ b/mesonbuild/munstable_coredata.py
@@ -97,13 +97,11 @@ def run(options):
print('Cached cross compilers:')
dump_compilers(v)
elif k == 'deps':
- native = []
- cross = []
- for dep_key, dep in sorted(v.items()):
- if dep_key[1]:
- cross.append((dep_key, dep))
- else:
- native.append((dep_key, dep))
+ native = list(sorted(v.build.items()))
+ if v.host is not v.build:
+ cross = list(sorted(v.host.items()))
+ else:
+ cross = []
def print_dep(dep_key, dep):
print(' ' + dep_key[0] + ": ")
@@ -115,12 +113,14 @@ def run(options):
if native:
print('Cached native dependencies:')
- for dep_key, dep in native:
- print_dep(dep_key, dep)
+ for dep_key, deps in native:
+ for dep in deps:
+ print_dep(dep_key, dep)
if cross:
print('Cached dependencies:')
- for dep_key, dep in cross:
- print_dep(dep_key, dep)
+ for dep_key, deps in cross:
+ for dep in deps:
+ print_dep(dep_key, dep)
else:
print(k + ':')
print(textwrap.indent(pprint.pformat(v), ' '))