summaryrefslogtreecommitdiffstats
path: root/mesonbuild/dependencies/factory.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/dependencies/factory.py')
-rw-r--r--mesonbuild/dependencies/factory.py156
1 files changed, 156 insertions, 0 deletions
diff --git a/mesonbuild/dependencies/factory.py b/mesonbuild/dependencies/factory.py
new file mode 100644
index 0000000..d50ce0f
--- /dev/null
+++ b/mesonbuild/dependencies/factory.py
@@ -0,0 +1,156 @@
+# Copyright 2013-2021 The Meson development team
+# Copyright © 2021 Intel Corporation
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+
+# http://www.apache.org/licenses/LICENSE-2.0
+
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from __future__ import annotations
+
+import functools
+import typing as T
+
+from .base import DependencyException, DependencyMethods
+from .base import process_method_kw
+from .base import BuiltinDependency, SystemDependency
+from .cmake import CMakeDependency
+from .framework import ExtraFrameworkDependency
+from .pkgconfig import PkgConfigDependency
+
+if T.TYPE_CHECKING:
+ from .base import ExternalDependency
+ from .configtool import ConfigToolDependency
+ from ..environment import Environment
+ from ..mesonlib import MachineChoice
+
+ DependencyGenerator = T.Callable[[], ExternalDependency]
+ FactoryFunc = T.Callable[
+ [
+ 'Environment',
+ MachineChoice,
+ T.Dict[str, T.Any],
+ T.List[DependencyMethods]
+ ],
+ T.List[DependencyGenerator]
+ ]
+
+ WrappedFactoryFunc = T.Callable[
+ [
+ 'Environment',
+ MachineChoice,
+ T.Dict[str, T.Any]
+ ],
+ T.List[DependencyGenerator]
+ ]
+
+ # This should be str, Environment, T.Dict[str, T.Any], T.Optional[str]
+ # But if you try that, you get error: Cannot infer type of lambda
+ CmakeDependencyFunc = T.Callable[..., CMakeDependency]
+
+class DependencyFactory:
+
+ """Factory to get dependencies from multiple sources.
+
+ This class provides an initializer that takes a set of names and classes
+ for various kinds of dependencies. When the initialized object is called
+ it returns a list of callables return Dependency objects to try in order.
+
+ :name: The name of the dependency. This will be passed as the name
+ parameter of the each dependency unless it is overridden on a per
+ type basis.
+ :methods: An ordered list of DependencyMethods. This is the order
+ dependencies will be returned in unless they are removed by the
+ _process_method function
+ :*_name: This will overwrite the name passed to the corresponding class.
+ For example, if the name is 'zlib', but cmake calls the dependency
+ 'Z', then using `cmake_name='Z'` will pass the name as 'Z' to cmake.
+ :*_class: A *type* or callable that creates a class, and has the
+ signature of an ExternalDependency
+ :system_class: If you pass DependencyMethods.SYSTEM in methods, you must
+ set this argument.
+ """
+
+ def __init__(self, name: str, methods: T.List[DependencyMethods], *,
+ extra_kwargs: T.Optional[T.Dict[str, T.Any]] = None,
+ pkgconfig_name: T.Optional[str] = None,
+ pkgconfig_class: 'T.Type[PkgConfigDependency]' = PkgConfigDependency,
+ cmake_name: T.Optional[str] = None,
+ cmake_class: 'T.Union[T.Type[CMakeDependency], CmakeDependencyFunc]' = CMakeDependency,
+ configtool_class: 'T.Optional[T.Type[ConfigToolDependency]]' = None,
+ framework_name: T.Optional[str] = None,
+ framework_class: 'T.Type[ExtraFrameworkDependency]' = ExtraFrameworkDependency,
+ builtin_class: 'T.Type[BuiltinDependency]' = BuiltinDependency,
+ system_class: 'T.Type[SystemDependency]' = SystemDependency):
+
+ if DependencyMethods.CONFIG_TOOL in methods and not configtool_class:
+ raise DependencyException('A configtool must have a custom class')
+
+ self.extra_kwargs = extra_kwargs or {}
+ self.methods = methods
+ self.classes: T.Dict[
+ DependencyMethods,
+ T.Callable[['Environment', T.Dict[str, T.Any]], ExternalDependency]
+ ] = {
+ # Just attach the correct name right now, either the generic name
+ # or the method specific name.
+ DependencyMethods.EXTRAFRAMEWORK: functools.partial(framework_class, framework_name or name),
+ DependencyMethods.PKGCONFIG: functools.partial(pkgconfig_class, pkgconfig_name or name),
+ DependencyMethods.CMAKE: functools.partial(cmake_class, cmake_name or name),
+ DependencyMethods.SYSTEM: functools.partial(system_class, name),
+ DependencyMethods.BUILTIN: functools.partial(builtin_class, name),
+ DependencyMethods.CONFIG_TOOL: None,
+ }
+ if configtool_class is not None:
+ self.classes[DependencyMethods.CONFIG_TOOL] = functools.partial(configtool_class, name)
+
+ @staticmethod
+ def _process_method(method: DependencyMethods, env: 'Environment', for_machine: MachineChoice) -> bool:
+ """Report whether a method is valid or not.
+
+ If the method is valid, return true, otherwise return false. This is
+ used in a list comprehension to filter methods that are not possible.
+
+ By default this only remove EXTRAFRAMEWORK dependencies for non-mac platforms.
+ """
+ # Extra frameworks are only valid for macOS and other apple products
+ if (method is DependencyMethods.EXTRAFRAMEWORK and
+ not env.machines[for_machine].is_darwin()):
+ return False
+ return True
+
+ def __call__(self, env: 'Environment', for_machine: MachineChoice,
+ kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']:
+ """Return a list of Dependencies with the arguments already attached."""
+ methods = process_method_kw(self.methods, kwargs)
+ nwargs = self.extra_kwargs.copy()
+ nwargs.update(kwargs)
+
+ return [functools.partial(self.classes[m], env, nwargs) for m in methods
+ if self._process_method(m, env, for_machine)]
+
+
+def factory_methods(methods: T.Set[DependencyMethods]) -> T.Callable[['FactoryFunc'], 'WrappedFactoryFunc']:
+ """Decorator for handling methods for dependency factory functions.
+
+ This helps to make factory functions self documenting
+ >>> @factory_methods([DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE])
+ >>> def factory(env: Environment, for_machine: MachineChoice, kwargs: T.Dict[str, T.Any], methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
+ >>> pass
+ """
+
+ def inner(func: 'FactoryFunc') -> 'WrappedFactoryFunc':
+
+ @functools.wraps(func)
+ def wrapped(env: 'Environment', for_machine: MachineChoice, kwargs: T.Dict[str, T.Any]) -> T.List['DependencyGenerator']:
+ return func(env, for_machine, kwargs, process_method_kw(methods, kwargs))
+
+ return wrapped
+
+ return inner