diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 4536746d940f..de9e24f230de 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -7,6 +7,7 @@ from __future__ import annotations import copy +import dataclasses import os import collections import itertools @@ -21,7 +22,7 @@ #from ..interpreterbase import FeatureDeprecated, FeatureNew if T.TYPE_CHECKING: - from typing_extensions import Literal, TypedDict, TypeAlias + from typing_extensions import Literal, Required, TypedDict, TypeAlias from ..compilers.compilers import Compiler from ..environment import Environment @@ -51,7 +52,7 @@ class DependencyObjectKWs(TypedDict, total=False): main: bool method: DependencyMethods modules: T.List[str] - native: MachineChoice + native: Required[MachineChoice] optional_modules: T.List[str] private_headers: bool required: bool @@ -73,6 +74,8 @@ class DependencyObjectKWs(TypedDict, total=False): _MissingCompilerBase = object +DepType = T.TypeVar('DepType', bound='ExternalDependency', covariant=True) + class DependencyException(MesonException): '''Exceptions raised while trying to find dependencies''' @@ -129,15 +132,16 @@ class DependencyMethods(Enum): class Dependency(HoldableObject): - def __init__(self, type_name: DependencyTypeName, kwargs: DependencyObjectKWs) -> None: + type_name: DependencyTypeName + + def __init__(self, kwargs: DependencyObjectKWs) -> None: # This allows two Dependencies to be compared even after being copied. # The purpose is to allow the name to be changed, but still have a proper comparison self._id = uuid.uuid4().int self.name = f'dep{self._id}' self.version: T.Optional[str] = None - self.language: T.Optional[str] = None # None means C-like + self.language: T.Optional[str] = kwargs.get('language') # None means C-like self.is_found = False - self.type_name = type_name self.compile_args: T.List[str] = [] self.link_args: T.List[str] = [] # Raw -L and -l arguments without manual library searching @@ -298,6 +302,9 @@ def get_as_shared(self, recursive: bool) -> Dependency: return self class InternalDependency(Dependency): + + type_name = DependencyTypeName('internal') + def __init__(self, version: str, incdirs: T.List['IncludeDirs'], compile_args: T.List[str], link_args: T.List[str], libraries: T.List[LibTypes], @@ -308,7 +315,7 @@ def __init__(self, version: str, incdirs: T.List['IncludeDirs'], compile_args: T d_module_versions: T.List[T.Union[str, int]], d_import_dirs: T.List['IncludeDirs'], objects: T.List['ExtractedObjects'], name: T.Optional[str] = None): - super().__init__(DependencyTypeName('internal'), {}) + super().__init__({'native': MachineChoice.HOST}) # TODO: does the native key actually matter self.version = version self.is_found = True self.include_directories = incdirs @@ -412,12 +419,11 @@ def get_as_shared(self, recursive: bool) -> InternalDependency: return new_dep class ExternalDependency(Dependency): - def __init__(self, type_name: DependencyTypeName, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None): - Dependency.__init__(self, type_name, kwargs) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): + Dependency.__init__(self, kwargs) self.env = environment - self.name = type_name # default + self.name = name self.is_found = False - self.language = language self.version_reqs = kwargs.get('version', []) self.required = kwargs.get('required', True) self.silent = kwargs.get('silent', False) @@ -427,7 +433,7 @@ def __init__(self, type_name: DependencyTypeName, environment: 'Environment', kw self.static = static self.libtype = LibType.STATIC if self.static else LibType.PREFER_SHARED # Is this dependency to be run on the build platform? - self.for_machine = kwargs.get('native', MachineChoice.HOST) + self.for_machine = kwargs['native'] self.clib_compiler = detect_compiler(self.name, environment, self.for_machine, self.language) def get_compiler(self) -> T.Union['MissingCompiler', 'Compiler']: @@ -457,10 +463,6 @@ def log_details(self) -> str: def log_info(self) -> str: return '' - @staticmethod - def log_tried() -> str: - return '' - # Check if dependency version meets the requirements def _check_version(self) -> None: if not self.is_found: @@ -499,8 +501,11 @@ def _check_version(self) -> None: class NotFoundDependency(Dependency): + + type_name = DependencyTypeName('not-found') + def __init__(self, name: str, environment: 'Environment') -> None: - super().__init__(DependencyTypeName('not-found'), {}) + super().__init__({'native': MachineChoice.HOST}) # TODO: does this actually matter? self.env = environment self.name = name self.is_found = False @@ -514,11 +519,12 @@ def get_partial_dependency(self, *, compile_args: bool = False, class ExternalLibrary(ExternalDependency): + + type_name = DependencyTypeName('library') + def __init__(self, name: str, link_args: T.List[str], environment: 'Environment', - language: str, silent: bool = False) -> None: - super().__init__(DependencyTypeName('library'), environment, {}, language=language) - self.name = name - self.language = language + language: str, for_machine: MachineChoice, silent: bool = False) -> None: + super().__init__(name, environment, {'language': language, 'native': for_machine}) self.is_found = False if link_args: self.is_found = True @@ -660,25 +666,44 @@ class SystemDependency(ExternalDependency): """Dependency base for System type dependencies.""" - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, - language: T.Optional[str] = None) -> None: - super().__init__(DependencyTypeName('system'), env, kwargs, language=language) - self.name = name - - @staticmethod - def log_tried() -> str: - return 'system' + type_name = DependencyTypeName('system') class BuiltinDependency(ExternalDependency): """Dependency base for Builtin type dependencies.""" - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, - language: T.Optional[str] = None) -> None: - super().__init__(DependencyTypeName('builtin'), env, kwargs, language=language) - self.name = name + type_name = DependencyTypeName('builtin') + + +@dataclasses.dataclass +class DependencyCandidate(T.Generic[DepType]): + + callable: T.Union[T.Type[DepType], T.Callable[[str, Environment, DependencyObjectKWs], DepType]] + name: str + method: str + modules: T.Optional[T.List[str]] = None + arguments: T.Optional[T.Tuple[Environment, DependencyObjectKWs]] = dataclasses.field(default=None) + + def __call__(self) -> DepType: + if self.arguments is None: + raise mesonlib.MesonBugException('Attempted to instantiate a candidate before setting its arguments') + env, kwargs = self.arguments + if self.modules is not None: + kwargs['modules'] = self.modules.copy() + return self.callable(self.name, env, kwargs) + + @classmethod + def from_dependency(cls, name: str, dep: T.Type[DepType], + args: T.Optional[T.Tuple[Environment, DependencyObjectKWs]] = None, + modules: T.Optional[T.List[str]] = None, + ) -> DependencyCandidate[DepType]: + tried = str(dep.type_name) + + # fixup the cases where type_name and log tried don't match + if tried in {'extraframeworks', 'appleframeworks'}: + tried = 'framework' + elif tried == 'pkgconfig': + tried = 'pkg-config' - @staticmethod - def log_tried() -> str: - return 'builtin' + return cls(dep, name, tried, modules, arguments=args) diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 1aeb451f1634..02c449cb2f49 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -340,8 +340,9 @@ def get_link_args(self) -> T.List[str]: return [self.path.as_posix()] class BoostDependency(SystemDependency): - def __init__(self, environment: Environment, kwargs: DependencyObjectKWs) -> None: - super().__init__('boost', environment, kwargs, language='cpp') + def __init__(self, name: str, environment: Environment, kwargs: DependencyObjectKWs) -> None: + kwargs['language'] = 'cpp' + super().__init__(name, environment, kwargs) buildtype = environment.coredata.optstore.get_value_for(OptionKey('buildtype')) assert isinstance(buildtype, str) self.debug = buildtype.startswith('debug') @@ -361,7 +362,7 @@ def __init__(self, environment: Environment, kwargs: DependencyObjectKWs) -> Non # Do we need threads? if 'thread' in self.modules: - if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): + if not self._add_sub_dependency(threads_factory(environment, {'native': self.for_machine})): self.is_found = False return @@ -676,7 +677,7 @@ def detect_roots(self) -> None: # Try getting the BOOST_ROOT from a boost.pc if it exists. This primarily # allows BoostDependency to find boost from Conan. See #5438 try: - boost_pc = PkgConfigDependency('boost', self.env, {'required': False}) + boost_pc = PkgConfigDependency('boost', self.env, {'required': False, 'native': self.for_machine}) if boost_pc.found(): boost_lib_dir = boost_pc.get_variable(pkgconfig='libdir') boost_inc_dir = boost_pc.get_variable(pkgconfig='includedir') diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 066bb29007bd..5fc207317878 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -4,7 +4,7 @@ from __future__ import annotations from .base import ExternalDependency, DependencyException, DependencyTypeName -from ..mesonlib import is_windows, MesonException, PerMachine, MachineChoice +from ..mesonlib import is_windows, MesonException, PerMachine from ..cmake import CMakeExecutor, CMakeTraceParser, CMakeException, CMakeToolchain, CMakeExecScope, check_cmake_args, resolve_cmake_trace_targets, cmake_is_debug from .. import mlog import importlib.resources @@ -39,6 +39,8 @@ class CMakeDependency(ExternalDependency): class_cmake_generators = ['', 'Ninja', 'Unix Makefiles', 'Visual Studio 10 2010'] class_working_generator: T.Optional[str] = None + type_name = DependencyTypeName('cmake') + def _gen_exception(self, msg: str) -> DependencyException: return DependencyException(f'Dependency {self.name} not found: {msg}') @@ -70,11 +72,12 @@ def _original_module_name(self, module: str) -> str: # one module return module - def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, force_use_global_compilers: bool = False) -> None: # Gather a list of all languages to support self.language_list: T.List[str] = [] + language = kwargs.get('language') if language is None or force_use_global_compilers: - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] compilers = environment.coredata.compilers[for_machine] candidates = ['c', 'cpp', 'fortran', 'objc', 'objcxx'] self.language_list += [x for x in candidates if x in compilers] @@ -88,8 +91,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje # Ensure that the list is unique self.language_list = list(set(self.language_list)) - super().__init__(DependencyTypeName('cmake'), environment, kwargs, language=language) - self.name = name + super().__init__(name, environment, kwargs) self.is_libtool = False # Where all CMake "build dirs" are located @@ -607,10 +609,6 @@ def _call_cmake(self, build_dir = self._setup_cmake_dir(cmake_file) return self.cmakebin.call(args, build_dir, env=env) - @staticmethod - def log_tried() -> str: - return 'cmake' - def log_details(self) -> str: modules = [self._original_module_name(x) for x in self.found_modules] modules = sorted(set(modules)) @@ -643,22 +641,6 @@ def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[s raise DependencyException(f'Could not get cmake variable and no default provided for {self!r}') -class CMakeDependencyFactory: - - def __init__(self, name: T.Optional[str] = None, modules: T.Optional[T.List[str]] = None): - self.name = name - self.modules = modules - - def __call__(self, name: str, env: Environment, kwargs: DependencyObjectKWs, language: T.Optional[str] = None, force_use_global_compilers: bool = False) -> CMakeDependency: - if self.modules: - kwargs['modules'] = self.modules - return CMakeDependency(self.name or name, env, kwargs, language, force_use_global_compilers) - - @staticmethod - def log_tried() -> str: - return CMakeDependency.log_tried() - - def sort_link_args(args: T.List[str]) -> T.List[str]: itr = iter(args) result: T.Set[T.Union[T.Tuple[str], T.Tuple[str, str]]] = set() diff --git a/mesonbuild/dependencies/coarrays.py b/mesonbuild/dependencies/coarrays.py index a4dbdc535c45..ddb50058f0ea 100644 --- a/mesonbuild/dependencies/coarrays.py +++ b/mesonbuild/dependencies/coarrays.py @@ -3,10 +3,9 @@ from __future__ import annotations -import functools import typing as T -from .base import DependencyMethods, detect_compiler, SystemDependency +from .base import DependencyCandidate, DependencyMethods, detect_compiler, SystemDependency from .cmake import CMakeDependency from .detect import packages from .pkgconfig import PkgConfigDependency @@ -15,15 +14,15 @@ if T.TYPE_CHECKING: from . factory import DependencyGenerator from ..environment import Environment - from ..mesonlib import MachineChoice from .base import DependencyObjectKWs @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE, DependencyMethods.SYSTEM}) def coarray_factory(env: 'Environment', - for_machine: 'MachineChoice', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: + kwargs['language'] = 'fortran' + for_machine = kwargs['native'] fcid = detect_compiler('coarray', env, for_machine, 'fortran').get_id() candidates: T.List['DependencyGenerator'] = [] @@ -31,19 +30,24 @@ def coarray_factory(env: 'Environment', # OpenCoarrays is the most commonly used method for Fortran Coarray with GCC if DependencyMethods.PKGCONFIG in methods: for pkg in ['caf-openmpi', 'caf']: - candidates.append(functools.partial( - PkgConfigDependency, pkg, env, kwargs, language='fortran')) + candidates.append(DependencyCandidate.from_dependency( + pkg, PkgConfigDependency, (env, kwargs))) if DependencyMethods.CMAKE in methods: + nkwargs = kwargs if not kwargs.get('modules'): - kwargs['modules'] = ['OpenCoarrays::caf_mpi'] - candidates.append(functools.partial( - CMakeDependency, 'OpenCoarrays', env, kwargs, language='fortran')) + nkwargs = kwargs.copy() + nkwargs['modules'] = ['OpenCoarrays::caf_mpi'] + candidates.append(DependencyCandidate.from_dependency( + 'OpenCoarrays', CMakeDependency, (env, nkwargs))) if DependencyMethods.SYSTEM in methods: - candidates.append(functools.partial(CoarrayDependency, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'coarray', CoarrayDependency, (env, kwargs))) return candidates + + packages['coarray'] = coarray_factory @@ -56,10 +60,9 @@ class CoarrayDependency(SystemDependency): Coarrays may be thought of as a high-level language abstraction of low-level MPI calls. """ - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__('coarray', environment, kwargs, language='fortran') - kwargs['required'] = False - kwargs['silent'] = True + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + kwargs['language'] = 'fortran' + super().__init__(name, environment, kwargs) cid = self.get_compiler().get_id() if cid == 'gcc': diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index e2721fe3bbd0..3d018943c7aa 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -36,10 +36,10 @@ class ConfigToolDependency(ExternalDependency): skip_version: T.Optional[str] = None allow_default_for_cross = False __strip_version = re.compile(r'^[0-9][0-9.]+') + type_name = DependencyTypeName('config-tool') - def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None, exclude_paths: T.Optional[T.List[str]] = None): - super().__init__(DependencyTypeName('config-tool'), environment, kwargs, language=language) - self.name = name + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, exclude_paths: T.Optional[T.List[str]] = None): + super().__init__(name, environment, kwargs) # You may want to overwrite the class version in some cases self.tools = listify(kwargs.get('tools', self.tools)) if not self.tool_name: @@ -150,10 +150,6 @@ def get_config_value(self, args: T.List[str], stage: str) -> T.List[str]: def get_variable_args(self, variable_name: str) -> T.List[str]: return [f'--{variable_name}'] - @staticmethod - def log_tried() -> str: - return 'config-tool' - def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, configtool: T.Optional[str] = None, internal: T.Optional[str] = None, system: T.Optional[str] = None, default_value: T.Optional[str] = None, diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index d80c62d8de4c..b3401ee0310a 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -28,16 +28,17 @@ class CudaDependency(SystemDependency): supported_languages = ['cpp', 'c', 'cuda'] # see also _default_language targets_dir = 'targets' # Directory containing CUDA targets. - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - for_machine = kwargs.get('native', mesonlib.MachineChoice.HOST) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + for_machine = kwargs['native'] compilers = environment.coredata.compilers[for_machine] machine = environment.machines[for_machine] - language = self._detect_language(compilers) + if not kwargs.get('language'): + kwargs['language'] = self._detect_language(compilers) - if language not in self.supported_languages: - raise DependencyException(f'Language \'{language}\' is not supported by the CUDA Toolkit. Supported languages are {self.supported_languages}.') + if kwargs['language'] not in self.supported_languages: + raise DependencyException(f'Language \'{kwargs["language"]}\' is not supported by the CUDA Toolkit. Supported languages are {self.supported_languages}.') - super().__init__('cuda', environment, kwargs, language=language) + super().__init__(name, environment, kwargs) self.lib_modules: T.Dict[str, T.List[str]] = {} self.requested_modules = kwargs.get('modules', []) if not any(runtime in self.requested_modules for runtime in ['cudart', 'cudart_static']): diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py index f00075b0dd40..65e19c2aac59 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -3,25 +3,29 @@ from __future__ import annotations -import collections, functools, importlib +import collections, importlib import enum import typing as T -from .base import ExternalDependency, DependencyException, DependencyMethods, NotFoundDependency +from .base import DependencyCandidate, ExternalDependency, DependencyException, DependencyMethods, NotFoundDependency -from ..mesonlib import listify, MachineChoice, PerMachine +from ..mesonlib import listify, PerMachine, MesonBugException, MesonException from .. import mlog if T.TYPE_CHECKING: from ..environment import Environment - from .factory import DependencyFactory, WrappedFactoryFunc, DependencyGenerator + from .factory import DependencyFactory, DependencyGenerator, WrappedFactoryFunc from .base import DependencyObjectKWs TV_DepIDEntry = T.Union[str, bool, int, None, T.Tuple[str, ...]] TV_DepID = T.Tuple[T.Tuple[str, TV_DepIDEntry], ...] - PackageTypes = T.Union[T.Type[ExternalDependency], DependencyFactory, WrappedFactoryFunc] + PackageTypes = T.Union[T.Type[ExternalDependency], DependencyFactory, DependencyCandidate, WrappedFactoryFunc] + # Workaround for older python + DependencyPackagesType = collections.UserDict[str, PackageTypes] +else: + DependencyPackagesType = collections.UserDict -class DependencyPackages(collections.UserDict): +class DependencyPackages(DependencyPackagesType): data: T.Dict[str, PackageTypes] defaults: T.Dict[str, str] = {} @@ -98,16 +102,17 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb # display the dependency name with correct casing display_name = display_name_map.get(lname, lname) - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] type_text = PerMachine('Build-time', 'Run-time')[for_machine] + ' dependency' # build a list of dependency methods to try if candidates is None: - candidates = _build_external_dependency_list(name, env, for_machine, kwargs) + candidates = _build_external_dependency_list(name, env, kwargs) pkg_exc: T.List[DependencyException] = [] pkgdep: T.List[ExternalDependency] = [] details = '' + tried_methods: T.List[str] = [] for c in candidates: # try this dependency method @@ -116,11 +121,15 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb d._check_version() pkgdep.append(d) except DependencyException as e: - assert isinstance(c, functools.partial), 'for mypy' - bettermsg = f'Dependency lookup for {name} with method {c.func.log_tried()!r} failed: {e}' + bettermsg = f'Dependency lookup for {name} with method {c.method!r} failed: {e}' mlog.debug(bettermsg) e.args = (bettermsg,) pkg_exc.append(e) + except MesonException: + raise + except Exception as e: + bettermsg = f'Dependency lookup for {name} with method {c.method!r} failed: {e}' + raise MesonBugException(bettermsg) from e else: pkg_exc.append(None) details = d.log_details() @@ -131,7 +140,6 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb # if the dependency was found if d.found(): - info: mlog.TV_LoggableList = [] if d.version: info.append(mlog.normal_cyan(d.version)) @@ -143,16 +151,11 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.green('YES'), *info) return d + tried_methods.append(c.method) # otherwise, the dependency could not be found - tried_methods = [d.log_tried() for d in pkgdep if d.log_tried()] - if tried_methods: - tried = mlog.format_list(tried_methods) - else: - tried = '' - - mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.red('NO'), - f'(tried {tried})' if tried else '') + tried = ' (tried {})'.format(mlog.format_list(tried_methods)) if tried_methods else '' + mlog.log(type_text, mlog.bold(display_name), details + 'found:', mlog.red('NO'), tried) if required: # if an exception occurred with the first detection method, re-raise it @@ -163,28 +166,27 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb # we have a list of failed ExternalDependency objects, so we can report # the methods we tried to find the dependency - raise DependencyException(f'Dependency "{name}" not found' + - (f', tried {tried}' if tried else '')) + raise DependencyException(f'Dependency "{name}" not found' + tried) return NotFoundDependency(name, env) -def _build_external_dependency_list(name: str, env: 'Environment', for_machine: MachineChoice, - kwargs: DependencyObjectKWs) -> T.List['DependencyGenerator']: +def _build_external_dependency_list(name: str, env: 'Environment', kwargs: DependencyObjectKWs + ) -> T.List['DependencyGenerator']: # Is there a specific dependency detector for this dependency? lname = name.lower() if lname in packages: - # Create the list of dependency object constructors using a factory - # class method, if one exists, otherwise the list just consists of the - # constructor - if isinstance(packages[lname], type): - entry1 = T.cast('T.Type[ExternalDependency]', packages[lname]) # mypy doesn't understand isinstance(..., type) - if issubclass(entry1, ExternalDependency): - func: T.Callable[[], 'ExternalDependency'] = functools.partial(entry1, env, kwargs) - dep = [func] + entry = packages[lname] + if isinstance(entry, type): + if issubclass(entry, ExternalDependency): + dep = [DependencyCandidate.from_dependency(name, entry, (env, kwargs))] + else: + raise MesonBugException(f'Got an invalid type in the dependency list: {entry!r}') + elif isinstance(entry, DependencyCandidate): + entry.arguments = (env, kwargs) + dep = [entry] else: - entry2 = T.cast('T.Union[DependencyFactory, WrappedFactoryFunc]', packages[lname]) - dep = entry2(env, for_machine, kwargs) + dep = entry(env, kwargs) return dep candidates: T.List['DependencyGenerator'] = [] @@ -200,24 +202,24 @@ def _build_external_dependency_list(name: str, env: 'Environment', for_machine: # Exclusive to when it is explicitly requested if DependencyMethods.DUB in methods: from .dub import DubDependency - candidates.append(functools.partial(DubDependency, name, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency(name, DubDependency, (env, kwargs))) # Preferred first candidate for auto. if DependencyMethods.PKGCONFIG in methods: from .pkgconfig import PkgConfigDependency - candidates.append(functools.partial(PkgConfigDependency, name, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency(name, PkgConfigDependency, (env, kwargs))) # On OSX only, try framework dependency detector. if DependencyMethods.EXTRAFRAMEWORK in methods: - if env.machines[for_machine].is_darwin(): + if env.machines[kwargs['native']].is_darwin(): from .framework import ExtraFrameworkDependency - candidates.append(functools.partial(ExtraFrameworkDependency, name, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency(name, ExtraFrameworkDependency, (env, kwargs))) # Only use CMake: # - if it's explicitly requested # - as a last resort, since it might not work 100% (see #6113) if DependencyMethods.CMAKE in methods: from .cmake import CMakeDependency - candidates.append(functools.partial(CMakeDependency, name, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency(name, CMakeDependency, (env, kwargs))) return candidates diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 4d219a58967f..207557852f62 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -17,7 +17,7 @@ from .. import mesonlib, mlog from ..tooldetect import get_llvm_tool_names from ..mesonlib import version_compare, version_compare_many, search_version -from .base import DependencyException, DependencyMethods, detect_compiler, strip_system_includedirs, strip_system_libdirs, SystemDependency, ExternalDependency, DependencyTypeName +from .base import DependencyException, DependencyMethods, detect_compiler, strip_system_includedirs, strip_system_libdirs, SystemDependency, ExternalDependency from .cmake import CMakeDependency from .configtool import ConfigToolDependency from .detect import packages @@ -48,12 +48,13 @@ def get_shared_library_suffix(environment: 'Environment', for_machine: MachineCh class GTestDependencySystem(SystemDependency): def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__(name, environment, kwargs, language='cpp') + kwargs['language'] = 'cpp' + super().__init__(name, environment, kwargs) self.main = kwargs.get('main', False) sysroot = environment.properties[self.for_machine].get_sys_root() or '' self.src_dirs = [sysroot + '/usr/src/gtest/src', sysroot + '/usr/src/googletest/googletest/src'] - if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): + if not self._add_sub_dependency(threads_factory(environment, {'native': self.for_machine})): self.is_found = False return self.detect() @@ -113,22 +114,24 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje class GMockDependencySystem(SystemDependency): def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__(name, environment, kwargs, language='cpp') + kwargs['language'] = 'cpp' + super().__init__(name, environment, kwargs) self.main = kwargs.get('main', False) - if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): + if not self._add_sub_dependency(threads_factory(environment, {'native': self.for_machine})): self.is_found = False return # If we are getting main() from GMock, we definitely # want to avoid linking in main() from GTest gtest_kwargs = kwargs.copy() + gtest_kwargs['native'] = self.for_machine if self.main: gtest_kwargs['main'] = False # GMock without GTest is pretty much useless # this also mimics the structure given in WrapDB, # where GMock always pulls in GTest - found = self._add_sub_dependency(gtest_factory(environment, self.for_machine, gtest_kwargs)) + found = self._add_sub_dependency(gtest_factory(environment, gtest_kwargs)) if not found: self.is_found = False return @@ -188,20 +191,21 @@ class LLVMDependencyConfigTool(ConfigToolDependency): __cpp_blacklist = {'-DNDEBUG'} def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): + kwargs['language'] = 'cpp' self.tools = get_llvm_tool_names('llvm-config') # Fedora starting with Fedora 30 adds a suffix of the number # of bits in the isa that llvm targets, for example, on x86_64 # and aarch64 the name will be llvm-config-64, on x86 and arm # it will be llvm-config-32. - if environment.machines[kwargs.get('native', mesonlib.MachineChoice.HOST)].is_64_bit: + if environment.machines[kwargs['native']].is_64_bit: self.tools.append('llvm-config-64') else: self.tools.append('llvm-config-32') # It's necessary for LLVM <= 3.8 to use the C++ linker. For 3.9 and 4.0 # the C linker works fine if only using the C API. - super().__init__(name, environment, kwargs, language='cpp') + super().__init__(name, environment, kwargs) self.provided_modules: T.List[str] = [] self.required_modules: mesonlib.OrderedSet[str] = mesonlib.OrderedSet() self.module_details: T.List[str] = [] @@ -224,7 +228,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje self._set_old_link_args() self.link_args = strip_system_libdirs(environment, self.for_machine, self.link_args) self.link_args = self.__fix_bogus_link_args(self.link_args) - if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): + if not self._add_sub_dependency(threads_factory(environment, {'native': self.for_machine})): self.is_found = False return @@ -383,18 +387,18 @@ def log_details(self) -> str: class LLVMDependencyCMake(CMakeDependency): def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) -> None: + kwargs['language'] = 'cpp' self.llvm_modules = kwargs.get('modules', []) self.llvm_opt_modules = kwargs.get('optional_modules', []) - for_machine = kwargs.get('native', mesonlib.MachineChoice.HOST) + for_machine = kwargs['native'] compilers = env.coredata.compilers[for_machine] if not compilers or not {'c', 'cpp'}.issubset(compilers): # Initialize basic variables - ExternalDependency.__init__(self, DependencyTypeName('cmake'), env, kwargs) + ExternalDependency.__init__(self, name, env, kwargs) # Initialize CMake specific variables self.found_modules: T.List[str] = [] - self.name = name langs: T.List[str] = [] if not compilers: @@ -422,7 +426,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) - ) return - super().__init__(name, env, kwargs, language='cpp', force_use_global_compilers=True) + super().__init__(name, env, kwargs, force_use_global_compilers=True) if not self.cmakebin.found(): return @@ -444,7 +448,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) - temp = ['-I' + x for x in inc_dirs] + defs self.compile_args += [x for x in temp if x not in self.compile_args] self.compile_args = strip_system_includedirs(env, self.for_machine, self.compile_args) - if not self._add_sub_dependency(threads_factory(env, self.for_machine, {})): + if not self._add_sub_dependency(threads_factory(env, {'native': self.for_machine})): self.is_found = False return @@ -506,8 +510,8 @@ class ValgrindDependency(PkgConfigDependency): Consumers of Valgrind usually only need the compile args and do not want to link to its (static) libraries. ''' - def __init__(self, env: 'Environment', kwargs: DependencyObjectKWs): - super().__init__('valgrind', env, kwargs) + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): + super().__init__(name, env, kwargs) def get_link_args(self, language: T.Optional[str] = None, raw: bool = False) -> T.List[str]: return [] @@ -554,8 +558,8 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje class JNISystemDependency(SystemDependency): - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__('jni', environment, kwargs) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): + super().__init__(name, environment, kwargs) self.feature_since = ('0.62.0', '') @@ -682,8 +686,8 @@ def __machine_info_to_platform_include_dir(m: 'MachineInfo') -> T.Optional[str]: class JDKSystemDependency(JNISystemDependency): - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__(environment, kwargs) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): + super().__init__('jni', environment, kwargs) self.feature_since = ('0.59.0', '') self.featurechecks.append(FeatureDeprecated( @@ -748,8 +752,8 @@ def _has_define(compiler: 'Compiler', dname: str, env: 'Environment') -> bool: defval, _ = compiler.get_define(dname, '', [], []) return defval is not None - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__('diasdk', environment, kwargs) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + super().__init__(name, environment, kwargs) self.is_found = False compilers = environment.coredata.compilers.host @@ -798,27 +802,27 @@ def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[s packages['llvm'] = llvm_factory = DependencyFactory( 'LLVM', [DependencyMethods.CMAKE, DependencyMethods.CONFIG_TOOL], - cmake_class=LLVMDependencyCMake, - configtool_class=LLVMDependencyConfigTool, + cmake=LLVMDependencyCMake, + configtool=LLVMDependencyConfigTool, ) packages['gtest'] = gtest_factory = DependencyFactory( 'gtest', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM], - pkgconfig_class=GTestDependencyPC, - system_class=GTestDependencySystem, + pkgconfig=GTestDependencyPC, + system=GTestDependencySystem, ) packages['gmock'] = gmock_factory = DependencyFactory( 'gmock', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM], - pkgconfig_class=GMockDependencyPC, - system_class=GMockDependencySystem, + pkgconfig=GMockDependencyPC, + system=GMockDependencySystem, ) packages['zlib'] = zlib_factory = DependencyFactory( 'zlib', [DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE, DependencyMethods.SYSTEM], cmake_name='ZLIB', - system_class=ZlibSystemDependency, + system=ZlibSystemDependency, ) diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index 2166a951ef06..7b4daf37c26d 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -68,6 +68,8 @@ class DubDependency(ExternalDependency): class_dubbin_searched = False class_cache_dir = '' + type_name = DependencyTypeName('dub') + # Map Meson Compiler ID's to Dub Compiler ID's _ID_MAP: T.Mapping[str, str] = { 'dmd': 'dmd', @@ -76,8 +78,8 @@ class DubDependency(ExternalDependency): } def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__(DependencyTypeName('dub'), environment, kwargs, language='d') - self.name = name + kwargs['language'] = 'd' + super().__init__(name, environment, kwargs) from ..compilers.d import DCompiler, d_feature_args _temp_comp = super().get_compiler() @@ -304,7 +306,7 @@ def find_package_target(pkg: DubPackDesc) -> bool: for lib in bs['libs']: if os.name != 'nt': # trying to add system libraries by pkg-config - pkgdep = PkgConfigDependency(lib, environment, {'required': True, 'silent': True}) + pkgdep = PkgConfigDependency(lib, environment, {'required': True, 'silent': True, 'native': self.for_machine}) if pkgdep.is_found: for arg in pkgdep.get_compile_args(): self.compile_args.append(arg) diff --git a/mesonbuild/dependencies/factory.py b/mesonbuild/dependencies/factory.py index 0c4ca817460e..11c91c317719 100644 --- a/mesonbuild/dependencies/factory.py +++ b/mesonbuild/dependencies/factory.py @@ -7,7 +7,8 @@ import functools import typing as T -from .base import DependencyException, DependencyMethods +from ..mesonlib import MachineChoice +from .base import DependencyCandidate, DependencyException, DependencyMethods from .base import process_method_kw from .base import BuiltinDependency, SystemDependency from .cmake import CMakeDependency @@ -15,16 +16,17 @@ from .pkgconfig import PkgConfigDependency if T.TYPE_CHECKING: - from .base import DependencyObjectKWs, ExternalDependency + from typing_extensions import TypeAlias + + from .base import DependencyObjectKWs, ExternalDependency, DepType from .configtool import ConfigToolDependency from ..environment import Environment - from ..mesonlib import MachineChoice - DependencyGenerator = T.Callable[[], ExternalDependency] + # TODO: remove this? + DependencyGenerator: TypeAlias = DependencyCandidate[ExternalDependency] FactoryFunc = T.Callable[ [ 'Environment', - MachineChoice, DependencyObjectKWs, T.List[DependencyMethods] ], @@ -34,16 +36,11 @@ WrappedFactoryFunc = T.Callable[ [ 'Environment', - MachineChoice, DependencyObjectKWs, ], 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. @@ -52,53 +49,71 @@ class DependencyFactory: 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 + :param 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 + :param 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. + :param extra_kwargs: Additional keyword arguments to add when creating the + DependencyCandidate + :param pkgconfig: A custom PackageConfig lookup to use + :param cmake_name: A name to use in a cmake class. Exclusive with :param:`cmake` + :param cmake: A custom CMake lookup to use. Exclusive with :param:`cmake_name` + :param framework: A custom AppleFramework lookup to use + :param configtool: A custom ConfigTool lookup to use. If + DependencyMethods.CONFIG_TOOL is in the `:param:methods` argument, + this must be set. + :param builtin: A custom Builtin lookup to use. If + DependencyMethods.BUILTIN is in the `:param:methods` argument, + this must be set. + :param system: A custom System lookup to use. If + DependencyMethods.SYSTEM is in the `:param:methods` argument, + this must be set. """ def __init__(self, name: str, methods: T.List[DependencyMethods], *, extra_kwargs: T.Optional[DependencyObjectKWs] = 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 {} + pkgconfig: T.Union[DependencyCandidate[PkgConfigDependency], T.Type[PkgConfigDependency], None] = PkgConfigDependency, + cmake: T.Union[DependencyCandidate[CMakeDependency], T.Type[CMakeDependency], None] = None, + framework: T.Union[DependencyCandidate[ExtraFrameworkDependency], T.Type[ExtraFrameworkDependency], None] = ExtraFrameworkDependency, + configtool: T.Union[DependencyCandidate[ConfigToolDependency], T.Type[ConfigToolDependency], None] = None, + builtin: T.Union[DependencyCandidate[BuiltinDependency], T.Type[BuiltinDependency], None] = None, + system: T.Union[DependencyCandidate[SystemDependency], T.Type[SystemDependency], None] = None): + + if DependencyMethods.CONFIG_TOOL in methods and not configtool: + raise DependencyException('A configtool dependency must have a custom class') + if DependencyMethods.BUILTIN in methods and not builtin: + raise DependencyException('A builtin dependency must have a custom class') + if DependencyMethods.SYSTEM in methods and not system: + raise DependencyException('A system dependency must have a custom class') + + if cmake_name is not None and cmake is not None: + raise DependencyException('A most one of `cmake_name` and `cmake` can be provided') + + if cmake_name is not None: + cmake = DependencyCandidate.from_dependency(cmake_name, CMakeDependency) + if cmake is None: + cmake = CMakeDependency + + def make(arg: T.Union[DependencyCandidate[DepType], T.Type[DepType], None]) -> T.Optional[DependencyCandidate[DepType]]: + if arg is None or isinstance(arg, DependencyCandidate): + return arg + return DependencyCandidate.from_dependency(name, arg) + + self.extra_kwargs = extra_kwargs self.methods = methods - self.classes: T.Dict[ - DependencyMethods, - T.Callable[['Environment', DependencyObjectKWs], ExternalDependency] - ] = { + self.classes: T.Mapping[DependencyMethods, T.Optional[DependencyCandidate[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, + DependencyMethods.EXTRAFRAMEWORK: make(framework), + DependencyMethods.PKGCONFIG: make(pkgconfig), + DependencyMethods.CMAKE: make(cmake), + DependencyMethods.SYSTEM: make(system), + DependencyMethods.BUILTIN: make(builtin), + DependencyMethods.CONFIG_TOOL: make(configtool), } - 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: @@ -115,15 +130,24 @@ def _process_method(method: DependencyMethods, env: 'Environment', for_machine: return False return True - def __call__(self, env: 'Environment', for_machine: MachineChoice, - kwargs: DependencyObjectKWs) -> T.List['DependencyGenerator']: + def __call__(self, env: 'Environment', kwargs: DependencyObjectKWs) -> 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)] + if self.extra_kwargs: + nwargs = self.extra_kwargs.copy() + nwargs.update(kwargs) + else: + nwargs = kwargs.copy() + + ret: T.List[DependencyGenerator] = [] + for m in methods: + if self._process_method(m, env, kwargs['native']): + c = self.classes[m] + if c is None: + continue + c.arguments = (env, nwargs) + ret.append(c) + return ret def factory_methods(methods: T.Set[DependencyMethods]) -> T.Callable[['FactoryFunc'], 'WrappedFactoryFunc']: @@ -138,8 +162,8 @@ def factory_methods(methods: T.Set[DependencyMethods]) -> T.Callable[['FactoryFu def inner(func: 'FactoryFunc') -> 'WrappedFactoryFunc': @functools.wraps(func) - def wrapped(env: 'Environment', for_machine: MachineChoice, kwargs: DependencyObjectKWs) -> T.List['DependencyGenerator']: - return func(env, for_machine, kwargs, process_method_kw(methods, kwargs)) + def wrapped(env: 'Environment', kwargs: DependencyObjectKWs) -> T.List['DependencyGenerator']: + return func(env, kwargs, process_method_kw(methods, kwargs)) return wrapped diff --git a/mesonbuild/dependencies/framework.py b/mesonbuild/dependencies/framework.py index a23b4a66b1b4..e3ebd3b4afe6 100644 --- a/mesonbuild/dependencies/framework.py +++ b/mesonbuild/dependencies/framework.py @@ -4,7 +4,7 @@ from __future__ import annotations from .base import DependencyTypeName, ExternalDependency, DependencyException -from ..mesonlib import MesonException, Version, stringlistify +from ..mesonlib import MesonException, Version from .. import mlog from pathlib import Path import typing as T @@ -16,10 +16,11 @@ class ExtraFrameworkDependency(ExternalDependency): system_framework_paths: T.Optional[T.List[str]] = None - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: - paths = stringlistify(kwargs.get('paths', [])) - super().__init__(DependencyTypeName('extraframeworks'), env, kwargs, language=language) - self.name = name + type_name = DependencyTypeName('extraframeworks') + + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) -> None: + paths = kwargs.get('paths', []) + super().__init__(name, env, kwargs) # Full path to framework directory self.framework_path: T.Optional[str] = None if not self.clib_compiler: @@ -111,7 +112,3 @@ def _get_framework_include_path(self, path: Path) -> T.Optional[str]: def log_info(self) -> str: return self.framework_path or '' - - @staticmethod - def log_tried() -> str: - return 'framework' diff --git a/mesonbuild/dependencies/hdf5.py b/mesonbuild/dependencies/hdf5.py index 5894cfb462bc..2c020669a6ea 100644 --- a/mesonbuild/dependencies/hdf5.py +++ b/mesonbuild/dependencies/hdf5.py @@ -4,13 +4,12 @@ # This file contains the detection logic for miscellaneous external dependencies. from __future__ import annotations -import functools import os import re from pathlib import Path -from ..mesonlib import OrderedSet, join_args, MachineChoice -from .base import DependencyException, DependencyMethods +from ..mesonlib import OrderedSet, join_args +from .base import DependencyCandidate, DependencyException, DependencyMethods from .configtool import ConfigToolDependency from .detect import packages from .pkgconfig import PkgConfigDependency, PkgConfigInterface @@ -27,12 +26,12 @@ class HDF5PkgConfigDependency(PkgConfigDependency): """Handle brokenness in the HDF5 pkg-config files.""" - def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: - language = language or 'c' + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + language = kwargs.get('language') or 'c' if language not in {'c', 'cpp', 'fortran'}: raise DependencyException(f'Language {language} is not supported with HDF5.') - super().__init__(name, environment, kwargs, language) + super().__init__(name, environment, kwargs) if not self.is_found: return @@ -78,8 +77,8 @@ class HDF5ConfigToolDependency(ConfigToolDependency): version_arg = '-showconfig' - def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: - language = language or 'c' + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + language = kwargs.get('language') or 'c' if language not in {'c', 'cpp', 'fortran'}: raise DependencyException(f'Language {language} is not supported with HDF5.') @@ -98,20 +97,19 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje else: raise DependencyException('How did you get here?') - # We need this before we call super() - for_machine = kwargs.get('native', MachineChoice.HOST) - nkwargs = kwargs.copy() nkwargs['tools'] = tools # Override the compiler that the config tools are going to use by # setting the environment variables that they use for the compiler and # linkers. + + for_machine = kwargs['native'] compiler = environment.coredata.compilers[for_machine][language] try: os.environ[f'HDF5_{cenv}'] = join_args(compiler.get_exelist()) os.environ[f'HDF5_{lenv}LINKER'] = join_args(compiler.get_linker_exelist()) - super().__init__(name, environment, nkwargs, language) + super().__init__(name, environment, nkwargs) finally: del os.environ[f'HDF5_{cenv}'] del os.environ[f'HDF5_{lenv}LINKER'] @@ -143,10 +141,10 @@ def _sanitize_version(self, ver: str) -> str: @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL}) -def hdf5_factory(env: 'Environment', for_machine: 'MachineChoice', - kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: - language = kwargs.get('language') +def hdf5_factory(env: 'Environment', kwargs: DependencyObjectKWs, + methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: candidates: T.List['DependencyGenerator'] = [] + for_machine = kwargs['native'] if DependencyMethods.PKGCONFIG in methods: # Use an ordered set so that these remain the first tried pkg-config files @@ -162,10 +160,12 @@ def hdf5_factory(env: 'Environment', for_machine: 'MachineChoice', # use just the standard files if pkg-config --list-all fails pass for mod in pkgconfig_files: - candidates.append(functools.partial(HDF5PkgConfigDependency, mod, env, kwargs, language)) + candidates.append(DependencyCandidate.from_dependency( + mod, HDF5PkgConfigDependency, (env, kwargs))) if DependencyMethods.CONFIG_TOOL in methods: - candidates.append(functools.partial(HDF5ConfigToolDependency, 'hdf5', env, kwargs, language)) + candidates.append(DependencyCandidate.from_dependency( + 'hd5f', HDF5ConfigToolDependency, (env, kwargs))) return candidates diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index b1b8b8e1319b..7612fdef7781 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -4,15 +4,14 @@ # This file contains the detection logic for miscellaneous external dependencies. from __future__ import annotations -import functools import re import typing as T from .. import mesonlib from .. import mlog -from .base import DependencyException, DependencyMethods +from .base import DependencyCandidate, DependencyException, DependencyMethods from .base import BuiltinDependency, SystemDependency -from .cmake import CMakeDependency, CMakeDependencyFactory +from .cmake import CMakeDependency from .configtool import ConfigToolDependency from .detect import packages from .factory import DependencyFactory, factory_methods @@ -27,7 +26,6 @@ @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE}) def netcdf_factory(env: 'Environment', - for_machine: 'mesonlib.MachineChoice', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: language = kwargs.get('language') @@ -44,10 +42,12 @@ def netcdf_factory(env: 'Environment', else: pkg = 'netcdf' - candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs, language=language)) + candidates.append(DependencyCandidate.from_dependency( + pkg, PkgConfigDependency, (env, kwargs))) if DependencyMethods.CMAKE in methods: - candidates.append(functools.partial(CMakeDependency, 'NetCDF', env, kwargs, language=language)) + candidates.append(DependencyCandidate.from_dependency( + 'NetCDF', CMakeDependency, (env, kwargs))) return candidates @@ -113,9 +113,8 @@ class OpenMPDependency(SystemDependency): '199810': '1.0', } - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - language = kwargs.get('language') - super().__init__('openmp', environment, kwargs, language=language) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + super().__init__(name, environment, kwargs) self.is_found = False if self.clib_compiler.get_id() == 'nagfor': # No macro defined for OpenMP, but OpenMP 3.1 is supported. @@ -181,8 +180,8 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje class BlocksDependency(SystemDependency): - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__('blocks', environment, kwargs) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + super().__init__(name, environment, kwargs) self.name = 'blocks' self.is_found = False @@ -304,8 +303,8 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje class ShadercDependency(SystemDependency): - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__('shaderc', environment, kwargs) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): + super().__init__(name, environment, kwargs) static_lib = 'shaderc_combined' shared_lib = 'shaderc_shared' @@ -336,7 +335,7 @@ class CursesConfigToolDependency(ConfigToolDependency): # ncurses5.4-config is for macOS Catalina tools = ['ncursesw6-config', 'ncursesw5-config', 'ncurses6-config', 'ncurses5-config', 'ncurses5.4-config'] - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): exclude_paths = None # macOS mistakenly ships /usr/bin/ncurses5.4-config and a man page for # it, but none of the headers or libraries. Ignore /usr/bin because it @@ -344,7 +343,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, l # Homebrew is /usr/local or /opt/homebrew. if env.machines.build and env.machines.build.system == 'darwin': exclude_paths = ['/usr/bin'] - super().__init__(name, env, kwargs, language, exclude_paths=exclude_paths) + super().__init__(name, env, kwargs, exclude_paths=exclude_paths) if not self.is_found: return self.compile_args = self.get_config_value(['--cflags'], 'compile_args') @@ -450,7 +449,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): self.is_found = True if self.static: - if not self._add_sub_dependency(iconv_factory(env, self.for_machine, {'static': True})): + if not self._add_sub_dependency(iconv_factory(env, {'static': True, 'native': self.for_machine})): self.is_found = False @@ -461,6 +460,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): dependency_kwargs: DependencyObjectKWs = { 'method': DependencyMethods.SYSTEM, 'static': self.static, + 'native': kwargs.get('native'), } if not self.clib_compiler.has_header('openssl/ssl.h', '')[0]: return @@ -478,8 +478,8 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): self.version = '.'.join(str(i) for i in version_ints[:3]) + chr(ord('a') + version_ints[3] - 1) if name == 'openssl': - if self._add_sub_dependency(libssl_factory(env, self.for_machine, dependency_kwargs)) and \ - self._add_sub_dependency(libcrypto_factory(env, self.for_machine, dependency_kwargs)): + if self._add_sub_dependency(libssl_factory(env, dependency_kwargs)) and \ + self._add_sub_dependency(libcrypto_factory(env, dependency_kwargs)): self.is_found = True return else: @@ -491,11 +491,11 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): self.is_found = True else: if name == 'libssl': - if self._add_sub_dependency(libcrypto_factory(env, self.for_machine, dependency_kwargs)): + if self._add_sub_dependency(libcrypto_factory(env, dependency_kwargs)): self.is_found = True elif name == 'libcrypto': use_threads = self.clib_compiler.has_header_symbol('openssl/opensslconf.h', 'OPENSSL_THREADS', '', dependencies=[self])[0] - if not use_threads or self._add_sub_dependency(threads_factory(env, self.for_machine, {})): + if not use_threads or self._add_sub_dependency(threads_factory(env, {'native': self.for_machine})): self.is_found = True # only relevant on platforms where it is distributed with the libc, in which case it always succeeds sublib = self.clib_compiler.find_library('dl', [], self.libtype) @@ -508,8 +508,8 @@ class ObjFWDependency(ConfigToolDependency): tools = ['objfw-config'] tool_name = 'objfw-config' - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__('objfw', environment, kwargs) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): + super().__init__(name, environment, kwargs) self.feature_since = ('1.5.0', '') if not self.is_found: return @@ -529,25 +529,28 @@ def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs): @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM}) def curses_factory(env: 'Environment', - for_machine: 'mesonlib.MachineChoice', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: candidates: T.List['DependencyGenerator'] = [] + for_machine = kwargs['native'] if DependencyMethods.PKGCONFIG in methods: pkgconfig_files = ['pdcurses', 'ncursesw', 'ncurses', 'curses'] for pkg in pkgconfig_files: - candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + pkg, PkgConfigDependency, (env, kwargs))) # There are path handling problems with these methods on msys, and they # don't apply to windows otherwise (cygwin is handled separately from # windows) if not env.machines[for_machine].is_windows(): if DependencyMethods.CONFIG_TOOL in methods: - candidates.append(functools.partial(CursesConfigToolDependency, 'curses', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'curses', CursesConfigToolDependency, (env, kwargs))) if DependencyMethods.SYSTEM in methods: - candidates.append(functools.partial(CursesSystemDependency, 'curses', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'curses', CursesSystemDependency, (env, kwargs))) return candidates packages['curses'] = curses_factory @@ -555,7 +558,6 @@ def curses_factory(env: 'Environment', @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM}) def shaderc_factory(env: 'Environment', - for_machine: 'mesonlib.MachineChoice', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: """Custom DependencyFactory for ShaderC. @@ -578,15 +580,16 @@ def shaderc_factory(env: 'Environment', if static is None: static = T.cast('bool', env.coredata.optstore.get_value_for(OptionKey('prefer_static'))) if static: - c = [functools.partial(PkgConfigDependency, name, env, kwargs) + c = [DependencyCandidate.from_dependency(name, PkgConfigDependency, (env, kwargs)) for name in static_libs + shared_libs] else: - c = [functools.partial(PkgConfigDependency, name, env, kwargs) + c = [DependencyCandidate.from_dependency(name, PkgConfigDependency, (env, kwargs)) for name in shared_libs + static_libs] candidates.extend(c) if DependencyMethods.SYSTEM in methods: - candidates.append(functools.partial(ShadercDependency, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'shaderc', ShadercDependency, (env, kwargs))) return candidates packages['shaderc'] = shaderc_factory @@ -595,89 +598,89 @@ def shaderc_factory(env: 'Environment', packages['atomic'] = atomic_factory = DependencyFactory( 'atomic', [DependencyMethods.SYSTEM, DependencyMethods.BUILTIN], - system_class=AtomicSystemDependency, - builtin_class=AtomicBuiltinDependency, + system=AtomicSystemDependency, + builtin=AtomicBuiltinDependency, ) packages['cups'] = cups_factory = DependencyFactory( 'cups', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE], - configtool_class=CupsDependencyConfigTool, + configtool=CupsDependencyConfigTool, cmake_name='Cups', ) packages['dl'] = dl_factory = DependencyFactory( 'dl', [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM], - builtin_class=DlBuiltinDependency, - system_class=DlSystemDependency, + builtin=DlBuiltinDependency, + system=DlSystemDependency, ) packages['gpgme'] = gpgme_factory = DependencyFactory( 'gpgme', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - configtool_class=GpgmeDependencyConfigTool, + configtool=GpgmeDependencyConfigTool, ) packages['libgcrypt'] = libgcrypt_factory = DependencyFactory( 'libgcrypt', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - configtool_class=LibGCryptDependencyConfigTool, + configtool=LibGCryptDependencyConfigTool, ) packages['libwmf'] = libwmf_factory = DependencyFactory( 'libwmf', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - configtool_class=LibWmfDependencyConfigTool, + configtool=LibWmfDependencyConfigTool, ) packages['pcap'] = pcap_factory = DependencyFactory( 'pcap', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - configtool_class=PcapDependencyConfigTool, - pkgconfig_name='libpcap', + configtool=PcapDependencyConfigTool, + pkgconfig=DependencyCandidate.from_dependency('libpcap', PkgConfigDependency), ) packages['threads'] = threads_factory = DependencyFactory( 'threads', [DependencyMethods.SYSTEM, DependencyMethods.CMAKE], cmake_name='Threads', - system_class=ThreadDependency, + system=ThreadDependency, ) packages['iconv'] = iconv_factory = DependencyFactory( 'iconv', [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM], - builtin_class=IconvBuiltinDependency, - system_class=IconvSystemDependency, + builtin=IconvBuiltinDependency, + system=IconvSystemDependency, ) packages['intl'] = intl_factory = DependencyFactory( 'intl', [DependencyMethods.BUILTIN, DependencyMethods.SYSTEM], - builtin_class=IntlBuiltinDependency, - system_class=IntlSystemDependency, + builtin=IntlBuiltinDependency, + system=IntlSystemDependency, ) packages['openssl'] = openssl_factory = DependencyFactory( 'openssl', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE], - system_class=OpensslSystemDependency, - cmake_class=CMakeDependencyFactory('OpenSSL', modules=['OpenSSL::Crypto', 'OpenSSL::SSL']), + system=OpensslSystemDependency, + cmake=DependencyCandidate.from_dependency('OpenSSL', CMakeDependency, modules=['OpenSSL::Crypto', 'OpenSSL::SSL']), ) packages['libcrypto'] = libcrypto_factory = DependencyFactory( 'libcrypto', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE], - system_class=OpensslSystemDependency, - cmake_class=CMakeDependencyFactory('OpenSSL', modules=['OpenSSL::Crypto']), + system=OpensslSystemDependency, + cmake=DependencyCandidate.from_dependency('OpenSSL', CMakeDependency, modules=['OpenSSL::Crypto']), ) packages['libssl'] = libssl_factory = DependencyFactory( 'libssl', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM, DependencyMethods.CMAKE], - system_class=OpensslSystemDependency, - cmake_class=CMakeDependencyFactory('OpenSSL', modules=['OpenSSL::SSL']), + system=OpensslSystemDependency, + cmake=DependencyCandidate.from_dependency('OpenSSL', CMakeDependency, modules=['OpenSSL::SSL']), ) packages['objfw'] = ObjFWDependency diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index 1eae1a49356c..8a4b49ddcb83 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -3,14 +3,13 @@ from __future__ import annotations -import functools import typing as T import os import re from ..envconfig import detect_cpu_family from ..mesonlib import Popen_safe -from .base import DependencyException, DependencyMethods, detect_compiler, SystemDependency +from .base import DependencyCandidate, DependencyException, DependencyMethods, detect_compiler, SystemDependency from .configtool import ConfigToolDependency from .detect import packages from .factory import factory_methods @@ -19,22 +18,20 @@ if T.TYPE_CHECKING: from .factory import DependencyGenerator from ..environment import Environment - from ..mesonlib import MachineChoice from .base import DependencyObjectKWs @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM}) def mpi_factory(env: 'Environment', - for_machine: 'MachineChoice', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: - language = kwargs.get('language') - if language is None: - language = 'c' + language = kwargs.get('language') or 'c' if language not in {'c', 'cpp', 'fortran'}: # OpenMPI doesn't work without any other languages return [] + for_machine = kwargs['native'] + candidates: T.List['DependencyGenerator'] = [] compiler = detect_compiler('mpi', env, for_machine, language) if not compiler: @@ -77,12 +74,12 @@ def mpi_factory(env: 'Environment', tool_names.extend(['mpifort', 'mpif90', 'mpif77']) nwargs['tools'] = tool_names - candidates.append(functools.partial( - MPIConfigToolDependency, tool_names[0], env, nwargs, language=language)) + candidates.append(DependencyCandidate.from_dependency( + tool_names[0], MPIConfigToolDependency, (env, nwargs))) if DependencyMethods.SYSTEM in methods and env.machines[for_machine].is_windows(): - candidates.append(functools.partial( - MSMPIDependency, 'msmpi', env, kwargs, language=language)) + candidates.append(DependencyCandidate.from_dependency( + 'msmpi', MSMPIDependency, (env, kwargs))) # Only OpenMPI has pkg-config, and it doesn't work with the intel compilers # for MPI, environment variables and commands like mpicc should have priority @@ -94,8 +91,8 @@ def mpi_factory(env: 'Environment', pkg_name = 'ompi-cxx' elif language == 'fortran': pkg_name = 'ompi-fort' - candidates.append(functools.partial( - PkgConfigDependency, pkg_name, env, kwargs, language=language)) + candidates.append(DependencyCandidate.from_dependency( + pkg_name, PkgConfigDependency, (env, kwargs))) return candidates @@ -105,9 +102,8 @@ def mpi_factory(env: 'Environment', class MPIConfigToolDependency(ConfigToolDependency): """Wrapper around mpicc, Intel's mpiicc and friends.""" - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, - language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language=language) + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): + super().__init__(name, env, kwargs) if not self.is_found: return @@ -215,11 +211,10 @@ class MSMPIDependency(SystemDependency): """The Microsoft MPI.""" - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, - language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language=language) + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): + super().__init__(name, env, kwargs) # MSMPI only supports the C API - if language not in {'c', 'fortran', None}: + if self.language not in {'c', 'fortran', None}: self.is_found = False return # MSMPI is only for windows, obviously diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index b628e005bd3a..2a4e91d8d722 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -306,11 +306,11 @@ def _call_pkgbin(self, args: T.List[str], env: T.Optional[EnvironOrDict] = None) class PkgConfigDependency(ExternalDependency): + type_name = DependencyTypeName('pkgconfig') + def __init__(self, name: str, environment: Environment, kwargs: DependencyObjectKWs, - language: T.Optional[str] = None, extra_paths: T.Optional[T.List[str]] = None) -> None: - super().__init__(DependencyTypeName('pkgconfig'), environment, kwargs, language=language) - self.name = name + super().__init__(name, environment, kwargs) self.is_libtool = False self.extra_paths = extra_paths or [] pkgconfig = PkgConfigInterface.instance(self.env, self.for_machine, self.silent, self.extra_paths) @@ -585,10 +585,6 @@ def extract_libtool_shlib(self, la_file: str) -> T.Optional[str]: # a path rather than the raw dlname return os.path.basename(dlname) - @staticmethod - def log_tried() -> str: - return 'pkgconfig' - def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[str] = None, configtool: T.Optional[str] = None, internal: T.Optional[str] = None, system: T.Optional[str] = None, default_value: T.Optional[str] = None, diff --git a/mesonbuild/dependencies/platform.py b/mesonbuild/dependencies/platform.py index 49ec980b2143..829220ccb26d 100644 --- a/mesonbuild/dependencies/platform.py +++ b/mesonbuild/dependencies/platform.py @@ -15,8 +15,11 @@ from .base import DependencyObjectKWs class AppleFrameworks(ExternalDependency): - def __init__(self, env: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__(DependencyTypeName('appleframeworks'), env, kwargs) + + type_name = DependencyTypeName('appleframeworks') + + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) -> None: + super().__init__(name, env, kwargs) modules = kwargs.get('modules', []) if not modules: raise DependencyException("AppleFrameworks dependency requires at least one module.") @@ -44,8 +47,4 @@ def __init__(self, env: 'Environment', kwargs: DependencyObjectKWs) -> None: def log_info(self) -> str: return ', '.join(self.frameworks) - @staticmethod - def log_tried() -> str: - return 'framework' - packages['appleframeworks'] = AppleFrameworks diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index aa2e22c6f5ef..0e40d481faf5 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -8,13 +8,14 @@ import typing as T from .. import mesonlib, mlog -from .base import process_method_kw, DependencyException, DependencyMethods, ExternalDependency, SystemDependency +from .base import process_method_kw, DependencyCandidate, DependencyException, DependencyMethods, ExternalDependency, SystemDependency from .configtool import ConfigToolDependency from .detect import packages from .factory import DependencyFactory from .framework import ExtraFrameworkDependency from .pkgconfig import PkgConfigDependency from ..envconfig import detect_cpu_family +from ..mesonlib import MachineChoice from ..programs import ExternalProgram from ..options import OptionKey @@ -23,7 +24,6 @@ from .factory import DependencyGenerator from ..environment import Environment - from ..mesonlib import MachineChoice from .base import DependencyObjectKWs class PythonIntrospectionDict(TypedDict): @@ -248,9 +248,9 @@ def sanity(self) -> bool: class _PythonDependencyBase(_Base): - def __init__(self, python_holder: 'BasicPythonExternalProgram', embed: bool, - for_machine: 'MachineChoice'): - self.for_machine = for_machine + for_machine: MachineChoice + + def __init__(self, python_holder: 'BasicPythonExternalProgram', embed: bool): self.embed = embed self.build_config = python_holder.build_config @@ -457,9 +457,10 @@ def find_libpy_windows(self, env: 'Environment', limited_api: bool = False) -> N class PythonPkgConfigDependency(PkgConfigDependency, _PythonDependencyBase): - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs, - installation: 'BasicPythonExternalProgram', embed: bool, - for_machine: 'MachineChoice'): + # name is needed for polymorphism + def __init__(self, name: str, environment: Environment, kwargs: DependencyObjectKWs, + installation: 'BasicPythonExternalProgram'): + embed = kwargs.get('embed', False) pkg_embed = '-embed' if embed and mesonlib.version_compare(installation.info['version'], '>=3.8') else '' pkg_name = f'python-{installation.version}{pkg_embed}' @@ -477,6 +478,7 @@ def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs, self.is_found = False return + for_machine = kwargs['native'] sysroot = environment.properties[for_machine].get_sys_root() or '' pkg_libdir = sysroot + pkg_libdir @@ -484,7 +486,7 @@ def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs, pkgconfig_paths = [pkg_libdir] if pkg_libdir else [] PkgConfigDependency.__init__(self, pkg_name, environment, kwargs, extra_paths=pkgconfig_paths) - _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False), for_machine) + _PythonDependencyBase.__init__(self, installation, embed) if pkg_libdir and not self.is_found: mlog.debug(f'{pkg_name!r} could not be found in {pkg_libdir_origin}, ' @@ -509,19 +511,17 @@ def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs, class PythonFrameworkDependency(ExtraFrameworkDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: DependencyObjectKWs, installation: 'BasicPythonExternalProgram', - for_machine: 'MachineChoice'): + kwargs: DependencyObjectKWs, installation: 'BasicPythonExternalProgram'): ExtraFrameworkDependency.__init__(self, name, environment, kwargs) - _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False), for_machine) + _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False)) class PythonSystemDependency(SystemDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: DependencyObjectKWs, installation: 'BasicPythonExternalProgram', - for_machine: 'MachineChoice'): + kwargs: DependencyObjectKWs, installation: BasicPythonExternalProgram): SystemDependency.__init__(self, name, environment, kwargs) - _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False), for_machine) + _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False)) # For most platforms, match pkg-config behavior. iOS is a special case; # check for that first, so that check takes priority over @@ -541,7 +541,7 @@ def __init__(self, name: str, environment: 'Environment', # compile args if self.build_config: - sysroot = environment.properties[for_machine].get_sys_root() or '' + sysroot = environment.properties[self.for_machine].get_sys_root() or '' inc_paths = mesonlib.OrderedSet([sysroot + self.build_config['c_api']['headers']]) else: inc_paths = mesonlib.OrderedSet([ @@ -559,17 +559,11 @@ def __init__(self, name: str, environment: 'Environment', if not self.clib_compiler.has_header('Python.h', '', extra_args=self.compile_args)[0]: self.is_found = False - @staticmethod - def log_tried() -> str: - return 'sysconfig' - -def python_factory(env: 'Environment', for_machine: 'MachineChoice', - kwargs: DependencyObjectKWs, +def python_factory(env: Environment, kwargs: DependencyObjectKWs, installation: T.Optional['BasicPythonExternalProgram'] = None) -> T.List['DependencyGenerator']: # We can't use the factory_methods decorator here, as we need to pass the # extra installation argument methods = process_method_kw({DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM}, kwargs) - embed = kwargs.get('embed', False) candidates: T.List['DependencyGenerator'] = [] from_installation = installation is not None # When not invoked through the python module, default installation. @@ -579,12 +573,18 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice', if DependencyMethods.PKGCONFIG in methods: if from_installation: - candidates.append(functools.partial(PythonPkgConfigDependency, env, kwargs, installation, embed, for_machine)) + candidates.append(DependencyCandidate( + functools.partial(PythonPkgConfigDependency, installation=installation), + 'python3', PythonPkgConfigDependency.type_name, arguments=(env, kwargs))) else: - candidates.append(functools.partial(PkgConfigDependency, 'python3', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'python3', PkgConfigDependency, (env, kwargs))) if DependencyMethods.SYSTEM in methods: - candidates.append(functools.partial(PythonSystemDependency, 'python', env, kwargs, installation, for_machine)) + # This is a unique log-tried. + candidates.append(DependencyCandidate( + functools.partial(PythonSystemDependency, installation=installation), + 'python', 'sysconfig', arguments=(env, kwargs))) if DependencyMethods.EXTRAFRAMEWORK in methods: nkwargs = kwargs.copy() @@ -592,7 +592,9 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice', # There is a python in /System/Library/Frameworks, but that's python 2.x, # Python 3 will always be in /Library nkwargs['paths'] = ['/Library/Frameworks'] - candidates.append(functools.partial(PythonFrameworkDependency, 'Python', env, nkwargs, installation, for_machine)) + candidates.append(DependencyCandidate( + functools.partial(PythonFrameworkDependency, installation=installation), + 'python', PythonPkgConfigDependency.type_name, arguments=(env, nkwargs))) return candidates @@ -601,11 +603,11 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice', packages['pybind11'] = pybind11_factory = DependencyFactory( 'pybind11', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.CMAKE], - configtool_class=Pybind11ConfigToolDependency, + configtool=Pybind11ConfigToolDependency, ) packages['numpy'] = numpy_factory = DependencyFactory( 'numpy', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - configtool_class=NumPyConfigToolDependency, + configtool=NumPyConfigToolDependency, ) diff --git a/mesonbuild/dependencies/qt.py b/mesonbuild/dependencies/qt.py index c245e5c8c5ee..57cdd5ec6de0 100644 --- a/mesonbuild/dependencies/qt.py +++ b/mesonbuild/dependencies/qt.py @@ -97,8 +97,8 @@ def _get_modules_lib_suffix(version: str, info: 'MachineInfo', is_debug: bool) - class QtExtraFrameworkDependency(ExtraFrameworkDependency): - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, qvars: T.Dict[str, str], language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language=language) + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, qvars: T.Dict[str, str]): + super().__init__(name, env, kwargs) self.mod_name = name[2:] self.qt_extra_include_directory = qvars['QT_INSTALL_HEADERS'] @@ -185,7 +185,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): self.link_args = [] for m in self.requested_modules: - mod = PkgConfigDependency(self.qtpkgname + m, self.env, kwargs, language=self.language) + mod = PkgConfigDependency(self.qtpkgname + m, self.env, kwargs) if not mod.found(): self.is_found = False return @@ -357,11 +357,12 @@ def _framework_detect(self, qvars: T.Dict[str, str], modules: T.List[str], kwarg fw_kwargs = kwargs.copy() fw_kwargs.pop('method') fw_kwargs['paths'] = [libdir] + fw_kwargs['language'] = self.language for m in modules: fname = 'Qt' + m mlog.debug('Looking for qt framework ' + fname) - fwdep = QtExtraFrameworkDependency(fname, self.env, fw_kwargs, qvars, language=self.language) + fwdep = QtExtraFrameworkDependency(fname, self.env, fw_kwargs, qvars) if fwdep.found(): self.compile_args.append('-F' + libdir) self.compile_args += fwdep.get_compile_args(with_private_headers=self.private_headers, @@ -467,20 +468,20 @@ def get_private_includes(self, mod_inc_dir: str, module: str) -> T.List[str]: packages['qt4'] = qt4_factory = DependencyFactory( 'qt4', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - pkgconfig_class=Qt4PkgConfigDependency, - configtool_class=Qt4ConfigToolDependency, + pkgconfig=Qt4PkgConfigDependency, + configtool=Qt4ConfigToolDependency, ) packages['qt5'] = qt5_factory = DependencyFactory( 'qt5', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - pkgconfig_class=Qt5PkgConfigDependency, - configtool_class=Qt5ConfigToolDependency, + pkgconfig=Qt5PkgConfigDependency, + configtool=Qt5ConfigToolDependency, ) packages['qt6'] = qt6_factory = DependencyFactory( 'qt6', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL], - pkgconfig_class=Qt6PkgConfigDependency, - configtool_class=Qt6ConfigToolDependency, + pkgconfig=Qt6PkgConfigDependency, + configtool=Qt6ConfigToolDependency, ) diff --git a/mesonbuild/dependencies/scalapack.py b/mesonbuild/dependencies/scalapack.py index 26a6e39044f5..92276ce68b6d 100644 --- a/mesonbuild/dependencies/scalapack.py +++ b/mesonbuild/dependencies/scalapack.py @@ -4,12 +4,11 @@ from __future__ import annotations from pathlib import Path -import functools import os import typing as T from ..options import OptionKey -from .base import DependencyException, DependencyMethods +from .base import DependencyCandidate, DependencyException, DependencyMethods from .cmake import CMakeDependency from .detect import packages from .pkgconfig import PkgConfigDependency @@ -17,13 +16,12 @@ if T.TYPE_CHECKING: from ..environment import Environment - from ..mesonlib import MachineChoice from .factory import DependencyGenerator from .base import DependencyObjectKWs @factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE}) -def scalapack_factory(env: 'Environment', for_machine: 'MachineChoice', +def scalapack_factory(env: 'Environment', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: candidates: T.List['DependencyGenerator'] = [] @@ -31,16 +29,16 @@ def scalapack_factory(env: 'Environment', for_machine: 'MachineChoice', if DependencyMethods.PKGCONFIG in methods: static_opt = kwargs['static'] if kwargs.get('static') is not None else env.coredata.optstore.get_value_for(OptionKey('prefer_static')) mkl = 'mkl-static-lp64-iomp' if static_opt else 'mkl-dynamic-lp64-iomp' - candidates.append(functools.partial( - MKLPkgConfigDependency, mkl, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + mkl, MKLPkgConfigDependency, (env, kwargs))) for pkg in ['scalapack-openmpi', 'scalapack']: - candidates.append(functools.partial( - PkgConfigDependency, pkg, env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + pkg, PkgConfigDependency, (env, kwargs))) if DependencyMethods.CMAKE in methods: - candidates.append(functools.partial( - CMakeDependency, 'Scalapack', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'Scalapack', CMakeDependency, (env, kwargs))) return candidates @@ -55,15 +53,14 @@ class MKLPkgConfigDependency(PkgConfigDependency): bunch of fixups to make it work correctly. """ - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, - language: T.Optional[str] = None): + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs): _m = os.environ.get('MKLROOT') self.__mklroot = Path(_m).resolve() if _m else None # We need to call down into the normal super() method even if we don't # find mklroot, otherwise we won't have all of the instance variables # initialized that meson expects. - super().__init__(name, env, kwargs, language=language) + super().__init__(name, env, kwargs) # Doesn't work with gcc on windows, but does on Linux if env.machines[self.for_machine].is_windows() and self.clib_compiler.id == 'gcc': diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index f000b58dd460..8c513ae9c6cf 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -57,8 +57,9 @@ class GnuStepDependency(ConfigToolDependency): tools = ['gnustep-config'] tool_name = 'gnustep-config' - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__('gnustep', environment, kwargs, language='objc') + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + kwargs['language'] = 'objc' + super().__init__(name, environment, kwargs) if not self.is_found: return self.modules = kwargs.get('modules', []) @@ -149,8 +150,11 @@ class WxDependency(ConfigToolDependency): tools = ['wx-config-3.0', 'wx-config-3.1', 'wx-config', 'wx-config-gtk3'] tool_name = 'wx-config' - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__('WxWidgets', environment, kwargs, language='cpp') + # name is intentionally ignored to maintain existing capitalization, + # but is needed for polymorphism + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): + kwargs['language'] = 'cpp' + super().__init__('WxWidgets', environment, kwargs) if not self.is_found: return self.requested_modules = kwargs.get('modules', []) @@ -175,8 +179,8 @@ def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs): class VulkanDependencySystem(SystemDependency): - def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: - super().__init__(name, environment, kwargs, language=language) + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + super().__init__(name, environment, kwargs) self.vulkan_sdk = os.environ.get('VULKAN_SDK', os.environ.get('VK_SDK_PATH')) if self.vulkan_sdk and not os.path.isabs(self.vulkan_sdk): @@ -247,18 +251,18 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje packages['gl'] = gl_factory = DependencyFactory( 'gl', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM], - system_class=GLDependencySystem, + system=GLDependencySystem, ) packages['sdl2'] = sdl2_factory = DependencyFactory( 'sdl2', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE], - configtool_class=SDL2DependencyConfigTool, + configtool=SDL2DependencyConfigTool, cmake_name='SDL2', ) packages['vulkan'] = vulkan_factory = DependencyFactory( 'vulkan', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM], - system_class=VulkanDependencySystem, + system=VulkanDependencySystem, ) diff --git a/mesonbuild/interpreter/compiler.py b/mesonbuild/interpreter/compiler.py index d5b14afbbccd..1794154cf661 100644 --- a/mesonbuild/interpreter/compiler.py +++ b/mesonbuild/interpreter/compiler.py @@ -649,6 +649,7 @@ def notfound_library(self, libname: str) -> 'dependencies.ExternalLibrary': lib = dependencies.ExternalLibrary(libname, None, self.environment, self.compiler.language, + self.held_object.for_machine, silent=True) return lib @@ -710,7 +711,7 @@ def find_library_method(self, args: T.Tuple[str], kwargs: 'FindLibraryKW') -> 'd .format(self.compiler.get_display_language(), libtype_s, libname)) lib = dependencies.ExternalLibrary(libname, linkargs, self.environment, - self.compiler.language) + self.compiler.language, self.held_object.for_machine) return lib def _has_argument_impl(self, arguments: T.Union[str, T.List[str]], diff --git a/mesonbuild/interpreter/dependencyfallbacks.py b/mesonbuild/interpreter/dependencyfallbacks.py index baf5ea39ebb9..4e4dcde564b7 100644 --- a/mesonbuild/interpreter/dependencyfallbacks.py +++ b/mesonbuild/interpreter/dependencyfallbacks.py @@ -8,7 +8,7 @@ from .. import dependencies from .. import build from ..wrap import WrapMode -from ..mesonlib import stringlistify, version_compare_many, MachineChoice +from ..mesonlib import stringlistify, version_compare_many from ..options import OptionKey from ..dependencies import Dependency, DependencyException, NotFoundDependency from ..interpreterbase import (MesonInterpreterObject, FeatureNew, @@ -96,7 +96,7 @@ def _do_dependency(self, kwargs: DependencyObjectKWs, name: str, func_kwargs: Do self._handle_featurenew_dependencies(name) dep = dependencies.find_external_dependency(name, self.environment, kwargs) if dep.found(): - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] identifier = dependencies.get_dep_identifier(name, kwargs) self.coredata.deps[for_machine].put(identifier, dep) return dep @@ -209,7 +209,7 @@ def _get_cached_dep(self, name: str, kwargs: DependencyObjectKWs) -> T.Optional[ # of None in the case the dependency is cached as not-found, or if cached # version does not match. In that case we don't want to continue with # other candidates. - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] identifier = dependencies.get_dep_identifier(name, kwargs) wanted_vers = stringlistify(kwargs.get('version', [])) @@ -366,7 +366,7 @@ def lookup(self, kwargs: DependencyObjectKWs, force_fallback: bool = False) -> D # Override this dependency to have consistent results in subsequent # dependency lookups. for name in self.names: - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] identifier = dependencies.get_dep_identifier(name, kwargs) if identifier not in self.build.dependency_overrides[for_machine]: self.build.dependency_overrides[for_machine][identifier] = \ diff --git a/mesonbuild/mdevenv.py b/mesonbuild/mdevenv.py index e6c4fad4db61..46ec1482447c 100644 --- a/mesonbuild/mdevenv.py +++ b/mesonbuild/mdevenv.py @@ -84,7 +84,7 @@ def bash_completion_files(b: build.Build, install_data: 'InstallData') -> T.List from .dependencies.pkgconfig import PkgConfigDependency result = [] dep = PkgConfigDependency('bash-completion', b.environment, - {'required': False, 'silent': True, 'version': ['>=2.10']}) + {'required': False, 'silent': True, 'version': ['>=2.10'], 'native': MachineChoice.HOST}) if dep.found(): prefix = b.environment.coredata.optstore.get_value_for(OptionKey('prefix')) assert isinstance(prefix, str), 'for mypy' diff --git a/mesonbuild/modules/_qt.py b/mesonbuild/modules/_qt.py index b75169e4b2b0..c0c67ece079f 100644 --- a/mesonbuild/modules/_qt.py +++ b/mesonbuild/modules/_qt.py @@ -15,7 +15,7 @@ from .. import options from .. import mlog from ..dependencies import DependencyMethods, find_external_dependency, Dependency, ExternalLibrary, InternalDependency -from ..mesonlib import MesonException, File, FileMode, version_compare, Popen_safe +from ..mesonlib import MachineChoice, MesonException, File, FileMode, version_compare, Popen_safe from ..interpreter import extract_required_kwarg from ..interpreter.type_checking import DEPENDENCY_METHOD_KW, INSTALL_DIR_KW, INSTALL_KW, NoneType from ..interpreterbase import ContainerTypeInfo, FeatureDeprecated, KwargInfo, noPosargs, FeatureNew, typed_kwargs, typed_pos_args @@ -270,7 +270,7 @@ def _detect_tools(self, state: ModuleState, method: DependencyMethods, required: return self._tools_detected = True mlog.log(f'Detecting Qt{self.qt_version} tools') - kwargs: DependencyObjectKWs = {'required': required, 'modules': ['Core'], 'method': method} + kwargs: DependencyObjectKWs = {'required': required, 'modules': ['Core'], 'method': method, 'native': MachineChoice.HOST} # Just pick one to make mypy happy qt = T.cast('QtPkgConfigDependency', find_external_dependency(f'qt{self.qt_version}', state.environment, kwargs)) if qt.found(): diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 99602c05ad4c..b375e2ed94d4 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -158,7 +158,7 @@ def extension_module_method(self, args: T.Tuple[str, T.List[BuildTargetSource]], new_deps = mesonlib.extract_as_list(kwargs, 'dependencies') pydep = next((dep for dep in new_deps if isinstance(dep, _PythonDependencyBase)), None) if pydep is None: - pydep = self._dependency_method_impl({}) + pydep = self._dependency_method_impl({'native': kwargs['native']}) if not pydep.found(): raise mesonlib.MesonException('Python dependency not found') new_deps.append(pydep) @@ -247,7 +247,7 @@ def _convert_api_version_to_py_version_hex(self, api_version: str, detected_vers return '0x{:02x}{:02x}0000'.format(major, minor) def _dependency_method_impl(self, kwargs: DependencyObjectKWs) -> Dependency: - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] identifier = get_dep_identifier(self._full_path(), kwargs) dep = self.interpreter.coredata.deps[for_machine].get(identifier) @@ -260,7 +260,7 @@ def _dependency_method_impl(self, kwargs: DependencyObjectKWs) -> Dependency: new_kwargs['required'] = False if build_config: new_kwargs['build_config'] = build_config - candidates = python_factory(self.interpreter.environment, for_machine, new_kwargs, self.held_object) + candidates = python_factory(self.interpreter.environment, new_kwargs, self.held_object) dep = find_external_dependency('python', self.interpreter.environment, new_kwargs, candidates) self.interpreter.coredata.deps[for_machine].put(identifier, dep) diff --git a/test cases/failing/101 no fallback/test.json b/test cases/failing/101 no fallback/test.json index 5fbffe35d893..d3f7345b0715 100644 --- a/test cases/failing/101 no fallback/test.json +++ b/test cases/failing/101 no fallback/test.json @@ -2,7 +2,7 @@ "stdout": [ { "match": "re", - "line": ".*/meson\\.build:2:11: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foob\" not found, tried .*)" + "line": ".*/meson\\.build:2:11: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foob\" not found \\(tried .*\\))" } ] } diff --git a/test cases/failing/34 dependency not-required then required/test.json b/test cases/failing/34 dependency not-required then required/test.json index 7dd8519563e0..daf4f351aa81 100644 --- a/test cases/failing/34 dependency not-required then required/test.json +++ b/test cases/failing/34 dependency not-required then required/test.json @@ -2,7 +2,7 @@ "stdout": [ { "match": "re", - "line": ".*/meson\\.build:4:10: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foo\\-bar\\-xyz\\-12\\.3\" not found, tried .*)" + "line": ".*/meson\\.build:4:10: ERROR: (Pkg-config binary for machine MachineChoice\\.HOST not found\\. Giving up\\.|Dependency \"foo\\-bar\\-xyz\\-12\\.3\" not found \\(tried .*\\))" } ] } diff --git a/test cases/failing/63 wrong boost module/test.json b/test cases/failing/63 wrong boost module/test.json index ec3c1b083abd..e3d98f4f83b8 100644 --- a/test cases/failing/63 wrong boost module/test.json +++ b/test cases/failing/63 wrong boost module/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/63 wrong boost module/meson.build:9:10: ERROR: Dependency \"boost\" not found, tried system" + "line": "test cases/failing/63 wrong boost module/meson.build:9:10: ERROR: Dependency \"boost\" not found (tried system)" } ] } diff --git a/test cases/failing/80 dub library/test.json b/test cases/failing/80 dub library/test.json index d3c7d426449e..3eccab871072 100644 --- a/test cases/failing/80 dub library/test.json +++ b/test cases/failing/80 dub library/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/80 dub library/meson.build:11:0: ERROR: Dependency \"dubtestproject\" not found" + "line": "test cases/failing/80 dub library/meson.build:11:0: ERROR: Dependency \"dubtestproject\" not found (tried dub)" } ] } diff --git a/test cases/failing/81 dub executable/test.json b/test cases/failing/81 dub executable/test.json index 8aefa170689e..23e3d27e0bf0 100644 --- a/test cases/failing/81 dub executable/test.json +++ b/test cases/failing/81 dub executable/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/81 dub executable/meson.build:11:0: ERROR: Dependency \"dubtestproject:test1\" not found" + "line": "test cases/failing/81 dub executable/meson.build:11:0: ERROR: Dependency \"dubtestproject:test1\" not found (tried dub)" } ] } diff --git a/test cases/failing/82 dub compiler/test.json b/test cases/failing/82 dub compiler/test.json index 89d1882d9652..640c307f8043 100644 --- a/test cases/failing/82 dub compiler/test.json +++ b/test cases/failing/82 dub compiler/test.json @@ -13,7 +13,7 @@ }, "stdout": [ { - "line": "test cases/failing/82 dub compiler/meson.build:17:0: ERROR: Dependency \"dubtestproject:test2\" not found" + "line": "test cases/failing/82 dub compiler/meson.build:17:0: ERROR: Dependency \"dubtestproject:test2\" not found (tried dub)" } ] } diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 385b195eaf04..f5174e8b7156 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -2155,7 +2155,7 @@ def test_pkgconfig_gen_escaping(self): # Find foo dependency os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir env = get_fake_env(testdir, self.builddir, self.prefix) - kwargs = {'required': True, 'silent': True} + kwargs = {'required': True, 'silent': True, 'native': MachineChoice.HOST} foo_dep = PkgConfigDependency('libanswer', env, kwargs) # Ensure link_args are properly quoted libdir = PurePath(prefix) / PurePath(libdir) diff --git a/unittests/internaltests.py b/unittests/internaltests.py index 74b36a83ed3d..27de7afb10b4 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -667,7 +667,7 @@ def _call_pkgbin(self, args, env=None): with mock.patch.object(PkgConfigInterface, 'instance') as instance_method: instance_method.return_value = FakeInstance(env, MachineChoice.HOST, silent=True) - kwargs = {'required': True, 'silent': True} + kwargs = {'required': True, 'silent': True, 'native': MachineChoice.HOST} foo_dep = PkgConfigDependency('foo', env, kwargs) self.assertEqual(foo_dep.get_link_args(), [(p1 / 'libfoo.a').as_posix(), (p2 / 'libbar.a').as_posix()]) @@ -1038,14 +1038,14 @@ def test_dependency_factory_order(self): 'test_dep', methods=[b.DependencyMethods.PKGCONFIG, b.DependencyMethods.CMAKE] ) - actual = [m() for m in f(env, MachineChoice.HOST, {'required': False})] + actual = [m() for m in f(env, {'required': False, 'native': MachineChoice.HOST})] self.assertListEqual([m.type_name for m in actual], ['pkgconfig', 'cmake']) f = F.DependencyFactory( 'test_dep', methods=[b.DependencyMethods.CMAKE, b.DependencyMethods.PKGCONFIG] ) - actual = [m() for m in f(env, MachineChoice.HOST, {'required': False})] + actual = [m() for m in f(env, {'required': False, 'native': MachineChoice.HOST})] self.assertListEqual([m.type_name for m in actual], ['cmake', 'pkgconfig']) def test_validate_json(self) -> None: diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index a97a1f106a6a..284fe205883a 100644 --- a/unittests/linuxliketests.py +++ b/unittests/linuxliketests.py @@ -149,7 +149,7 @@ def test_pkgconfig_gen(self): testdir = os.path.join(self.common_test_dir, '44 pkgconfig-gen') self.init(testdir) env = get_fake_env(testdir, self.builddir, self.prefix) - kwargs = {'required': True, 'silent': True} + kwargs = {'required': True, 'silent': True, 'native': MachineChoice.HOST} os.environ['PKG_CONFIG_LIBDIR'] = self.privatedir foo_dep = PkgConfigDependency('libfoo', env, kwargs) self.assertTrue(foo_dep.found()) @@ -1145,7 +1145,7 @@ def test_pkgconfig_relative_paths(self): env = get_fake_env(testdir, self.builddir, self.prefix) env.coredata.optstore.set_option(OptionKey('pkg_config_path'), pkg_dir) - kwargs = {'required': True, 'silent': True} + kwargs = {'required': True, 'silent': True, 'native': MachineChoice.HOST} relative_path_dep = PkgConfigDependency('librelativepath', env, kwargs) self.assertTrue(relative_path_dep.found())