diff --git a/mesonbuild/build.py b/mesonbuild/build.py index ef2210ed3..a9089e99c 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -271,6 +271,7 @@ class Build: self.dependency_overrides: PerMachine[T.Dict[T.Tuple, DependencyOverride]] = PerMachineDefaultable.default( environment.is_cross_build(), {}, {}) self.devenv: T.List[EnvironmentVariables] = [] + self.modules: T.List[str] = [] def get_build_targets(self): build_targets = OrderedDict() diff --git a/mesonbuild/interpreter/interpreter.py b/mesonbuild/interpreter/interpreter.py index 8ac92c8c0..4c5dfbb99 100644 --- a/mesonbuild/interpreter/interpreter.py +++ b/mesonbuild/interpreter/interpreter.py @@ -551,6 +551,7 @@ class Interpreter(InterpreterBase, HoldableObject): else: ext_module = module.initialize(self) assert isinstance(ext_module, (ExtensionModule, NewExtensionModule)) + self.build.modules.append(modname) self.modules[modname] = ext_module return ext_module diff --git a/mesonbuild/mconf.py b/mesonbuild/mconf.py index b58eaa74f..cf7040f33 100644 --- a/mesonbuild/mconf.py +++ b/mesonbuild/mconf.py @@ -17,6 +17,7 @@ import shutil import os import textwrap import typing as T +import collections from . import build from . import coredata @@ -243,11 +244,18 @@ class Conf: dir_options: 'coredata.KeyedOptionDictType' = {} test_options: 'coredata.KeyedOptionDictType' = {} core_options: 'coredata.KeyedOptionDictType' = {} + module_options: T.Dict[str, 'coredata.KeyedOptionDictType'] = collections.defaultdict(dict) for k, v in self.coredata.options.items(): if k in dir_option_names: dir_options[k] = v elif k in test_option_names: test_options[k] = v + elif k.module: + # Ignore module options if we did not use that module during + # configuration. + if self.build and k.module not in self.build.modules: + continue + module_options[k.module][k] = v elif k.is_builtin(): core_options[k] = v @@ -267,6 +275,8 @@ class Conf: self.print_options('Compiler options', host_compiler_options.get('', {})) if show_build_options: self.print_options('', build_compiler_options.get('', {})) + for mod, mod_options in module_options.items(): + self.print_options(f'{mod} module options', mod_options) self.print_options('Directories', dir_options) self.print_options('Testing options', test_options) self.print_options('Project options', project_options.get('', {})) diff --git a/mesonbuild/mesonlib/universal.py b/mesonbuild/mesonlib/universal.py index a1ca6771f..6eedd7956 100644 --- a/mesonbuild/mesonlib/universal.py +++ b/mesonbuild/mesonlib/universal.py @@ -2024,7 +2024,7 @@ def _classify_argument(key: 'OptionKey') -> OptionType: return OptionType.BASE elif key.lang is not None: return OptionType.COMPILER - elif key.name in _BUILTIN_NAMES: + elif key.name in _BUILTIN_NAMES or key.module: return OptionType.BUILTIN elif key.name.startswith('backend_'): assert key.machine is MachineChoice.HOST, str(key) @@ -2044,7 +2044,7 @@ class OptionKey: internally easier to reason about and produce. """ - __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'type'] + __slots__ = ['name', 'subproject', 'machine', 'lang', '_hash', 'type', 'module'] name: str subproject: str @@ -2052,10 +2052,13 @@ class OptionKey: lang: T.Optional[str] _hash: int type: OptionType + module: T.Optional[str] def __init__(self, name: str, subproject: str = '', machine: MachineChoice = MachineChoice.HOST, - lang: T.Optional[str] = None, _type: T.Optional[OptionType] = None): + lang: T.Optional[str] = None, + module: T.Optional[str] = None, + _type: T.Optional[OptionType] = None): # the _type option to the constructor is kinda private. We want to be # able tos ave the state and avoid the lookup function when # pickling/unpickling, but we need to be able to calculate it when @@ -2064,7 +2067,8 @@ class OptionKey: object.__setattr__(self, 'subproject', subproject) object.__setattr__(self, 'machine', machine) object.__setattr__(self, 'lang', lang) - object.__setattr__(self, '_hash', hash((name, subproject, machine, lang))) + object.__setattr__(self, 'module', module) + object.__setattr__(self, '_hash', hash((name, subproject, machine, lang, module))) if _type is None: _type = _classify_argument(self) object.__setattr__(self, 'type', _type) @@ -2079,6 +2083,7 @@ class OptionKey: 'machine': self.machine, 'lang': self.lang, '_type': self.type, + 'module': self.module, } def __setstate__(self, state: T.Dict[str, T.Any]) -> None: @@ -2095,20 +2100,17 @@ class OptionKey: def __hash__(self) -> int: return self._hash + def _to_tuple(self): + return (self.subproject, self.type, self.lang or '', self.module or '', self.machine, self.name) + def __eq__(self, other: object) -> bool: if isinstance(other, OptionKey): - return ( - self.name == other.name and - self.subproject == other.subproject and - self.machine is other.machine and - self.lang == other.lang) + return self._to_tuple() == other._to_tuple() return NotImplemented def __lt__(self, other: object) -> bool: if isinstance(other, OptionKey): - self_tuple = (self.subproject, self.type, self.lang, self.machine, self.name) - other_tuple = (other.subproject, other.type, other.lang, other.machine, other.name) - return self_tuple < other_tuple + return self._to_tuple() < other._to_tuple() return NotImplemented def __str__(self) -> str: @@ -2117,6 +2119,8 @@ class OptionKey: out = f'{self.lang}_{out}' if self.machine is MachineChoice.BUILD: out = f'build.{out}' + if self.module: + out = f'{self.module}.{out}' if self.subproject: out = f'{self.subproject}:{out}' return out @@ -2136,12 +2140,16 @@ class OptionKey: except ValueError: subproject, raw2 = '', raw - if raw2.startswith('build.'): - raw3 = raw2.split('.', 1)[1] - for_machine = MachineChoice.BUILD - else: + module = None + for_machine = MachineChoice.HOST + try: + prefix, raw3 = raw2.split('.') + if prefix == 'build': + for_machine = MachineChoice.BUILD + else: + module = prefix + except ValueError: raw3 = raw2 - for_machine = MachineChoice.HOST from ..compilers import all_languages if any(raw3.startswith(f'{l}_') for l in all_languages): @@ -2149,12 +2157,13 @@ class OptionKey: else: lang, opt = None, raw3 assert ':' not in opt - assert 'build.' not in opt + assert '.' not in opt - return cls(opt, subproject, for_machine, lang) + return cls(opt, subproject, for_machine, lang, module) def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None, - machine: T.Optional[MachineChoice] = None, lang: T.Optional[str] = '') -> 'OptionKey': + machine: T.Optional[MachineChoice] = None, lang: T.Optional[str] = '', + module: T.Optional[str] = '') -> 'OptionKey': """Create a new copy of this key, but with alterted members. For example: @@ -2170,6 +2179,7 @@ class OptionKey: subproject if subproject is not None else self.subproject, machine if machine is not None else self.machine, lang if lang != '' else self.lang, + module if module != '' else self.module ) def as_root(self) -> 'OptionKey':