From 18fc4423edffdb2fba5d5b181b4ef1931c0cffd3 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 15:51:29 -0700 Subject: [PATCH 01/13] dependencies: Annotate the DependencyPackages class --- mesonbuild/dependencies/detect.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py index f00075b0dd40..8682e6727804 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -20,8 +20,12 @@ 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] + # 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] = {} From 228dd7879d657aacca35daca4495e0ff4490a87c Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 09:14:25 -0700 Subject: [PATCH 02/13] dependencies: Move type_name to class level This is really class constant for all dependencies, and by taking it out of the initializer we make the `__init__` call have a more consistent interface. --- mesonbuild/dependencies/base.py | 34 +++++++++++++++++++-------- mesonbuild/dependencies/cmake.py | 4 +++- mesonbuild/dependencies/configtool.py | 3 ++- mesonbuild/dependencies/dev.py | 4 ++-- mesonbuild/dependencies/dub.py | 4 +++- mesonbuild/dependencies/framework.py | 4 +++- mesonbuild/dependencies/pkgconfig.py | 4 +++- mesonbuild/dependencies/platform.py | 5 +++- 8 files changed, 44 insertions(+), 18 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 4536746d940f..1de6e1bcf05d 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -129,7 +129,9 @@ 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 @@ -137,7 +139,6 @@ def __init__(self, type_name: DependencyTypeName, kwargs: DependencyObjectKWs) - self.version: T.Optional[str] = None self.language: T.Optional[str] = None # 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 +299,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 +312,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__({}) self.version = version self.is_found = True self.include_directories = incdirs @@ -412,10 +416,10 @@ 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, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None): + Dependency.__init__(self, kwargs) self.env = environment - self.name = type_name # default + self.name = str(self.type_name) self.is_found = False self.language = language self.version_reqs = kwargs.get('version', []) @@ -499,8 +503,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__({}) self.env = environment self.name = name self.is_found = False @@ -514,9 +521,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) + super().__init__(environment, {}, language=language) self.name = name self.language = language self.is_found = False @@ -660,9 +670,11 @@ class SystemDependency(ExternalDependency): """Dependency base for System type dependencies.""" + type_name = DependencyTypeName('system') + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: - super().__init__(DependencyTypeName('system'), env, kwargs, language=language) + super().__init__(env, kwargs, language=language) self.name = name @staticmethod @@ -674,9 +686,11 @@ class BuiltinDependency(ExternalDependency): """Dependency base for Builtin type dependencies.""" + type_name = DependencyTypeName('builtin') + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: - super().__init__(DependencyTypeName('builtin'), env, kwargs, language=language) + super().__init__(env, kwargs, language=language) self.name = name @staticmethod diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 066bb29007bd..2e7d19465b99 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -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}') @@ -88,7 +90,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) + super().__init__(environment, kwargs, language=language) self.name = name self.is_libtool = False diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index e2721fe3bbd0..fa1d05afc0fe 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -36,9 +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) + super().__init__(environment, kwargs, language=language) self.name = name # You may want to overwrite the class version in some cases self.tools = listify(kwargs.get('tools', self.tools)) diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 4d219a58967f..6b6e13000ce6 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 @@ -390,7 +390,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) - 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, env, kwargs) # Initialize CMake specific variables self.found_modules: T.List[str] = [] diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index 2166a951ef06..e00a7232a168 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,7 +78,7 @@ class DubDependency(ExternalDependency): } def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__(DependencyTypeName('dub'), environment, kwargs, language='d') + super().__init__(environment, kwargs, language='d') self.name = name from ..compilers.d import DCompiler, d_feature_args diff --git a/mesonbuild/dependencies/framework.py b/mesonbuild/dependencies/framework.py index a23b4a66b1b4..9c897614fc91 100644 --- a/mesonbuild/dependencies/framework.py +++ b/mesonbuild/dependencies/framework.py @@ -16,9 +16,11 @@ class ExtraFrameworkDependency(ExternalDependency): system_framework_paths: T.Optional[T.List[str]] = None + type_name = DependencyTypeName('extraframeworks') + 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) + super().__init__(env, kwargs, language=language) self.name = name # Full path to framework directory self.framework_path: T.Optional[str] = None diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index b628e005bd3a..163f98959f3c 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -306,10 +306,12 @@ 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) + super().__init__(environment, kwargs, language=language) self.name = name self.is_libtool = False self.extra_paths = extra_paths or [] diff --git a/mesonbuild/dependencies/platform.py b/mesonbuild/dependencies/platform.py index 49ec980b2143..954556f418a7 100644 --- a/mesonbuild/dependencies/platform.py +++ b/mesonbuild/dependencies/platform.py @@ -15,8 +15,11 @@ from .base import DependencyObjectKWs class AppleFrameworks(ExternalDependency): + + type_name = DependencyTypeName('appleframeworks') + def __init__(self, env: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__(DependencyTypeName('appleframeworks'), env, kwargs) + super().__init__(env, kwargs) modules = kwargs.get('modules', []) if not modules: raise DependencyException("AppleFrameworks dependency requires at least one module.") From ec98a545b76a212bbc36d04cdb04c295606e8528 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 09:26:35 -0700 Subject: [PATCH 03/13] dependencies: Pass the `name` to `ExternalDependency` constructor So we don't create a default name that is overwritten except in the case of appleframeworks. This allows for some cleanup, including deleting some initializers that were only setting the name. --- mesonbuild/dependencies/base.py | 17 +++-------------- mesonbuild/dependencies/boost.py | 4 ++-- mesonbuild/dependencies/cmake.py | 3 +-- mesonbuild/dependencies/coarrays.py | 6 +++--- mesonbuild/dependencies/configtool.py | 3 +-- mesonbuild/dependencies/cuda.py | 4 ++-- mesonbuild/dependencies/dev.py | 19 +++++++++---------- mesonbuild/dependencies/dub.py | 3 +-- mesonbuild/dependencies/framework.py | 3 +-- mesonbuild/dependencies/misc.py | 18 +++++++++--------- mesonbuild/dependencies/pkgconfig.py | 3 +-- mesonbuild/dependencies/platform.py | 4 ++-- mesonbuild/dependencies/python.py | 5 +++-- mesonbuild/dependencies/ui.py | 8 +++++--- 14 files changed, 43 insertions(+), 57 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 1de6e1bcf05d..eadd8afb899e 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -416,10 +416,10 @@ def get_as_shared(self, recursive: bool) -> InternalDependency: return new_dep class ExternalDependency(Dependency): - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None): Dependency.__init__(self, kwargs) self.env = environment - self.name = str(self.type_name) + self.name = name self.is_found = False self.language = language self.version_reqs = kwargs.get('version', []) @@ -526,8 +526,7 @@ class ExternalLibrary(ExternalDependency): def __init__(self, name: str, link_args: T.List[str], environment: 'Environment', language: str, silent: bool = False) -> None: - super().__init__(environment, {}, language=language) - self.name = name + super().__init__(name, environment, {}, language=language) self.language = language self.is_found = False if link_args: @@ -672,11 +671,6 @@ class SystemDependency(ExternalDependency): type_name = DependencyTypeName('system') - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, - language: T.Optional[str] = None) -> None: - super().__init__(env, kwargs, language=language) - self.name = name - @staticmethod def log_tried() -> str: return 'system' @@ -688,11 +682,6 @@ class BuiltinDependency(ExternalDependency): type_name = DependencyTypeName('builtin') - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, - language: T.Optional[str] = None) -> None: - super().__init__(env, kwargs, language=language) - self.name = name - @staticmethod def log_tried() -> str: return 'builtin' diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 1aeb451f1634..b4d7ba740348 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -340,8 +340,8 @@ 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: + super().__init__(name, environment, kwargs, language='cpp') buildtype = environment.coredata.optstore.get_value_for(OptionKey('buildtype')) assert isinstance(buildtype, str) self.debug = buildtype.startswith('debug') diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 2e7d19465b99..591c68ea0990 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -90,8 +90,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__(environment, kwargs, language=language) - self.name = name + super().__init__(name, environment, kwargs, language=language) self.is_libtool = False # Where all CMake "build dirs" are located diff --git a/mesonbuild/dependencies/coarrays.py b/mesonbuild/dependencies/coarrays.py index a4dbdc535c45..0c8750ced4cf 100644 --- a/mesonbuild/dependencies/coarrays.py +++ b/mesonbuild/dependencies/coarrays.py @@ -41,7 +41,7 @@ def coarray_factory(env: 'Environment', CMakeDependency, 'OpenCoarrays', env, kwargs, language='fortran')) if DependencyMethods.SYSTEM in methods: - candidates.append(functools.partial(CoarrayDependency, env, kwargs)) + candidates.append(functools.partial(CoarrayDependency, 'coarray', env, kwargs)) return candidates packages['coarray'] = coarray_factory @@ -56,8 +56,8 @@ 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') + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + super().__init__(name, environment, kwargs, language='fortran') kwargs['required'] = False kwargs['silent'] = True diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index fa1d05afc0fe..a87062114437 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -39,8 +39,7 @@ class ConfigToolDependency(ExternalDependency): 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__(environment, kwargs, language=language) - self.name = name + super().__init__(name, environment, kwargs, language=language) # You may want to overwrite the class version in some cases self.tools = listify(kwargs.get('tools', self.tools)) if not self.tool_name: diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index d80c62d8de4c..276b886f1468 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -28,7 +28,7 @@ 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: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: for_machine = kwargs.get('native', mesonlib.MachineChoice.HOST) compilers = environment.coredata.compilers[for_machine] machine = environment.machines[for_machine] @@ -37,7 +37,7 @@ def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> N 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}.') - super().__init__('cuda', environment, kwargs, language=language) + super().__init__(name, environment, kwargs, language=language) 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/dev.py b/mesonbuild/dependencies/dev.py index 6b6e13000ce6..c63aa8e0fe84 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -390,11 +390,10 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) - compilers = env.coredata.compilers[for_machine] if not compilers or not {'c', 'cpp'}.issubset(compilers): # Initialize basic variables - ExternalDependency.__init__(self, 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: @@ -506,8 +505,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 +553,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 +681,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 +747,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 diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index e00a7232a168..a10a86c5e9cb 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -78,8 +78,7 @@ class DubDependency(ExternalDependency): } def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__(environment, kwargs, language='d') - self.name = name + super().__init__(name, environment, kwargs, language='d') from ..compilers.d import DCompiler, d_feature_args _temp_comp = super().get_compiler() diff --git a/mesonbuild/dependencies/framework.py b/mesonbuild/dependencies/framework.py index 9c897614fc91..1f564668255c 100644 --- a/mesonbuild/dependencies/framework.py +++ b/mesonbuild/dependencies/framework.py @@ -20,8 +20,7 @@ class ExtraFrameworkDependency(ExternalDependency): def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: paths = stringlistify(kwargs.get('paths', [])) - super().__init__(env, kwargs, language=language) - self.name = name + super().__init__(name, env, kwargs, language=language) # Full path to framework directory self.framework_path: T.Optional[str] = None if not self.clib_compiler: diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index b1b8b8e1319b..9c9475574aaa 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -113,9 +113,9 @@ class OpenMPDependency(SystemDependency): '199810': '1.0', } - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: language = kwargs.get('language') - super().__init__('openmp', environment, kwargs, language=language) + super().__init__(name, environment, kwargs, language=language) self.is_found = False if self.clib_compiler.get_id() == 'nagfor': # No macro defined for OpenMP, but OpenMP 3.1 is supported. @@ -181,8 +181,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 +304,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' @@ -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 @@ -586,7 +586,7 @@ def shaderc_factory(env: 'Environment', candidates.extend(c) if DependencyMethods.SYSTEM in methods: - candidates.append(functools.partial(ShadercDependency, env, kwargs)) + candidates.append(functools.partial(ShadercDependency, 'shaderc', env, kwargs)) return candidates packages['shaderc'] = shaderc_factory diff --git a/mesonbuild/dependencies/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index 163f98959f3c..c27841eeacbd 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -311,8 +311,7 @@ class PkgConfigDependency(ExternalDependency): 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__(environment, kwargs, language=language) - self.name = name + super().__init__(name, environment, kwargs, language=language) self.is_libtool = False self.extra_paths = extra_paths or [] pkgconfig = PkgConfigInterface.instance(self.env, self.for_machine, self.silent, self.extra_paths) diff --git a/mesonbuild/dependencies/platform.py b/mesonbuild/dependencies/platform.py index 954556f418a7..f193c87ebe2f 100644 --- a/mesonbuild/dependencies/platform.py +++ b/mesonbuild/dependencies/platform.py @@ -18,8 +18,8 @@ class AppleFrameworks(ExternalDependency): type_name = DependencyTypeName('appleframeworks') - def __init__(self, env: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__(env, kwargs) + 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.") diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index aa2e22c6f5ef..f979e705ec5f 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -457,7 +457,8 @@ def find_libpy_windows(self, env: 'Environment', limited_api: bool = False) -> N class PythonPkgConfigDependency(PkgConfigDependency, _PythonDependencyBase): - def __init__(self, environment: 'Environment', kwargs: DependencyObjectKWs, + # name is needed for polymorphism + def __init__(self, name: str, environment: Environment, kwargs: DependencyObjectKWs, installation: 'BasicPythonExternalProgram', embed: bool, for_machine: 'MachineChoice'): pkg_embed = '-embed' if embed and mesonlib.version_compare(installation.info['version'], '>=3.8') else '' @@ -579,7 +580,7 @@ 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(functools.partial(PythonPkgConfigDependency, 'python3', env, kwargs, installation, embed, for_machine)) else: candidates.append(functools.partial(PkgConfigDependency, 'python3', env, kwargs)) diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index f000b58dd460..52567354059a 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -57,8 +57,8 @@ 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: + super().__init__(name, environment, kwargs, language='objc') if not self.is_found: return self.modules = kwargs.get('modules', []) @@ -149,7 +149,9 @@ 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): + # name is intentionally ignored to maintain existing capitalization, + # but is needed for polymorphism + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): super().__init__('WxWidgets', environment, kwargs, language='cpp') if not self.is_found: return From 9ecc5adaba48ae6733afbaaaddc271001b0db5ee Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 09:27:50 -0700 Subject: [PATCH 04/13] dependencies/framework: remove useless stringlistify call We have type checking that ensures this is a string list already. --- mesonbuild/dependencies/framework.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mesonbuild/dependencies/framework.py b/mesonbuild/dependencies/framework.py index 1f564668255c..627e43b52392 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 @@ -19,7 +19,7 @@ class ExtraFrameworkDependency(ExternalDependency): type_name = DependencyTypeName('extraframeworks') def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: - paths = stringlistify(kwargs.get('paths', [])) + paths = kwargs.get('paths', []) super().__init__(name, env, kwargs, language=language) # Full path to framework directory self.framework_path: T.Optional[str] = None From 5ef140770411e76daa0c74a7e38974b7d44d3338 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 14:06:43 -0700 Subject: [PATCH 05/13] dependencies: stop passing "language" as a keyword argument It's allowed in the `DependencyKeywordArguments` TypeDict already, so we now have two sources of truth. Additionally, it's often populated by reading from that dict, so we're just doing useless work. --- mesonbuild/dependencies/base.py | 8 +++--- mesonbuild/dependencies/boost.py | 5 ++-- mesonbuild/dependencies/cmake.py | 9 ++++--- mesonbuild/dependencies/coarrays.py | 12 +++++---- mesonbuild/dependencies/configtool.py | 4 +-- mesonbuild/dependencies/cuda.py | 9 ++++--- mesonbuild/dependencies/detect.py | 9 ++++--- mesonbuild/dependencies/dev.py | 23 ++++++++++------- mesonbuild/dependencies/dub.py | 3 ++- mesonbuild/dependencies/factory.py | 13 +++++----- mesonbuild/dependencies/framework.py | 4 +-- mesonbuild/dependencies/hdf5.py | 22 ++++++++-------- mesonbuild/dependencies/misc.py | 26 +++++++++---------- mesonbuild/dependencies/mpi.py | 27 +++++++++---------- mesonbuild/dependencies/pkgconfig.py | 3 +-- mesonbuild/dependencies/python.py | 37 ++++++++++++--------------- mesonbuild/dependencies/qt.py | 9 ++++--- mesonbuild/dependencies/scalapack.py | 8 +++--- mesonbuild/dependencies/ui.py | 10 +++++--- mesonbuild/modules/python.py | 2 +- unittests/internaltests.py | 4 +-- 21 files changed, 124 insertions(+), 123 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index eadd8afb899e..293f772a851f 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -137,7 +137,7 @@ def __init__(self, kwargs: DependencyObjectKWs) -> None: 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.compile_args: T.List[str] = [] self.link_args: T.List[str] = [] @@ -416,12 +416,11 @@ def get_as_shared(self, recursive: bool) -> InternalDependency: return new_dep class ExternalDependency(Dependency): - def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None): + def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): Dependency.__init__(self, kwargs) self.env = environment 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) @@ -526,8 +525,7 @@ class ExternalLibrary(ExternalDependency): def __init__(self, name: str, link_args: T.List[str], environment: 'Environment', language: str, silent: bool = False) -> None: - super().__init__(name, environment, {}, language=language) - self.language = language + super().__init__(name, environment, {'language': language}) self.is_found = False if link_args: self.is_found = True diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index b4d7ba740348..171c49455a9a 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -341,7 +341,8 @@ def get_link_args(self) -> T.List[str]: class BoostDependency(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) 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, name: str, environment: Environment, kwargs: DependencyObject # 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 diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 591c68ea0990..e8881cda26e2 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -72,9 +72,10 @@ 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) compilers = environment.coredata.compilers[for_machine] @@ -90,7 +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__(name, environment, kwargs, language=language) + super().__init__(name, environment, kwargs) self.is_libtool = False # Where all CMake "build dirs" are located @@ -650,10 +651,10 @@ def __init__(self, name: T.Optional[str] = None, modules: T.Optional[T.List[str] 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: + def __call__(self, name: str, env: Environment, kwargs: DependencyObjectKWs, 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) + return CMakeDependency(self.name or name, env, kwargs, force_use_global_compilers) @staticmethod def log_tried() -> str: diff --git a/mesonbuild/dependencies/coarrays.py b/mesonbuild/dependencies/coarrays.py index 0c8750ced4cf..d75eb58578d4 100644 --- a/mesonbuild/dependencies/coarrays.py +++ b/mesonbuild/dependencies/coarrays.py @@ -6,6 +6,7 @@ import functools import typing as T +from ..mesonlib import MachineChoice from .base import DependencyMethods, detect_compiler, SystemDependency from .cmake import CMakeDependency from .detect import packages @@ -15,15 +16,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.get('native', MachineChoice.HOST) fcid = detect_compiler('coarray', env, for_machine, 'fortran').get_id() candidates: T.List['DependencyGenerator'] = [] @@ -32,13 +33,13 @@ def coarray_factory(env: 'Environment', if DependencyMethods.PKGCONFIG in methods: for pkg in ['caf-openmpi', 'caf']: candidates.append(functools.partial( - PkgConfigDependency, pkg, env, kwargs, language='fortran')) + PkgConfigDependency, pkg, env, kwargs)) if DependencyMethods.CMAKE in methods: if not kwargs.get('modules'): kwargs['modules'] = ['OpenCoarrays::caf_mpi'] candidates.append(functools.partial( - CMakeDependency, 'OpenCoarrays', env, kwargs, language='fortran')) + CMakeDependency, 'OpenCoarrays', env, kwargs)) if DependencyMethods.SYSTEM in methods: candidates.append(functools.partial(CoarrayDependency, 'coarray', env, kwargs)) @@ -57,7 +58,8 @@ class CoarrayDependency(SystemDependency): low-level MPI calls. """ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__(name, environment, kwargs, language='fortran') + kwargs['language'] = 'fortran' + super().__init__(name, environment, kwargs) kwargs['required'] = False kwargs['silent'] = True diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index a87062114437..024bf94300c1 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -38,8 +38,8 @@ class ConfigToolDependency(ExternalDependency): __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__(name, environment, kwargs, language=language) + 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: diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index 276b886f1468..75f6cb9e57fa 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -32,12 +32,13 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje for_machine = kwargs.get('native', mesonlib.MachineChoice.HOST) 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__(name, 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 8682e6727804..0681913a1704 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -107,7 +107,7 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb # 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] = [] @@ -173,8 +173,8 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb 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: @@ -188,7 +188,7 @@ def _build_external_dependency_list(name: str, env: 'Environment', for_machine: dep = [func] else: entry2 = T.cast('T.Union[DependencyFactory, WrappedFactoryFunc]', packages[lname]) - dep = entry2(env, for_machine, kwargs) + dep = entry2(env, kwargs) return dep candidates: T.List['DependencyGenerator'] = [] @@ -213,6 +213,7 @@ def _build_external_dependency_list(name: str, env: 'Environment', for_machine: # On OSX only, try framework dependency detector. if DependencyMethods.EXTRAFRAMEWORK in methods: + for_machine = kwargs.get('native', MachineChoice.HOST) if env.machines[for_machine].is_darwin(): from .framework import ExtraFrameworkDependency candidates.append(functools.partial(ExtraFrameworkDependency, name, env, kwargs)) diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index c63aa8e0fe84..dd21b910f0f9 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -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,6 +191,7 @@ 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 @@ -201,7 +205,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje # 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,6 +387,7 @@ 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', []) @@ -421,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 @@ -443,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 diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index a10a86c5e9cb..cfd04ee007a3 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -78,7 +78,8 @@ class DubDependency(ExternalDependency): } def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__(name, environment, kwargs, language='d') + kwargs['language'] = 'd' + super().__init__(name, environment, kwargs) from ..compilers.d import DCompiler, d_feature_args _temp_comp = super().get_compiler() diff --git a/mesonbuild/dependencies/factory.py b/mesonbuild/dependencies/factory.py index 0c4ca817460e..2afe28847033 100644 --- a/mesonbuild/dependencies/factory.py +++ b/mesonbuild/dependencies/factory.py @@ -7,6 +7,7 @@ import functools import typing as T +from ..mesonlib import MachineChoice from .base import DependencyException, DependencyMethods from .base import process_method_kw from .base import BuiltinDependency, SystemDependency @@ -18,13 +19,11 @@ from .base import DependencyObjectKWs, ExternalDependency from .configtool import ConfigToolDependency from ..environment import Environment - from ..mesonlib import MachineChoice DependencyGenerator = T.Callable[[], ExternalDependency] FactoryFunc = T.Callable[ [ 'Environment', - MachineChoice, DependencyObjectKWs, T.List[DependencyMethods] ], @@ -34,7 +33,6 @@ WrappedFactoryFunc = T.Callable[ [ 'Environment', - MachineChoice, DependencyObjectKWs, ], T.List[DependencyGenerator] @@ -115,13 +113,14 @@ 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) + for_machine = kwargs.get('native', MachineChoice.HOST) + return [functools.partial(self.classes[m], env, nwargs) for m in methods if self._process_method(m, env, for_machine)] @@ -138,8 +137,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 627e43b52392..15c4ce2fffca 100644 --- a/mesonbuild/dependencies/framework.py +++ b/mesonbuild/dependencies/framework.py @@ -18,9 +18,9 @@ class ExtraFrameworkDependency(ExternalDependency): type_name = DependencyTypeName('extraframeworks') - def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs, language: T.Optional[str] = None) -> None: + def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) -> None: paths = kwargs.get('paths', []) - super().__init__(name, env, kwargs, language=language) + super().__init__(name, env, kwargs) # Full path to framework directory self.framework_path: T.Optional[str] = None if not self.clib_compiler: diff --git a/mesonbuild/dependencies/hdf5.py b/mesonbuild/dependencies/hdf5.py index 5894cfb462bc..75331f254b0b 100644 --- a/mesonbuild/dependencies/hdf5.py +++ b/mesonbuild/dependencies/hdf5.py @@ -27,12 +27,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 +78,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.') @@ -111,7 +111,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje 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 +143,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.get('native', MachineChoice.HOST) if DependencyMethods.PKGCONFIG in methods: # Use an ordered set so that these remain the first tried pkg-config files @@ -162,10 +162,10 @@ 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(functools.partial(HDF5PkgConfigDependency, mod, env, kwargs)) if DependencyMethods.CONFIG_TOOL in methods: - candidates.append(functools.partial(HDF5ConfigToolDependency, 'hdf5', env, kwargs, language)) + candidates.append(functools.partial(HDF5ConfigToolDependency, 'hdf5', env, kwargs)) return candidates diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 9c9475574aaa..b5c3f54de941 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -27,7 +27,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 +43,10 @@ def netcdf_factory(env: 'Environment', else: pkg = 'netcdf' - candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs, language=language)) + candidates.append(functools.partial(PkgConfigDependency, pkg, env, kwargs)) if DependencyMethods.CMAKE in methods: - candidates.append(functools.partial(CMakeDependency, 'NetCDF', env, kwargs, language=language)) + candidates.append(functools.partial(CMakeDependency, 'NetCDF', env, kwargs)) return candidates @@ -114,8 +113,7 @@ class OpenMPDependency(SystemDependency): } def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - language = kwargs.get('language') - super().__init__(name, environment, kwargs, language=language) + 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. @@ -336,7 +334,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 +342,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 +448,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 +459,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 +477,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 +490,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) @@ -529,10 +528,10 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje @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.get('native', mesonlib.MachineChoice.HOST) if DependencyMethods.PKGCONFIG in methods: pkgconfig_files = ['pdcurses', 'ncursesw', 'ncurses', 'curses'] @@ -555,7 +554,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. diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index 1eae1a49356c..00e5a98416ac 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -8,6 +8,7 @@ import os import re +from ..mesonlib import MachineChoice from ..envconfig import detect_cpu_family from ..mesonlib import Popen_safe from .base import DependencyException, DependencyMethods, detect_compiler, SystemDependency @@ -19,22 +20,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.get('native', MachineChoice.HOST) + candidates: T.List['DependencyGenerator'] = [] compiler = detect_compiler('mpi', env, for_machine, language) if not compiler: @@ -78,11 +77,11 @@ def mpi_factory(env: 'Environment', nwargs['tools'] = tool_names candidates.append(functools.partial( - MPIConfigToolDependency, tool_names[0], env, nwargs, language=language)) + MPIConfigToolDependency, tool_names[0], env, nwargs)) if DependencyMethods.SYSTEM in methods and env.machines[for_machine].is_windows(): candidates.append(functools.partial( - MSMPIDependency, 'msmpi', env, kwargs, language=language)) + MSMPIDependency, 'msmpi', 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 @@ -95,7 +94,7 @@ def mpi_factory(env: 'Environment', elif language == 'fortran': pkg_name = 'ompi-fort' candidates.append(functools.partial( - PkgConfigDependency, pkg_name, env, kwargs, language=language)) + PkgConfigDependency, pkg_name, env, kwargs)) return candidates @@ -105,9 +104,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 +213,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 c27841eeacbd..938c77da474d 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -309,9 +309,8 @@ 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__(name, environment, kwargs, language=language) + 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) diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index f979e705ec5f..ad9262981c3f 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -15,6 +15,7 @@ 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 @@ -459,8 +459,8 @@ class PythonPkgConfigDependency(PkgConfigDependency, _PythonDependencyBase): # name is needed for polymorphism def __init__(self, name: str, environment: Environment, kwargs: DependencyObjectKWs, - installation: 'BasicPythonExternalProgram', embed: bool, - for_machine: 'MachineChoice'): + 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}' @@ -478,6 +478,7 @@ def __init__(self, name: str, environment: Environment, kwargs: DependencyObject self.is_found = False return + for_machine = kwargs.get('native', MachineChoice.HOST) sysroot = environment.properties[for_machine].get_sys_root() or '' pkg_libdir = sysroot + pkg_libdir @@ -485,7 +486,7 @@ def __init__(self, name: str, environment: Environment, kwargs: DependencyObject 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}, ' @@ -510,19 +511,17 @@ def __init__(self, name: str, environment: Environment, kwargs: DependencyObject 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 @@ -542,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([ @@ -564,13 +563,11 @@ def __init__(self, name: str, environment: 'Environment', 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. @@ -580,12 +577,12 @@ def python_factory(env: 'Environment', for_machine: 'MachineChoice', if DependencyMethods.PKGCONFIG in methods: if from_installation: - candidates.append(functools.partial(PythonPkgConfigDependency, 'python3', env, kwargs, installation, embed, for_machine)) + candidates.append(functools.partial(PythonPkgConfigDependency, 'python3', env, kwargs, installation)) else: candidates.append(functools.partial(PkgConfigDependency, 'python3', env, kwargs)) if DependencyMethods.SYSTEM in methods: - candidates.append(functools.partial(PythonSystemDependency, 'python', env, kwargs, installation, for_machine)) + candidates.append(functools.partial(PythonSystemDependency, 'python', env, kwargs, installation)) if DependencyMethods.EXTRAFRAMEWORK in methods: nkwargs = kwargs.copy() @@ -593,7 +590,7 @@ 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(functools.partial(PythonFrameworkDependency, 'Python', env, nkwargs, installation)) return candidates diff --git a/mesonbuild/dependencies/qt.py b/mesonbuild/dependencies/qt.py index c245e5c8c5ee..63ba9071b7f2 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, diff --git a/mesonbuild/dependencies/scalapack.py b/mesonbuild/dependencies/scalapack.py index 26a6e39044f5..18bc5fce6d07 100644 --- a/mesonbuild/dependencies/scalapack.py +++ b/mesonbuild/dependencies/scalapack.py @@ -17,13 +17,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'] = [] @@ -55,15 +54,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 52567354059a..01be3351b5dd 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -58,7 +58,8 @@ class GnuStepDependency(ConfigToolDependency): tool_name = 'gnustep-config' def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - super().__init__(name, environment, kwargs, language='objc') + kwargs['language'] = 'objc' + super().__init__(name, environment, kwargs) if not self.is_found: return self.modules = kwargs.get('modules', []) @@ -152,7 +153,8 @@ class WxDependency(ConfigToolDependency): # name is intentionally ignored to maintain existing capitalization, # but is needed for polymorphism def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs): - super().__init__('WxWidgets', environment, kwargs, language='cpp') + kwargs['language'] = 'cpp' + super().__init__('WxWidgets', environment, kwargs) if not self.is_found: return self.requested_modules = kwargs.get('modules', []) @@ -177,8 +179,8 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje 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): diff --git a/mesonbuild/modules/python.py b/mesonbuild/modules/python.py index 99602c05ad4c..75bffdd1820a 100644 --- a/mesonbuild/modules/python.py +++ b/mesonbuild/modules/python.py @@ -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/unittests/internaltests.py b/unittests/internaltests.py index 74b36a83ed3d..4d34a335df5e 100644 --- a/unittests/internaltests.py +++ b/unittests/internaltests.py @@ -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: From 316c818bc7642661f2706489174f0b04f74894eb Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 14:55:15 -0700 Subject: [PATCH 06/13] dependencies: Require 'native' be passed in kwargs This simplifies a bunch of cases, and likely fixes some annoying bugs in cross compile situations where should have been passing this and weren't. --- mesonbuild/dependencies/base.py | 14 +++++++------- mesonbuild/dependencies/boost.py | 2 +- mesonbuild/dependencies/cmake.py | 4 ++-- mesonbuild/dependencies/coarrays.py | 3 +-- mesonbuild/dependencies/cuda.py | 2 +- mesonbuild/dependencies/detect.py | 7 +++---- mesonbuild/dependencies/dev.py | 4 ++-- mesonbuild/dependencies/dub.py | 2 +- mesonbuild/dependencies/factory.py | 12 +++++++----- mesonbuild/dependencies/hdf5.py | 9 ++++----- mesonbuild/dependencies/misc.py | 2 +- mesonbuild/dependencies/mpi.py | 3 +-- mesonbuild/dependencies/python.py | 2 +- mesonbuild/interpreter/compiler.py | 3 ++- mesonbuild/interpreter/dependencyfallbacks.py | 8 ++++---- mesonbuild/mdevenv.py | 2 +- mesonbuild/modules/_qt.py | 4 ++-- mesonbuild/modules/python.py | 4 ++-- unittests/allplatformstests.py | 2 +- unittests/internaltests.py | 2 +- unittests/linuxliketests.py | 4 ++-- 21 files changed, 47 insertions(+), 48 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 293f772a851f..5e0d871efeb0 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -21,7 +21,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 +51,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 @@ -312,7 +312,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__({}) + super().__init__({'native': MachineChoice.HOST}) # TODO: does the native key actually matter self.version = version self.is_found = True self.include_directories = incdirs @@ -430,7 +430,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje 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']: @@ -506,7 +506,7 @@ class NotFoundDependency(Dependency): type_name = DependencyTypeName('not-found') def __init__(self, name: str, environment: 'Environment') -> None: - super().__init__({}) + super().__init__({'native': MachineChoice.HOST}) # TODO: does this actually matter? self.env = environment self.name = name self.is_found = False @@ -524,8 +524,8 @@ 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__(name, environment, {'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 diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py index 171c49455a9a..02c449cb2f49 100644 --- a/mesonbuild/dependencies/boost.py +++ b/mesonbuild/dependencies/boost.py @@ -677,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 e8881cda26e2..07855ef4a628 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 @@ -77,7 +77,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje 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] diff --git a/mesonbuild/dependencies/coarrays.py b/mesonbuild/dependencies/coarrays.py index d75eb58578d4..e261f2209c98 100644 --- a/mesonbuild/dependencies/coarrays.py +++ b/mesonbuild/dependencies/coarrays.py @@ -6,7 +6,6 @@ import functools import typing as T -from ..mesonlib import MachineChoice from .base import DependencyMethods, detect_compiler, SystemDependency from .cmake import CMakeDependency from .detect import packages @@ -24,7 +23,7 @@ def coarray_factory(env: 'Environment', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: kwargs['language'] = 'fortran' - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] fcid = detect_compiler('coarray', env, for_machine, 'fortran').get_id() candidates: T.List['DependencyGenerator'] = [] diff --git a/mesonbuild/dependencies/cuda.py b/mesonbuild/dependencies/cuda.py index 75f6cb9e57fa..b3401ee0310a 100644 --- a/mesonbuild/dependencies/cuda.py +++ b/mesonbuild/dependencies/cuda.py @@ -29,7 +29,7 @@ class CudaDependency(SystemDependency): targets_dir = 'targets' # Directory containing CUDA targets. def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: - for_machine = kwargs.get('native', mesonlib.MachineChoice.HOST) + for_machine = kwargs['native'] compilers = environment.coredata.compilers[for_machine] machine = environment.machines[for_machine] if not kwargs.get('language'): diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py index 0681913a1704..206742d1b613 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -9,7 +9,7 @@ from .base import ExternalDependency, DependencyException, DependencyMethods, NotFoundDependency -from ..mesonlib import listify, MachineChoice, PerMachine +from ..mesonlib import listify, PerMachine from .. import mlog if T.TYPE_CHECKING: @@ -102,7 +102,7 @@ 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 @@ -213,8 +213,7 @@ def _build_external_dependency_list(name: str, env: 'Environment', kwargs: Depen # On OSX only, try framework dependency detector. if DependencyMethods.EXTRAFRAMEWORK in methods: - for_machine = kwargs.get('native', MachineChoice.HOST) - 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)) diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index dd21b910f0f9..6e24251cdafb 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -198,7 +198,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje # 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') @@ -391,7 +391,7 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) - 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 diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index cfd04ee007a3..7b4daf37c26d 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -306,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 2afe28847033..e89adcbb50d6 100644 --- a/mesonbuild/dependencies/factory.py +++ b/mesonbuild/dependencies/factory.py @@ -80,7 +80,7 @@ def __init__(self, name: str, methods: T.List[DependencyMethods], *, if DependencyMethods.CONFIG_TOOL in methods and not configtool_class: raise DependencyException('A configtool must have a custom class') - self.extra_kwargs = extra_kwargs or {} + self.extra_kwargs = extra_kwargs self.methods = methods self.classes: T.Dict[ DependencyMethods, @@ -116,11 +116,13 @@ def _process_method(method: DependencyMethods, env: 'Environment', for_machine: 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) - - for_machine = kwargs.get('native', MachineChoice.HOST) + if self.extra_kwargs: + nwargs = self.extra_kwargs.copy() + nwargs.update(kwargs) + else: + nwargs = kwargs.copy() + for_machine = kwargs['native'] return [functools.partial(self.classes[m], env, nwargs) for m in methods if self._process_method(m, env, for_machine)] diff --git a/mesonbuild/dependencies/hdf5.py b/mesonbuild/dependencies/hdf5.py index 75331f254b0b..4effc6ce83b8 100644 --- a/mesonbuild/dependencies/hdf5.py +++ b/mesonbuild/dependencies/hdf5.py @@ -9,7 +9,7 @@ import re from pathlib import Path -from ..mesonlib import OrderedSet, join_args, MachineChoice +from ..mesonlib import OrderedSet, join_args from .base import DependencyException, DependencyMethods from .configtool import ConfigToolDependency from .detect import packages @@ -98,15 +98,14 @@ 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()) @@ -146,7 +145,7 @@ def _sanitize_version(self, ver: str) -> str: def hdf5_factory(env: 'Environment', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: candidates: T.List['DependencyGenerator'] = [] - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] if DependencyMethods.PKGCONFIG in methods: # Use an ordered set so that these remain the first tried pkg-config files diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index b5c3f54de941..586930d3425c 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -531,7 +531,7 @@ def curses_factory(env: 'Environment', kwargs: DependencyObjectKWs, methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']: candidates: T.List['DependencyGenerator'] = [] - for_machine = kwargs.get('native', mesonlib.MachineChoice.HOST) + for_machine = kwargs['native'] if DependencyMethods.PKGCONFIG in methods: pkgconfig_files = ['pdcurses', 'ncursesw', 'ncurses', 'curses'] diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index 00e5a98416ac..44372ab44f74 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -8,7 +8,6 @@ import os import re -from ..mesonlib import MachineChoice from ..envconfig import detect_cpu_family from ..mesonlib import Popen_safe from .base import DependencyException, DependencyMethods, detect_compiler, SystemDependency @@ -32,7 +31,7 @@ def mpi_factory(env: 'Environment', # OpenMPI doesn't work without any other languages return [] - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] candidates: T.List['DependencyGenerator'] = [] compiler = detect_compiler('mpi', env, for_machine, language) diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index ad9262981c3f..146f41d4dd69 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -478,7 +478,7 @@ def __init__(self, name: str, environment: Environment, kwargs: DependencyObject self.is_found = False return - for_machine = kwargs.get('native', MachineChoice.HOST) + for_machine = kwargs['native'] sysroot = environment.properties[for_machine].get_sys_root() or '' pkg_libdir = sysroot + pkg_libdir 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 75bffdd1820a..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) diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py index 1304658daeb9..0959f22a3899 100644 --- a/unittests/allplatformstests.py +++ b/unittests/allplatformstests.py @@ -2156,7 +2156,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 4d34a335df5e..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()]) diff --git a/unittests/linuxliketests.py b/unittests/linuxliketests.py index 4f775d651d04..e879ac3dddaf 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()) From 71c0076158d142d504d989a3f6992aa52eecd1ad Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 09:01:13 -0700 Subject: [PATCH 07/13] dependencies: Add a wrapper class for Dependency candidates The goal is to have a single type for candidates that replaces having a mixture of class initializers, partials, and factories with a single wrapper class. --- mesonbuild/dependencies/base.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 5e0d871efeb0..47d836c2f136 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 @@ -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''' @@ -683,3 +686,28 @@ class BuiltinDependency(ExternalDependency): @staticmethod def log_tried() -> str: return '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]: + return cls(dep, name, dep.log_tried(), modules, arguments=args) From 17321200dc3ba83dab1e447cebb8a6d07c2e5793 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Fri, 24 Oct 2025 15:35:37 -0700 Subject: [PATCH 08/13] Dependencies: Make use of the DependencyCandidate class This makes the type checking more reasonable (including fixing an issue that newer mypy is pointing out to us), consolidating special cases, and improving code readability. --- mesonbuild/dependencies/cmake.py | 16 ----- mesonbuild/dependencies/coarrays.py | 20 +++--- mesonbuild/dependencies/detect.py | 41 ++++++------ mesonbuild/dependencies/dev.py | 18 ++--- mesonbuild/dependencies/factory.py | 99 ++++++++++++++++------------ mesonbuild/dependencies/hdf5.py | 9 +-- mesonbuild/dependencies/misc.py | 73 ++++++++++---------- mesonbuild/dependencies/mpi.py | 15 ++--- mesonbuild/dependencies/python.py | 25 ++++--- mesonbuild/dependencies/qt.py | 12 ++-- mesonbuild/dependencies/scalapack.py | 15 ++--- mesonbuild/dependencies/ui.py | 11 ++-- 12 files changed, 183 insertions(+), 171 deletions(-) diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 07855ef4a628..76879796231e 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -645,22 +645,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, force_use_global_compilers: bool = False) -> CMakeDependency: - if self.modules: - kwargs['modules'] = self.modules - return CMakeDependency(self.name or name, env, kwargs, 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 e261f2209c98..dda4286d6285 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 @@ -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)) + 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)) + 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, 'coarray', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'coarray', CoarrayDependency, (env, kwargs))) return candidates + + packages['coarray'] = coarray_factory diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py index 206742d1b613..295689db2bf6 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -3,23 +3,23 @@ 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, PerMachine +from ..mesonlib import listify, PerMachine, MesonBugException 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: @@ -120,8 +120,7 @@ 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) @@ -178,17 +177,17 @@ def _build_external_dependency_list(name: str, env: 'Environment', kwargs: Depen # 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, kwargs) + dep = entry(env, kwargs) return dep candidates: T.List['DependencyGenerator'] = [] @@ -204,24 +203,24 @@ def _build_external_dependency_list(name: str, env: 'Environment', kwargs: Depen # 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[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 6e24251cdafb..4b043a07e82f 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 +from .base import DependencyException, DependencyMethods, detect_compiler, strip_system_includedirs, strip_system_libdirs, SystemDependency, ExternalDependency, DependencyCandidate from .cmake import CMakeDependency from .configtool import ConfigToolDependency from .detect import packages @@ -802,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, + cmake=DependencyCandidate.from_dependency('ZLIB', CMakeDependency), + system=ZlibSystemDependency, ) diff --git a/mesonbuild/dependencies/factory.py b/mesonbuild/dependencies/factory.py index e89adcbb50d6..02652e5e77d2 100644 --- a/mesonbuild/dependencies/factory.py +++ b/mesonbuild/dependencies/factory.py @@ -8,7 +8,7 @@ import typing as T from ..mesonlib import MachineChoice -from .base import DependencyException, DependencyMethods +from .base import DependencyCandidate, DependencyException, DependencyMethods from .base import process_method_kw from .base import BuiltinDependency, SystemDependency from .cmake import CMakeDependency @@ -16,11 +16,14 @@ 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 - DependencyGenerator = T.Callable[[], ExternalDependency] + # TODO: remove this? + DependencyGenerator: TypeAlias = DependencyCandidate[ExternalDependency] FactoryFunc = T.Callable[ [ 'Environment', @@ -38,10 +41,6 @@ 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. @@ -50,53 +49,61 @@ 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: A custom CMake lookup to use + :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') + pkgconfig: T.Union[DependencyCandidate[PkgConfigDependency], T.Type[PkgConfigDependency], None] = PkgConfigDependency, + cmake: T.Union[DependencyCandidate[CMakeDependency], T.Type[CMakeDependency], None] = CMakeDependency, + 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') + + 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: @@ -122,9 +129,15 @@ def __call__(self, env: 'Environment', kwargs: DependencyObjectKWs) -> T.List['D else: nwargs = kwargs.copy() - for_machine = kwargs['native'] - return [functools.partial(self.classes[m], env, nwargs) for m in methods - if self._process_method(m, env, for_machine)] + 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']: diff --git a/mesonbuild/dependencies/hdf5.py b/mesonbuild/dependencies/hdf5.py index 4effc6ce83b8..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 -from .base import DependencyException, DependencyMethods +from .base import DependencyCandidate, DependencyException, DependencyMethods from .configtool import ConfigToolDependency from .detect import packages from .pkgconfig import PkgConfigDependency, PkgConfigInterface @@ -161,10 +160,12 @@ def hdf5_factory(env: 'Environment', kwargs: DependencyObjectKWs, # 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)) + candidates.append(DependencyCandidate.from_dependency( + mod, HDF5PkgConfigDependency, (env, kwargs))) if DependencyMethods.CONFIG_TOOL in methods: - candidates.append(functools.partial(HDF5ConfigToolDependency, 'hdf5', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'hd5f', HDF5ConfigToolDependency, (env, kwargs))) return candidates diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 586930d3425c..1f9f06e97241 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 @@ -43,10 +42,12 @@ def netcdf_factory(env: 'Environment', else: pkg = 'netcdf' - 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, 'NetCDF', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'NetCDF', CMakeDependency, (env, kwargs))) return candidates @@ -536,17 +537,20 @@ def curses_factory(env: 'Environment', 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 @@ -576,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, 'shaderc', env, kwargs)) + candidates.append(DependencyCandidate.from_dependency( + 'shaderc', ShadercDependency, (env, kwargs))) return candidates packages['shaderc'] = shaderc_factory @@ -593,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, - cmake_name='Cups', + configtool=CupsDependencyConfigTool, + cmake=DependencyCandidate.from_dependency('Cups', CMakeDependency), ) 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, + cmake=DependencyCandidate.from_dependency('Threads', CMakeDependency), + 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 44372ab44f74..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 @@ -75,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)) + 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)) + 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 @@ -92,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)) + candidates.append(DependencyCandidate.from_dependency( + pkg_name, PkgConfigDependency, (env, kwargs))) return candidates diff --git a/mesonbuild/dependencies/python.py b/mesonbuild/dependencies/python.py index 146f41d4dd69..9614196d9b3e 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -8,7 +8,7 @@ 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 @@ -519,7 +519,7 @@ def __init__(self, name: str, environment: 'Environment', class PythonSystemDependency(SystemDependency, _PythonDependencyBase): def __init__(self, name: str, environment: 'Environment', - kwargs: DependencyObjectKWs, installation: 'BasicPythonExternalProgram'): + kwargs: DependencyObjectKWs, installation: BasicPythonExternalProgram): SystemDependency.__init__(self, name, environment, kwargs) _PythonDependencyBase.__init__(self, installation, kwargs.get('embed', False)) @@ -563,7 +563,7 @@ def __init__(self, name: str, environment: 'Environment', def log_tried() -> str: return 'sysconfig' -def python_factory(env: 'Environment', 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 @@ -577,12 +577,17 @@ def python_factory(env: 'Environment', kwargs: DependencyObjectKWs, if DependencyMethods.PKGCONFIG in methods: if from_installation: - candidates.append(functools.partial(PythonPkgConfigDependency, 'python3', env, kwargs, installation)) + candidates.append(DependencyCandidate( + functools.partial(PythonPkgConfigDependency, installation=installation), + 'python3', PythonPkgConfigDependency.log_tried(), 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)) + candidates.append(DependencyCandidate( + functools.partial(PythonSystemDependency, installation=installation), + 'python', PythonSystemDependency.log_tried(), arguments=(env, kwargs))) if DependencyMethods.EXTRAFRAMEWORK in methods: nkwargs = kwargs.copy() @@ -590,7 +595,9 @@ def python_factory(env: 'Environment', kwargs: DependencyObjectKWs, # 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)) + candidates.append(DependencyCandidate( + functools.partial(PythonFrameworkDependency, installation=installation), + 'python', PythonFrameworkDependency.log_tried(), arguments=(env, nkwargs))) return candidates @@ -599,11 +606,11 @@ def python_factory(env: 'Environment', kwargs: DependencyObjectKWs, 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 63ba9071b7f2..57cdd5ec6de0 100644 --- a/mesonbuild/dependencies/qt.py +++ b/mesonbuild/dependencies/qt.py @@ -468,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 18bc5fce6d07..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 @@ -30,16 +29,16 @@ def scalapack_factory(env: 'Environment', 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 diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 01be3351b5dd..97c7f6397122 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -17,7 +17,8 @@ ) from ..envconfig import detect_cpu_family -from .base import DependencyException, DependencyMethods, DependencyTypeName, SystemDependency +from .base import DependencyCandidate, DependencyException, DependencyMethods, DependencyTypeName, SystemDependency +from .cmake import CMakeDependency from .configtool import ConfigToolDependency from .detect import packages from .factory import DependencyFactory @@ -251,18 +252,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, - cmake_name='SDL2', + configtool=SDL2DependencyConfigTool, + cmake=DependencyCandidate.from_dependency('SDL2', CMakeDependency), ) packages['vulkan'] = vulkan_factory = DependencyFactory( 'vulkan', [DependencyMethods.PKGCONFIG, DependencyMethods.SYSTEM], - system_class=VulkanDependencySystem, + system=VulkanDependencySystem, ) From 5a085d1702162ca0339a196b7f5964433610153f Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 27 Oct 2025 10:45:41 -0700 Subject: [PATCH 09/13] dependencies: Catch non MesonException in detect and give better message --- mesonbuild/dependencies/detect.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py index 295689db2bf6..97eeb21cde97 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -9,7 +9,7 @@ from .base import DependencyCandidate, ExternalDependency, DependencyException, DependencyMethods, NotFoundDependency -from ..mesonlib import listify, PerMachine, MesonBugException +from ..mesonlib import listify, PerMachine, MesonBugException, MesonException from .. import mlog if T.TYPE_CHECKING: @@ -124,6 +124,11 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb 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() From 609703a688962b5f2e08852008822e57f4445908 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 27 Oct 2025 10:01:02 -0700 Subject: [PATCH 10/13] dependencies/detect: simplify logging tried methods Avoid extra method calls and repeating ourselves. --- mesonbuild/dependencies/detect.py | 16 +++++----------- test cases/failing/100 no fallback/test.json | 2 +- .../test.json | 2 +- .../failing/62 wrong boost module/test.json | 2 +- test cases/failing/79 dub library/test.json | 2 +- test cases/failing/80 dub executable/test.json | 2 +- test cases/failing/81 dub compiler/test.json | 2 +- 7 files changed, 11 insertions(+), 17 deletions(-) diff --git a/mesonbuild/dependencies/detect.py b/mesonbuild/dependencies/detect.py index 97eeb21cde97..65e19c2aac59 100644 --- a/mesonbuild/dependencies/detect.py +++ b/mesonbuild/dependencies/detect.py @@ -112,6 +112,7 @@ def find_external_dependency(name: str, env: 'Environment', kwargs: DependencyOb pkg_exc: T.List[DependencyException] = [] pkgdep: T.List[ExternalDependency] = [] details = '' + tried_methods: T.List[str] = [] for c in candidates: # try this dependency method @@ -139,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)) @@ -151,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 @@ -171,8 +166,7 @@ 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) diff --git a/test cases/failing/100 no fallback/test.json b/test cases/failing/100 no fallback/test.json index 5fbffe35d893..d3f7345b0715 100644 --- a/test cases/failing/100 no fallback/test.json +++ b/test cases/failing/100 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/33 dependency not-required then required/test.json b/test cases/failing/33 dependency not-required then required/test.json index 7dd8519563e0..daf4f351aa81 100644 --- a/test cases/failing/33 dependency not-required then required/test.json +++ b/test cases/failing/33 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/62 wrong boost module/test.json b/test cases/failing/62 wrong boost module/test.json index 75ef82b7ee91..2765ce917484 100644 --- a/test cases/failing/62 wrong boost module/test.json +++ b/test cases/failing/62 wrong boost module/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/62 wrong boost module/meson.build:9:10: ERROR: Dependency \"boost\" not found, tried system" + "line": "test cases/failing/62 wrong boost module/meson.build:9:10: ERROR: Dependency \"boost\" not found (tried system)" } ] } diff --git a/test cases/failing/79 dub library/test.json b/test cases/failing/79 dub library/test.json index 9f59604a410b..ea4e734908c2 100644 --- a/test cases/failing/79 dub library/test.json +++ b/test cases/failing/79 dub library/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/79 dub library/meson.build:11:0: ERROR: Dependency \"dubtestproject\" not found" + "line": "test cases/failing/79 dub library/meson.build:11:0: ERROR: Dependency \"dubtestproject\" not found (tried dub)" } ] } diff --git a/test cases/failing/80 dub executable/test.json b/test cases/failing/80 dub executable/test.json index edb74f62cdfc..97dab9f873db 100644 --- a/test cases/failing/80 dub executable/test.json +++ b/test cases/failing/80 dub executable/test.json @@ -1,7 +1,7 @@ { "stdout": [ { - "line": "test cases/failing/80 dub executable/meson.build:11:0: ERROR: Dependency \"dubtestproject:test1\" not found" + "line": "test cases/failing/80 dub executable/meson.build:11:0: ERROR: Dependency \"dubtestproject:test1\" not found (tried dub)" } ] } diff --git a/test cases/failing/81 dub compiler/test.json b/test cases/failing/81 dub compiler/test.json index d82984d5d6cc..1018d478b9db 100644 --- a/test cases/failing/81 dub compiler/test.json +++ b/test cases/failing/81 dub compiler/test.json @@ -13,7 +13,7 @@ }, "stdout": [ { - "line": "test cases/failing/81 dub compiler/meson.build:17:0: ERROR: Dependency \"dubtestproject:test2\" not found" + "line": "test cases/failing/81 dub compiler/meson.build:17:0: ERROR: Dependency \"dubtestproject:test2\" not found (tried dub)" } ] } From b310d68745f8f98b7da579d303986fc4e66d3437 Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Mon, 27 Oct 2025 10:07:48 -0700 Subject: [PATCH 11/13] dependencies: Remove `log_tried` method It's now only used to populate the DependencyCandidate, so we can remove it and just calculate the same information from the `type_name` parameter. This reduces code and the number of method calls. --- mesonbuild/dependencies/base.py | 22 +++++++++------------- mesonbuild/dependencies/cmake.py | 4 ---- mesonbuild/dependencies/configtool.py | 4 ---- mesonbuild/dependencies/framework.py | 4 ---- mesonbuild/dependencies/pkgconfig.py | 4 ---- mesonbuild/dependencies/platform.py | 4 ---- mesonbuild/dependencies/python.py | 11 ++++------- 7 files changed, 13 insertions(+), 40 deletions(-) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 47d836c2f136..de9e24f230de 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -463,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: @@ -672,10 +668,6 @@ class SystemDependency(ExternalDependency): type_name = DependencyTypeName('system') - @staticmethod - def log_tried() -> str: - return 'system' - class BuiltinDependency(ExternalDependency): @@ -683,10 +675,6 @@ class BuiltinDependency(ExternalDependency): type_name = DependencyTypeName('builtin') - @staticmethod - def log_tried() -> str: - return 'builtin' - @dataclasses.dataclass class DependencyCandidate(T.Generic[DepType]): @@ -710,4 +698,12 @@ 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]: - return cls(dep, name, dep.log_tried(), modules, arguments=args) + 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' + + return cls(dep, name, tried, modules, arguments=args) diff --git a/mesonbuild/dependencies/cmake.py b/mesonbuild/dependencies/cmake.py index 76879796231e..5fc207317878 100644 --- a/mesonbuild/dependencies/cmake.py +++ b/mesonbuild/dependencies/cmake.py @@ -609,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)) diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index 024bf94300c1..3d018943c7aa 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -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/framework.py b/mesonbuild/dependencies/framework.py index 15c4ce2fffca..e3ebd3b4afe6 100644 --- a/mesonbuild/dependencies/framework.py +++ b/mesonbuild/dependencies/framework.py @@ -112,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/pkgconfig.py b/mesonbuild/dependencies/pkgconfig.py index 938c77da474d..2a4e91d8d722 100644 --- a/mesonbuild/dependencies/pkgconfig.py +++ b/mesonbuild/dependencies/pkgconfig.py @@ -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 f193c87ebe2f..829220ccb26d 100644 --- a/mesonbuild/dependencies/platform.py +++ b/mesonbuild/dependencies/platform.py @@ -47,8 +47,4 @@ def __init__(self, name: str, env: 'Environment', kwargs: DependencyObjectKWs) - 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 9614196d9b3e..0e40d481faf5 100644 --- a/mesonbuild/dependencies/python.py +++ b/mesonbuild/dependencies/python.py @@ -559,10 +559,6 @@ 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, 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 @@ -579,15 +575,16 @@ def python_factory(env: Environment, kwargs: DependencyObjectKWs, if from_installation: candidates.append(DependencyCandidate( functools.partial(PythonPkgConfigDependency, installation=installation), - 'python3', PythonPkgConfigDependency.log_tried(), arguments=(env, kwargs))) + 'python3', PythonPkgConfigDependency.type_name, arguments=(env, kwargs))) else: candidates.append(DependencyCandidate.from_dependency( 'python3', PkgConfigDependency, (env, kwargs))) if DependencyMethods.SYSTEM in methods: + # This is a unique log-tried. candidates.append(DependencyCandidate( functools.partial(PythonSystemDependency, installation=installation), - 'python', PythonSystemDependency.log_tried(), arguments=(env, kwargs))) + 'python', 'sysconfig', arguments=(env, kwargs))) if DependencyMethods.EXTRAFRAMEWORK in methods: nkwargs = kwargs.copy() @@ -597,7 +594,7 @@ def python_factory(env: Environment, kwargs: DependencyObjectKWs, nkwargs['paths'] = ['/Library/Frameworks'] candidates.append(DependencyCandidate( functools.partial(PythonFrameworkDependency, installation=installation), - 'python', PythonFrameworkDependency.log_tried(), arguments=(env, nkwargs))) + 'python', PythonPkgConfigDependency.type_name, arguments=(env, nkwargs))) return candidates From 206749bdc5ca7ba75b8c07daf19f4cbbd5d4820b Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 29 Oct 2025 07:31:18 -0700 Subject: [PATCH 12/13] dependencies/coarrays: Remove dead code --- mesonbuild/dependencies/coarrays.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mesonbuild/dependencies/coarrays.py b/mesonbuild/dependencies/coarrays.py index dda4286d6285..ddb50058f0ea 100644 --- a/mesonbuild/dependencies/coarrays.py +++ b/mesonbuild/dependencies/coarrays.py @@ -63,8 +63,6 @@ class CoarrayDependency(SystemDependency): def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObjectKWs) -> None: kwargs['language'] = 'fortran' super().__init__(name, environment, kwargs) - kwargs['required'] = False - kwargs['silent'] = True cid = self.get_compiler().get_id() if cid == 'gcc': From df1667750b5e746af0bd0916a1de94cf9ee9745a Mon Sep 17 00:00:00 2001 From: Dylan Baker Date: Wed, 29 Oct 2025 07:50:22 -0700 Subject: [PATCH 13/13] WIP: add back the cmake_name parameter to DependencyFactory --- mesonbuild/dependencies/dev.py | 4 ++-- mesonbuild/dependencies/factory.py | 14 ++++++++++++-- mesonbuild/dependencies/misc.py | 4 ++-- mesonbuild/dependencies/ui.py | 5 ++--- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index 4b043a07e82f..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, DependencyCandidate +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 @@ -823,6 +823,6 @@ def get_variable(self, *, cmake: T.Optional[str] = None, pkgconfig: T.Optional[s packages['zlib'] = zlib_factory = DependencyFactory( 'zlib', [DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE, DependencyMethods.SYSTEM], - cmake=DependencyCandidate.from_dependency('ZLIB', CMakeDependency), + cmake_name='ZLIB', system=ZlibSystemDependency, ) diff --git a/mesonbuild/dependencies/factory.py b/mesonbuild/dependencies/factory.py index 02652e5e77d2..11c91c317719 100644 --- a/mesonbuild/dependencies/factory.py +++ b/mesonbuild/dependencies/factory.py @@ -58,7 +58,8 @@ class DependencyFactory: :param extra_kwargs: Additional keyword arguments to add when creating the DependencyCandidate :param pkgconfig: A custom PackageConfig lookup to use - :param cmake: A custom CMake 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, @@ -73,8 +74,9 @@ class DependencyFactory: def __init__(self, name: str, methods: T.List[DependencyMethods], *, extra_kwargs: T.Optional[DependencyObjectKWs] = None, + cmake_name: T.Optional[str] = None, pkgconfig: T.Union[DependencyCandidate[PkgConfigDependency], T.Type[PkgConfigDependency], None] = PkgConfigDependency, - cmake: T.Union[DependencyCandidate[CMakeDependency], T.Type[CMakeDependency], None] = CMakeDependency, + 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, @@ -87,6 +89,14 @@ def __init__(self, name: str, methods: T.List[DependencyMethods], *, 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 diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 1f9f06e97241..7612fdef7781 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -606,7 +606,7 @@ def shaderc_factory(env: 'Environment', 'cups', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE], configtool=CupsDependencyConfigTool, - cmake=DependencyCandidate.from_dependency('Cups', CMakeDependency), + cmake_name='Cups', ) packages['dl'] = dl_factory = DependencyFactory( @@ -644,7 +644,7 @@ def shaderc_factory(env: 'Environment', packages['threads'] = threads_factory = DependencyFactory( 'threads', [DependencyMethods.SYSTEM, DependencyMethods.CMAKE], - cmake=DependencyCandidate.from_dependency('Threads', CMakeDependency), + cmake_name='Threads', system=ThreadDependency, ) diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 97c7f6397122..8c513ae9c6cf 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -17,8 +17,7 @@ ) from ..envconfig import detect_cpu_family -from .base import DependencyCandidate, DependencyException, DependencyMethods, DependencyTypeName, SystemDependency -from .cmake import CMakeDependency +from .base import DependencyException, DependencyMethods, DependencyTypeName, SystemDependency from .configtool import ConfigToolDependency from .detect import packages from .factory import DependencyFactory @@ -259,7 +258,7 @@ def __init__(self, name: str, environment: 'Environment', kwargs: DependencyObje 'sdl2', [DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.EXTRAFRAMEWORK, DependencyMethods.CMAKE], configtool=SDL2DependencyConfigTool, - cmake=DependencyCandidate.from_dependency('SDL2', CMakeDependency), + cmake_name='SDL2', ) packages['vulkan'] = vulkan_factory = DependencyFactory(