The Meson Build System
http://mesonbuild.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
6.8 KiB
156 lines
6.8 KiB
# 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
|
|
|