|
|
|
# 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]
|
|
|
|
]
|
|
|
|
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
# 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,
|
openssl dependency: add cmake support
This is gross and looks terrible, but I'm not entirely sure how else to
do this.
And cmake is an inferior methodology, TBH, since it is effectively the
same as our own builtins. However, cmake also handles some bizarre
Windows library names whose provenance I'm not entirely sure of, in
addition to implementing the usual excessive pattern of hardcoded search
directories. So, this may be useful, at least on Windows, as a fallback.
(I am not really interested in offering feature compatibility with cmake
for a bunch of bizarre naming schemes that ***aren't the official cmake
library names***, so if cmake allows that and people really feel they
need it, all the more power to them.)
Nevertheless, I believe if it got found via our system dependency class,
it will always provide results which are just as functional as cmake.
cmake can only find openssl installations that would otherwise be
missed.
This also avoids the case where users did
```
dependency('OpenSSL', modules: [...], method: 'cmake')
```
and expected it to work, since our builtin dependency supersedes the
divergent case and didn't previously allow the cmake method. I don't
know why they would do such a thing, but who knows... it is always
possible.
3 years ago
|
|
|
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
|