|
|
|
@ -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 |
|
|
|
|