Remove module type from OptionKey.

pull/12487/head
Jussi Pakkanen 4 months ago
parent 61c742fae9
commit 6e20022295
  1. 4
      mesonbuild/coredata.py
  2. 7
      mesonbuild/mconf.py
  3. 10
      mesonbuild/modules/__init__.py
  4. 2
      mesonbuild/modules/pkgconfig.py
  5. 10
      mesonbuild/modules/python.py
  6. 78
      mesonbuild/options.py
  7. 4
      unittests/datatests.py

@ -422,6 +422,10 @@ class CoreData:
value = opts_map.get_value(key.as_root())
else:
value = None
if key.has_module_prefix():
modulename = key.get_module_prefix()
opts_map.add_module_option(modulename, key, opt.init_option(key, value, options.default_prefix()))
else:
opts_map.add_system_option(key, opt.init_option(key, value, options.default_prefix()))
def init_backend_options(self, backend_name: str) -> None:

@ -272,12 +272,13 @@ class Conf:
dir_options[k] = v
elif k in test_option_names:
test_options[k] = v
elif k.module:
elif k.has_module_prefix():
# Ignore module options if we did not use that module during
# configuration.
if self.build and k.module not in self.build.modules:
modname = k.get_module_prefix()
if self.build and modname not in self.build.modules:
continue
module_options[k.module][k] = v
module_options[modname][k] = v
elif self.coredata.optstore.is_builtin_option(k):
core_options[k] = v

@ -132,15 +132,13 @@ class ModuleState:
self._interpreter.func_test(self.current_node, real_args, kwargs)
def get_option(self, name: str, subproject: str = '',
machine: MachineChoice = MachineChoice.HOST,
module: T.Optional[str] = None) -> T.Union[T.List[str], str, int, bool]:
return self.environment.coredata.get_option(OptionKey(name, subproject, machine, module))
machine: MachineChoice = MachineChoice.HOST) -> T.Union[T.List[str], str, int, bool]:
return self.environment.coredata.get_option(OptionKey(name, subproject, machine))
def is_user_defined_option(self, name: str, subproject: str = '',
machine: MachineChoice = MachineChoice.HOST,
lang: T.Optional[str] = None,
module: T.Optional[str] = None) -> bool:
key = OptionKey(name, subproject, machine, module)
lang: T.Optional[str] = None) -> bool:
key = OptionKey(name, subproject, machine)
return key in self._interpreter.user_defined_options.cmd_line_options
def process_include_dirs(self, dirs: T.Iterable[T.Union[str, IncludeDirs]]) -> T.Iterable[IncludeDirs]:

@ -703,7 +703,7 @@ class PkgConfigModule(NewExtensionModule):
else:
pkgroot = os.path.join(_as_str(state.environment.coredata.get_option(OptionKey('libdir'))), 'pkgconfig')
pkgroot_name = os.path.join('{libdir}', 'pkgconfig')
relocatable = state.get_option('relocatable', module='pkgconfig')
relocatable = state.get_option('pkgconfig.relocatable')
self._generate_pkgconfig_file(state, deps, subdirs, name, description, url,
version, pcfile, conflicts, variables,
unescaped_variables, False, dataonly,

@ -83,13 +83,13 @@ class PythonExternalProgram(BasicPythonExternalProgram):
if not state:
# This happens only from run_project_tests.py
return rel_path
value = T.cast('str', state.get_option(f'{key}dir', module='python'))
value = T.cast('str', state.get_option(f'python.{key}dir'))
if value:
if state.is_user_defined_option('install_env', module='python'):
if state.is_user_defined_option('python.install_env'):
raise mesonlib.MesonException(f'python.{key}dir and python.install_env are mutually exclusive')
return value
install_env = state.get_option('install_env', module='python')
install_env = state.get_option('python.install_env')
if install_env == 'auto':
install_env = 'venv' if self.info['is_venv'] else 'system'
@ -169,7 +169,7 @@ class PythonInstallation(_ExternalProgramHolder['PythonExternalProgram']):
self.current_node)
limited_api_version = kwargs.pop('limited_api')
allow_limited_api = self.interpreter.environment.coredata.get_option(OptionKey('allow_limited_api', module='python'))
allow_limited_api = self.interpreter.environment.coredata.get_option(OptionKey('python.allow_limited_api'))
if limited_api_version != '' and allow_limited_api:
target_suffix = self.limited_api_suffix
@ -374,7 +374,7 @@ class PythonModule(ExtensionModule):
def _get_install_scripts(self) -> T.List[mesonlib.ExecutableSerialisation]:
backend = self.interpreter.backend
ret = []
optlevel = self.interpreter.environment.coredata.get_option(OptionKey('bytecompile', module='python'))
optlevel = self.interpreter.environment.coredata.get_option(OptionKey('python.bytecompile'))
if optlevel == -1:
return ret
if not any(PythonExternalProgram.run_bytecompile.values()):

@ -90,17 +90,15 @@ class OptionKey:
internally easier to reason about and produce.
"""
__slots__ = ['name', 'subproject', 'machine', '_hash', 'module']
__slots__ = ['name', 'subproject', 'machine', '_hash']
name: str
subproject: str
machine: MachineChoice
_hash: int
module: T.Optional[str]
def __init__(self, name: str, subproject: str = '',
machine: MachineChoice = MachineChoice.HOST,
module: T.Optional[str] = None):
machine: MachineChoice = MachineChoice.HOST):
# 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
@ -108,8 +106,7 @@ class OptionKey:
object.__setattr__(self, 'name', name)
object.__setattr__(self, 'subproject', subproject)
object.__setattr__(self, 'machine', machine)
object.__setattr__(self, 'module', module)
object.__setattr__(self, '_hash', hash((name, subproject, machine, module)))
object.__setattr__(self, '_hash', hash((name, subproject, machine)))
def __setattr__(self, key: str, value: T.Any) -> None:
raise AttributeError('OptionKey instances do not support mutation.')
@ -119,7 +116,6 @@ class OptionKey:
'name': self.name,
'subproject': self.subproject,
'machine': self.machine,
'module': self.module,
}
def __setstate__(self, state: T.Dict[str, T.Any]) -> None:
@ -137,7 +133,7 @@ class OptionKey:
return self._hash
def _to_tuple(self) -> T.Tuple[str, str, str, MachineChoice, str]:
return (self.subproject, self.module or '', self.machine, self.name)
return (self.subproject, self.machine, self.name)
def __eq__(self, other: object) -> bool:
if isinstance(other, OptionKey):
@ -153,14 +149,12 @@ class OptionKey:
out = self.name
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
def __repr__(self) -> str:
return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r}, {self.module!r})'
return f'OptionKey({self.name!r}, {self.subproject!r}, {self.machine!r})'
@classmethod
def from_string(cls, raw: str) -> 'OptionKey':
@ -174,26 +168,24 @@ class OptionKey:
except ValueError:
subproject, raw2 = '', raw
module = None
for_machine = MachineChoice.HOST
try:
prefix, raw3 = raw2.split('.')
if prefix == 'build':
for_machine = MachineChoice.BUILD
else:
module = prefix
raw3 = raw2
except ValueError:
raw3 = raw2
opt = raw3
assert ':' not in opt
assert '.' not in opt
assert opt.count('.') < 2
return cls(opt, subproject, for_machine, module)
return cls(opt, subproject, for_machine)
def evolve(self, name: T.Optional[str] = None, subproject: T.Optional[str] = None,
machine: T.Optional[MachineChoice] = None,
module: T.Optional[str] = '') -> 'OptionKey':
machine: T.Optional[MachineChoice] = None) -> 'OptionKey':
"""Create a new copy of this key, but with altered members.
For example:
@ -208,7 +200,6 @@ class OptionKey:
name if name is not None else self.name,
subproject if subproject is not None else self.subproject,
machine if machine is not None else self.machine,
module if module != '' else self.module
)
def as_root(self) -> 'OptionKey':
@ -228,6 +219,20 @@ class OptionKey:
import sys
sys.exit('FATAL internal error. This should not make it into an actual release. File a bug.')
def has_module_prefix(self) -> bool:
return '.' in self.name
def get_module_prefix(self) -> T.Optional[str]:
if self.has_module_prefix():
return self.name.split('.', 1)[0]
return None
def without_module_prefix(self) -> 'OptionKey':
if self.has_module_prefix():
newname = self.name.split('.', 1)[1]
return self.evolve(newname)
return self
class UserOption(T.Generic[_T], HoldableObject):
def __init__(self, name: str, description: str, choices: T.Optional[T.Union[str, T.List[_T]]],
@ -633,19 +638,19 @@ BUILTIN_CORE_OPTIONS: T.Dict['OptionKey', 'BuiltinOption'] = OrderedDict([
(OptionKey('vsenv'), BuiltinOption(UserBooleanOption, 'Activate Visual Studio environment', False, readonly=True)),
# Pkgconfig module
(OptionKey('relocatable', module='pkgconfig'),
(OptionKey('pkgconfig.relocatable'),
BuiltinOption(UserBooleanOption, 'Generate pkgconfig files as relocatable', False)),
# Python module
(OptionKey('bytecompile', module='python'),
(OptionKey('python.bytecompile'),
BuiltinOption(UserIntegerOption, 'Whether to compile bytecode', (-1, 2, 0))),
(OptionKey('install_env', module='python'),
(OptionKey('python.install_env'),
BuiltinOption(UserComboOption, 'Which python environment to install to', 'prefix', choices=['auto', 'prefix', 'system', 'venv'])),
(OptionKey('platlibdir', module='python'),
(OptionKey('python.platlibdir'),
BuiltinOption(UserStringOption, 'Directory for site-specific, platform-specific files.', '')),
(OptionKey('purelibdir', module='python'),
(OptionKey('python.purelibdir'),
BuiltinOption(UserStringOption, 'Directory for site-specific, non-platform-specific files.', '')),
(OptionKey('allow_limited_api', module='python'),
(OptionKey('python.allow_limited_api'),
BuiltinOption(UserBooleanOption, 'Whether to allow use of the Python Limited API', True)),
])
@ -662,8 +667,8 @@ BUILTIN_DIR_NOPREFIX_OPTIONS: T.Dict[OptionKey, T.Dict[str, str]] = {
OptionKey('sysconfdir'): {'/usr': '/etc'},
OptionKey('localstatedir'): {'/usr': '/var', '/usr/local': '/var/local'},
OptionKey('sharedstatedir'): {'/usr': '/var/lib', '/usr/local': '/var/local/lib'},
OptionKey('platlibdir', module='python'): {},
OptionKey('purelibdir', module='python'): {},
OptionKey('python.platlibdir'): {},
OptionKey('python.purelibdir'): {},
}
class OptionStore:
@ -671,6 +676,7 @@ class OptionStore:
self.d: T.Dict['OptionKey', 'UserOption[T.Any]'] = {}
self.project_options = set()
self.all_languages = set()
self.module_options = set()
from .compilers import all_languages
for lang in all_languages:
self.all_languages.add(lang)
@ -690,6 +696,12 @@ class OptionStore:
return self.get_value_object(key).value
def add_system_option(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'):
key = self.ensure_key(key)
if '.' in key.name:
raise MesonException(f'Internal error: non-module option has a period in its name {key.name}.')
self.add_system_option_internal(key, valobj)
def add_system_option_internal(self, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'):
key = self.ensure_key(key)
assert isinstance(valobj, UserOption)
self.d[key] = valobj
@ -705,6 +717,15 @@ class OptionStore:
self.d[key] = valobj
self.project_options.add(key)
def add_module_option(self, modulename: str, key: T.Union[OptionKey, str], valobj: 'UserOption[T.Any]'):
key = self.ensure_key(key)
if key.name.startswith('build.'):
raise MesonException('FATAL internal error: somebody goofed option handling.')
if not key.name.startswith(modulename + '.'):
raise MesonException('Internal error: module option name {key.name} does not start with module prefix {modulename}.')
self.add_system_option_internal(key, valobj)
self.module_options.add(key)
def set_value(self, key: T.Union[OptionKey, str], new_value: 'T.Any') -> bool:
key = self.ensure_key(key)
return self.d[key].set_value(new_value)
@ -764,7 +785,7 @@ class OptionStore:
def is_builtin_option(self, key: OptionKey) -> bool:
"""Convenience method to check if this is a builtin option."""
return key.name in _BUILTIN_NAMES or key.module
return key.name in _BUILTIN_NAMES or self.is_module_option(key)
def is_base_option(self, key: OptionKey) -> bool:
"""Convenience method to check if this is a base option."""
@ -784,3 +805,6 @@ class OptionStore:
if prefix in self.all_languages:
return True
return False
def is_module_option(self, key: OptionKey) -> bool:
return key in self.module_options

@ -139,8 +139,8 @@ class DataTests(unittest.TestCase):
found_entries |= options
self.assertEqual(found_entries, {
*(str(k.evolve(module=None)) for k in mesonbuild.options.BUILTIN_OPTIONS),
*(str(k.evolve(module=None)) for k in mesonbuild.options.BUILTIN_OPTIONS_PER_MACHINE),
*(str(k.without_module_prefix()) for k in mesonbuild.options.BUILTIN_OPTIONS),
*(str(k.without_module_prefix()) for k in mesonbuild.options.BUILTIN_OPTIONS_PER_MACHINE),
})
# Check that `buildtype` table inside `Core options` matches how

Loading…
Cancel
Save