summaryrefslogtreecommitdiff
path: root/mesonbuild/coredata.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/coredata.py')
-rw-r--r--mesonbuild/coredata.py569
1 files changed, 61 insertions, 508 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 6e67587b2..76da0b67f 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -6,7 +6,7 @@ from __future__ import annotations
import copy
-from . import mlog, mparser
+from . import mlog, mparser, options
import pickle, os, uuid
import sys
from itertools import chain
@@ -15,12 +15,10 @@ from collections import OrderedDict, abc
from dataclasses import dataclass
from .mesonlib import (
- HoldableObject, MesonBugException,
+ MesonBugException,
MesonException, EnvironmentException, MachineChoice, PerMachine,
- PerMachineDefaultable, default_libdir, default_libexecdir,
- default_prefix, default_datadir, default_includedir, default_infodir,
- default_localedir, default_mandir, default_sbindir, default_sysconfdir,
- listify_array_value, OptionKey, OptionType, stringlistify,
+ PerMachineDefaultable,
+ OptionKey, OptionType, stringlistify,
pickle_load
)
import ast
@@ -56,8 +54,8 @@ if T.TYPE_CHECKING:
cross_file: T.List[str]
native_file: T.List[str]
- OptionDictType = T.Union[T.Dict[str, 'UserOption[T.Any]'], 'OptionsView']
- MutableKeyedOptionDictType = T.Dict['OptionKey', 'UserOption[T.Any]']
+ OptionDictType = T.Union[T.Dict[str, 'options.UserOption[T.Any]'], 'OptionsView']
+ MutableKeyedOptionDictType = T.Dict['OptionKey', 'options.UserOption[T.Any]']
KeyedOptionDictType = T.Union[MutableKeyedOptionDictType, 'OptionsView']
CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, FileOrString, T.Tuple[str, ...], CompileCheckMode]
# code, args
@@ -82,20 +80,11 @@ if stable_version.endswith('.99'):
stable_version_array[-2] = str(int(stable_version_array[-2]) + 1)
stable_version = '.'.join(stable_version_array)
-backendlist = ['ninja', 'vs', 'vs2010', 'vs2012', 'vs2013', 'vs2015', 'vs2017', 'vs2019', 'vs2022', 'xcode', 'none']
-genvslitelist = ['vs2022']
-buildtypelist = ['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom']
-
-DEFAULT_YIELDING = False
-
-# Can't bind this near the class method it seems, sadly.
-_T = T.TypeVar('_T')
-
def get_genvs_default_buildtype_list() -> list[str]:
# just debug, debugoptimized, and release for now
# but this should probably be configurable through some extra option, alongside --genvslite.
- return buildtypelist[1:-2]
+ return options.buildtypelist[1:-2]
class MesonVersionMismatchException(MesonException):
@@ -108,312 +97,6 @@ class MesonVersionMismatchException(MesonException):
self.current_version = current_version
-class UserOption(T.Generic[_T], HoldableObject):
- def __init__(self, name: str, description: str, choices: T.Optional[T.Union[str, T.List[_T]]],
- yielding: bool,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- super().__init__()
- self.name = name
- self.choices = choices
- self.description = description
- if not isinstance(yielding, bool):
- raise MesonException('Value of "yielding" must be a boolean.')
- self.yielding = yielding
- self.deprecated = deprecated
- self.readonly = False
-
- def listify(self, value: T.Any) -> T.List[T.Any]:
- return [value]
-
- def printable_value(self) -> T.Union[str, int, bool, T.List[T.Union[str, int, bool]]]:
- assert isinstance(self.value, (str, int, bool, list))
- return self.value
-
- # Check that the input is a valid value and return the
- # "cleaned" or "native" version. For example the Boolean
- # option could take the string "true" and return True.
- def validate_value(self, value: T.Any) -> _T:
- raise RuntimeError('Derived option class did not override validate_value.')
-
- def set_value(self, newvalue: T.Any) -> bool:
- oldvalue = getattr(self, 'value', None)
- self.value = self.validate_value(newvalue)
- return self.value != oldvalue
-
-class UserStringOption(UserOption[str]):
- def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- super().__init__(name, description, None, yielding, deprecated)
- self.set_value(value)
-
- def validate_value(self, value: T.Any) -> str:
- if not isinstance(value, str):
- raise MesonException(f'The value of option "{self.name}" is "{value}", which is not a string.')
- return value
-
-class UserBooleanOption(UserOption[bool]):
- def __init__(self, name: str, description: str, value: bool, yielding: bool = DEFAULT_YIELDING,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- super().__init__(name, description, [True, False], yielding, deprecated)
- self.set_value(value)
-
- def __bool__(self) -> bool:
- return self.value
-
- def validate_value(self, value: T.Any) -> bool:
- if isinstance(value, bool):
- return value
- if not isinstance(value, str):
- raise MesonException(f'Option "{self.name}" value {value} cannot be converted to a boolean')
- if value.lower() == 'true':
- return True
- if value.lower() == 'false':
- return False
- raise MesonException(f'Option "{self.name}" value {value} is not boolean (true or false).')
-
-class UserIntegerOption(UserOption[int]):
- def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- min_value, max_value, default_value = value
- self.min_value = min_value
- self.max_value = max_value
- c: T.List[str] = []
- if min_value is not None:
- c.append('>=' + str(min_value))
- if max_value is not None:
- c.append('<=' + str(max_value))
- choices = ', '.join(c)
- super().__init__(name, description, choices, yielding, deprecated)
- self.set_value(default_value)
-
- def validate_value(self, value: T.Any) -> int:
- if isinstance(value, str):
- value = self.toint(value)
- if not isinstance(value, int):
- raise MesonException(f'Value {value!r} for option "{self.name}" is not an integer.')
- if self.min_value is not None and value < self.min_value:
- raise MesonException(f'Value {value} for option "{self.name}" is less than minimum value {self.min_value}.')
- if self.max_value is not None and value > self.max_value:
- raise MesonException(f'Value {value} for option "{self.name}" is more than maximum value {self.max_value}.')
- return value
-
- def toint(self, valuestring: str) -> int:
- try:
- return int(valuestring)
- except ValueError:
- raise MesonException(f'Value string "{valuestring}" for option "{self.name}" is not convertible to an integer.')
-
-class OctalInt(int):
- # NinjaBackend.get_user_option_args uses str() to converts it to a command line option
- # UserUmaskOption.toint() uses int(str, 8) to convert it to an integer
- # So we need to use oct instead of dec here if we do not want values to be misinterpreted.
- def __str__(self) -> str:
- return oct(int(self))
-
-class UserUmaskOption(UserIntegerOption, UserOption[T.Union[str, OctalInt]]):
- def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- super().__init__(name, description, (0, 0o777, value), yielding, deprecated)
- self.choices = ['preserve', '0000-0777']
-
- def printable_value(self) -> str:
- if self.value == 'preserve':
- return self.value
- return format(self.value, '04o')
-
- def validate_value(self, value: T.Any) -> T.Union[str, OctalInt]:
- if value == 'preserve':
- return 'preserve'
- return OctalInt(super().validate_value(value))
-
- def toint(self, valuestring: T.Union[str, OctalInt]) -> int:
- try:
- return int(valuestring, 8)
- except ValueError as e:
- raise MesonException(f'Invalid mode for option "{self.name}" {e}')
-
-class UserComboOption(UserOption[str]):
- def __init__(self, name: str, description: str, choices: T.List[str], value: T.Any,
- yielding: bool = DEFAULT_YIELDING,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- super().__init__(name, description, choices, yielding, deprecated)
- if not isinstance(self.choices, list):
- raise MesonException(f'Combo choices for option "{self.name}" must be an array.')
- for i in self.choices:
- if not isinstance(i, str):
- raise MesonException(f'Combo choice elements for option "{self.name}" must be strings.')
- self.set_value(value)
-
- def validate_value(self, value: T.Any) -> str:
- if value not in self.choices:
- if isinstance(value, bool):
- _type = 'boolean'
- elif isinstance(value, (int, float)):
- _type = 'number'
- else:
- _type = 'string'
- optionsstring = ', '.join([f'"{item}"' for item in self.choices])
- raise MesonException('Value "{}" (of type "{}") for option "{}" is not one of the choices.'
- ' Possible choices are (as string): {}.'.format(
- value, _type, self.name, optionsstring))
- return value
-
-class UserArrayOption(UserOption[T.List[str]]):
- def __init__(self, name: str, description: str, value: T.Union[str, T.List[str]],
- split_args: bool = False,
- allow_dups: bool = False, yielding: bool = DEFAULT_YIELDING,
- choices: T.Optional[T.List[str]] = None,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- super().__init__(name, description, choices if choices is not None else [], yielding, deprecated)
- self.split_args = split_args
- self.allow_dups = allow_dups
- self.set_value(value)
-
- def listify(self, value: T.Any) -> T.List[T.Any]:
- try:
- return listify_array_value(value, self.split_args)
- except MesonException as e:
- raise MesonException(f'error in option "{self.name}": {e!s}')
-
- def validate_value(self, value: T.Union[str, T.List[str]]) -> T.List[str]:
- newvalue = self.listify(value)
-
- if not self.allow_dups and len(set(newvalue)) != len(newvalue):
- msg = 'Duplicated values in array option is deprecated. ' \
- 'This will become a hard error in the future.'
- mlog.deprecation(msg)
- for i in newvalue:
- if not isinstance(i, str):
- raise MesonException(f'String array element "{newvalue!s}" for option "{self.name}" is not a string.')
- if self.choices:
- bad = [x for x in newvalue if x not in self.choices]
- if bad:
- raise MesonException('Value{} "{}" for option "{}" {} not in allowed choices: "{}"'.format(
- '' if len(bad) == 1 else 's',
- ', '.join(bad),
- self.name,
- 'is' if len(bad) == 1 else 'are',
- ', '.join(self.choices))
- )
- return newvalue
-
- def extend_value(self, value: T.Union[str, T.List[str]]) -> None:
- """Extend the value with an additional value."""
- new = self.validate_value(value)
- self.set_value(self.value + new)
-
-
-class UserFeatureOption(UserComboOption):
- static_choices = ['enabled', 'disabled', 'auto']
-
- def __init__(self, name: str, description: str, value: T.Any, yielding: bool = DEFAULT_YIELDING,
- deprecated: T.Union[bool, str, T.Dict[str, str], T.List[str]] = False):
- super().__init__(name, description, self.static_choices, value, yielding, deprecated)
- self.name: T.Optional[str] = None # TODO: Refactor options to all store their name
-
- def is_enabled(self) -> bool:
- return self.value == 'enabled'
-
- def is_disabled(self) -> bool:
- return self.value == 'disabled'
-
- def is_auto(self) -> bool:
- return self.value == 'auto'
-
-class UserStdOption(UserComboOption):
- '''
- UserOption specific to c_std and cpp_std options. User can set a list of
- STDs in preference order and it selects the first one supported by current
- compiler.
-
- For historical reasons, some compilers (msvc) allowed setting a GNU std and
- silently fell back to C std. This is now deprecated. Projects that support
- both GNU and MSVC compilers should set e.g. c_std=gnu11,c11.
-
- This is not using self.deprecated mechanism we already have for project
- options because we want to print a warning if ALL values are deprecated, not
- if SOME values are deprecated.
- '''
- def __init__(self, lang: str, all_stds: T.List[str]) -> None:
- self.lang = lang.lower()
- self.all_stds = ['none'] + all_stds
- # Map a deprecated std to its replacement. e.g. gnu11 -> c11.
- self.deprecated_stds: T.Dict[str, str] = {}
- opt_name = 'cpp_std' if lang == 'c++' else f'{lang}_std'
- super().__init__(opt_name, f'{lang} language standard to use', ['none'], 'none')
-
- def set_versions(self, versions: T.List[str], gnu: bool = False, gnu_deprecated: bool = False) -> None:
- assert all(std in self.all_stds for std in versions)
- self.choices += versions
- if gnu:
- gnu_stds_map = {f'gnu{std[1:]}': std for std in versions}
- if gnu_deprecated:
- self.deprecated_stds.update(gnu_stds_map)
- else:
- self.choices += gnu_stds_map.keys()
-
- def validate_value(self, value: T.Union[str, T.List[str]]) -> str:
- try:
- candidates = listify_array_value(value)
- except MesonException as e:
- raise MesonException(f'error in option "{self.name}": {e!s}')
- unknown = ','.join(std for std in candidates if std not in self.all_stds)
- if unknown:
- raise MesonException(f'Unknown option "{self.name}" value {unknown}. Possible values are {self.all_stds}.')
- # Check first if any of the candidates are not deprecated
- for std in candidates:
- if std in self.choices:
- return std
- # Fallback to a deprecated std if any
- for std in candidates:
- newstd = self.deprecated_stds.get(std)
- if newstd is not None:
- mlog.deprecation(
- f'None of the values {candidates} are supported by the {self.lang} compiler.\n' +
- f'However, the deprecated {std} std currently falls back to {newstd}.\n' +
- 'This will be an error in the future.\n' +
- 'If the project supports both GNU and MSVC compilers, a value such as\n' +
- '"c_std=gnu11,c11" specifies that GNU is preferred but it can safely fallback to plain c11.')
- return newstd
- raise MesonException(f'None of values {candidates} are supported by the {self.lang.upper()} compiler. ' +
- f'Possible values for option "{self.name}" are {self.choices}')
-
-@dataclass
-class OptionsView(abc.Mapping):
- '''A view on an options dictionary for a given subproject and with overrides.
- '''
-
- # TODO: the typing here could be made more explicit using a TypeDict from
- # python 3.8 or typing_extensions
- options: KeyedOptionDictType
- subproject: T.Optional[str] = None
- overrides: T.Optional[T.Mapping[OptionKey, T.Union[str, int, bool, T.List[str]]]] = None
-
- def __getitem__(self, key: OptionKey) -> UserOption:
- # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal().
- # We should try to share the code somehow.
- key = key.evolve(subproject=self.subproject)
- if not key.is_project():
- opt = self.options.get(key)
- if opt is None or opt.yielding:
- opt = self.options[key.as_root()]
- else:
- opt = self.options[key]
- if opt.yielding:
- opt = self.options.get(key.as_root(), opt)
- if self.overrides:
- override_value = self.overrides.get(key.as_root())
- if override_value is not None:
- opt = copy.copy(opt)
- opt.set_value(override_value)
- return opt
-
- def __iter__(self) -> T.Iterator[OptionKey]:
- return iter(self.options)
-
- def __len__(self) -> int:
- return len(self.options)
-
class DependencyCacheType(enum.Enum):
OTHER = 0
@@ -664,7 +347,7 @@ class CoreData:
# getting the "system default" is always wrong on multiarch
# platforms as it gets a value like lib/x86_64-linux-gnu.
if self.cross_files:
- BUILTIN_OPTIONS[OptionKey('libdir')].default = 'lib'
+ options.BUILTIN_OPTIONS[OptionKey('libdir')].default = 'lib'
def sanitize_prefix(self, prefix: str) -> str:
prefix = os.path.expanduser(prefix)
@@ -698,7 +381,7 @@ class CoreData:
except TypeError:
return value
if option.name.endswith('dir') and value.is_absolute() and \
- option not in BUILTIN_DIR_NOPREFIX_OPTIONS:
+ option not in options.BUILTIN_DIR_NOPREFIX_OPTIONS:
try:
# Try to relativize the path.
value = value.relative_to(prefix)
@@ -717,15 +400,15 @@ class CoreData:
def init_builtins(self, subproject: str) -> None:
# Create builtin options with default values
- for key, opt in BUILTIN_OPTIONS.items():
+ for key, opt in options.BUILTIN_OPTIONS.items():
self.add_builtin_option(self.options, key.evolve(subproject=subproject), opt)
for for_machine in iter(MachineChoice):
- for key, opt in BUILTIN_OPTIONS_PER_MACHINE.items():
+ for key, opt in options.BUILTIN_OPTIONS_PER_MACHINE.items():
self.add_builtin_option(self.options, key.evolve(subproject=subproject, machine=for_machine), opt)
@staticmethod
def add_builtin_option(opts_map: 'MutableKeyedOptionDictType', key: OptionKey,
- opt: 'BuiltinOption') -> None:
+ opt: 'options.BuiltinOption') -> None:
if key.subproject:
if opt.yielding:
# This option is global and not per-subproject
@@ -733,17 +416,17 @@ class CoreData:
value = opts_map[key.as_root()].value
else:
value = None
- opts_map[key] = opt.init_option(key, value, default_prefix())
+ opts_map[key] = opt.init_option(key, value, options.default_prefix())
def init_backend_options(self, backend_name: str) -> None:
if backend_name == 'ninja':
- self.options[OptionKey('backend_max_links')] = UserIntegerOption(
+ self.options[OptionKey('backend_max_links')] = options.UserIntegerOption(
'backend_max_links',
'Maximum number of linker processes to run or 0 for no '
'limit',
(0, None, 0))
elif backend_name.startswith('vs'):
- self.options[OptionKey('backend_startup_project')] = UserStringOption(
+ self.options[OptionKey('backend_startup_project')] = options.UserStringOption(
'backend_startup_project',
'Default project to execute in Visual Studio',
'')
@@ -881,7 +564,7 @@ class CoreData:
@staticmethod
def is_per_machine_option(optname: OptionKey) -> bool:
- if optname.as_host() in BUILTIN_OPTIONS_PER_MACHINE:
+ if optname.as_host() in options.BUILTIN_OPTIONS_PER_MACHINE:
return True
return optname.lang is not None
@@ -930,7 +613,7 @@ class CoreData:
def copy_build_options_from_regular_ones(self) -> bool:
dirty = False
assert not self.is_cross_build()
- for k in BUILTIN_OPTIONS_PER_MACHINE:
+ for k in options.BUILTIN_OPTIONS_PER_MACHINE:
o = self.options[k]
dirty |= self.options[k.as_build()].set_value(o.value)
for bk, bv in self.options.items():
@@ -944,21 +627,21 @@ class CoreData:
return dirty
- def set_options(self, options: T.Dict[OptionKey, T.Any], subproject: str = '', first_invocation: bool = False) -> bool:
+ def set_options(self, opts_to_set: T.Dict[OptionKey, T.Any], subproject: str = '', first_invocation: bool = False) -> bool:
dirty = False
if not self.is_cross_build():
- options = {k: v for k, v in options.items() if k.machine is not MachineChoice.BUILD}
+ opts_to_set = {k: v for k, v in opts_to_set.items() if k.machine is not MachineChoice.BUILD}
# Set prefix first because it's needed to sanitize other options
pfk = OptionKey('prefix')
- if pfk in options:
- prefix = self.sanitize_prefix(options[pfk])
+ if pfk in opts_to_set:
+ prefix = self.sanitize_prefix(opts_to_set[pfk])
dirty |= self.options[OptionKey('prefix')].set_value(prefix)
- for key in BUILTIN_DIR_NOPREFIX_OPTIONS:
- if key not in options:
- dirty |= self.options[key].set_value(BUILTIN_OPTIONS[key].prefixed_default(key, prefix))
+ for key in options.BUILTIN_DIR_NOPREFIX_OPTIONS:
+ if key not in opts_to_set:
+ dirty |= self.options[key].set_value(options.BUILTIN_OPTIONS[key].prefixed_default(key, prefix))
unknown_options: T.List[OptionKey] = []
- for k, v in options.items():
+ for k, v in opts_to_set.items():
if k == pfk:
continue
elif k in self.options:
@@ -1255,9 +938,9 @@ def save(obj: CoreData, build_dir: str) -> str:
def register_builtin_arguments(parser: argparse.ArgumentParser) -> None:
- for n, b in BUILTIN_OPTIONS.items():
+ for n, b in options.BUILTIN_OPTIONS.items():
b.add_to_argparse(str(n), parser, '')
- for n, b in BUILTIN_OPTIONS_PER_MACHINE.items():
+ for n, b in options.BUILTIN_OPTIONS_PER_MACHINE.items():
b.add_to_argparse(str(n), parser, ' (just for host machine)')
b.add_to_argparse(str(n.as_build()), parser, ' (just for build machine)')
parser.add_argument('-D', action='append', dest='projectoptions', default=[], metavar="option",
@@ -1281,185 +964,55 @@ def parse_cmd_line_options(args: SharedCMDOptions) -> None:
# Merge builtin options set with --option into the dict.
for key in chain(
- BUILTIN_OPTIONS.keys(),
- (k.as_build() for k in BUILTIN_OPTIONS_PER_MACHINE.keys()),
- BUILTIN_OPTIONS_PER_MACHINE.keys(),
+ options.BUILTIN_OPTIONS.keys(),
+ (k.as_build() for k in options.BUILTIN_OPTIONS_PER_MACHINE.keys()),
+ options.BUILTIN_OPTIONS_PER_MACHINE.keys(),
):
name = str(key)
value = getattr(args, name, None)
if value is not None:
if key in args.cmd_line_options:
- cmdline_name = BuiltinOption.argparse_name_to_arg(name)
+ cmdline_name = options.BuiltinOption.argparse_name_to_arg(name)
raise MesonException(
f'Got argument {name} as both -D{name} and {cmdline_name}. Pick one.')
args.cmd_line_options[key] = value
delattr(args, name)
+@dataclass
+class OptionsView(abc.Mapping):
+ '''A view on an options dictionary for a given subproject and with overrides.
+ '''
-_U = T.TypeVar('_U', bound=UserOption[_T])
-
-class BuiltinOption(T.Generic[_T, _U]):
-
- """Class for a builtin option type.
-
- There are some cases that are not fully supported yet.
- """
-
- def __init__(self, opt_type: T.Type[_U], description: str, default: T.Any, yielding: bool = True, *,
- choices: T.Any = None, readonly: bool = False):
- self.opt_type = opt_type
- self.description = description
- self.default = default
- self.choices = choices
- self.yielding = yielding
- self.readonly = readonly
-
- def init_option(self, name: 'OptionKey', value: T.Optional[T.Any], prefix: str) -> _U:
- """Create an instance of opt_type and return it."""
- if value is None:
- value = self.prefixed_default(name, prefix)
- keywords = {'yielding': self.yielding, 'value': value}
- if self.choices:
- keywords['choices'] = self.choices
- o = self.opt_type(name.name, self.description, **keywords)
- o.readonly = self.readonly
- return o
-
- def _argparse_action(self) -> T.Optional[str]:
- # If the type is a boolean, the presence of the argument in --foo form
- # is to enable it. Disabling happens by using -Dfoo=false, which is
- # parsed under `args.projectoptions` and does not hit this codepath.
- if isinstance(self.default, bool):
- return 'store_true'
- return None
-
- def _argparse_choices(self) -> T.Any:
- if self.opt_type is UserBooleanOption:
- return [True, False]
- elif self.opt_type is UserFeatureOption:
- return UserFeatureOption.static_choices
- return self.choices
+ # TODO: the typing here could be made more explicit using a TypeDict from
+ # python 3.8 or typing_extensions
+ original_options: KeyedOptionDictType
+ subproject: T.Optional[str] = None
+ overrides: T.Optional[T.Mapping[OptionKey, T.Union[str, int, bool, T.List[str]]]] = None
- @staticmethod
- def argparse_name_to_arg(name: str) -> str:
- if name == 'warning_level':
- return '--warnlevel'
+ def __getitem__(self, key: OptionKey) -> options.UserOption:
+ # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal().
+ # We should try to share the code somehow.
+ key = key.evolve(subproject=self.subproject)
+ if not key.is_project():
+ opt = self.original_options.get(key)
+ if opt is None or opt.yielding:
+ opt = self.original_options[key.as_root()]
else:
- return '--' + name.replace('_', '-')
-
- def prefixed_default(self, name: 'OptionKey', prefix: str = '') -> T.Any:
- if self.opt_type in [UserComboOption, UserIntegerOption]:
- return self.default
- try:
- return BUILTIN_DIR_NOPREFIX_OPTIONS[name][prefix]
- except KeyError:
- pass
- return self.default
+ opt = self.original_options[key]
+ if opt.yielding:
+ opt = self.original_options.get(key.as_root(), opt)
+ if self.overrides:
+ override_value = self.overrides.get(key.as_root())
+ if override_value is not None:
+ opt = copy.copy(opt)
+ opt.set_value(override_value)
+ return opt
- def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffix: str) -> None:
- kwargs = OrderedDict()
+ def __iter__(self) -> T.Iterator[OptionKey]:
+ return iter(self.original_options)
- c = self._argparse_choices()
- b = self._argparse_action()
- h = self.description
- if not b:
- h = '{} (default: {}).'.format(h.rstrip('.'), self.prefixed_default(name))
- else:
- kwargs['action'] = b
- if c and not b:
- kwargs['choices'] = c
- kwargs['default'] = argparse.SUPPRESS
- kwargs['dest'] = name
-
- cmdline_name = self.argparse_name_to_arg(name)
- parser.add_argument(cmdline_name, help=h + help_suffix, **kwargs)
-
-
-# Update `docs/markdown/Builtin-options.md` after changing the options below
-# Also update mesonlib._BUILTIN_NAMES. See the comment there for why this is required.
-# Please also update completion scripts in $MESONSRC/data/shell-completions/
-BUILTIN_DIR_OPTIONS: T.Dict['OptionKey', 'BuiltinOption'] = OrderedDict([
- (OptionKey('prefix'), BuiltinOption(UserStringOption, 'Installation prefix', default_prefix())),
- (OptionKey('bindir'), BuiltinOption(UserStringOption, 'Executable directory', 'bin')),
- (OptionKey('datadir'), BuiltinOption(UserStringOption, 'Data file directory', default_datadir())),
- (OptionKey('includedir'), BuiltinOption(UserStringOption, 'Header file directory', default_includedir())),
- (OptionKey('infodir'), BuiltinOption(UserStringOption, 'Info page directory', default_infodir())),
- (OptionKey('libdir'), BuiltinOption(UserStringOption, 'Library directory', default_libdir())),
- (OptionKey('licensedir'), BuiltinOption(UserStringOption, 'Licenses directory', '')),
- (OptionKey('libexecdir'), BuiltinOption(UserStringOption, 'Library executable directory', default_libexecdir())),
- (OptionKey('localedir'), BuiltinOption(UserStringOption, 'Locale data directory', default_localedir())),
- (OptionKey('localstatedir'), BuiltinOption(UserStringOption, 'Localstate data directory', 'var')),
- (OptionKey('mandir'), BuiltinOption(UserStringOption, 'Manual page directory', default_mandir())),
- (OptionKey('sbindir'), BuiltinOption(UserStringOption, 'System executable directory', default_sbindir())),
- (OptionKey('sharedstatedir'), BuiltinOption(UserStringOption, 'Architecture-independent data directory', 'com')),
- (OptionKey('sysconfdir'), BuiltinOption(UserStringOption, 'Sysconf data directory', default_sysconfdir())),
-])
-
-BUILTIN_CORE_OPTIONS: T.Dict['OptionKey', 'BuiltinOption'] = OrderedDict([
- (OptionKey('auto_features'), BuiltinOption(UserFeatureOption, "Override value of all 'auto' features", 'auto')),
- (OptionKey('backend'), BuiltinOption(UserComboOption, 'Backend to use', 'ninja', choices=backendlist,
- readonly=True)),
- (OptionKey('genvslite'),
- BuiltinOption(
- UserComboOption,
- 'Setup multiple buildtype-suffixed ninja-backend build directories, '
- 'and a [builddir]_vs containing a Visual Studio meta-backend with multiple configurations that calls into them',
- 'vs2022',
- choices=genvslitelist)
- ),
- (OptionKey('buildtype'), BuiltinOption(UserComboOption, 'Build type to use', 'debug',
- choices=buildtypelist)),
- (OptionKey('debug'), BuiltinOption(UserBooleanOption, 'Enable debug symbols and other information', True)),
- (OptionKey('default_library'), BuiltinOption(UserComboOption, 'Default library type', 'shared', choices=['shared', 'static', 'both'],
- yielding=False)),
- (OptionKey('errorlogs'), BuiltinOption(UserBooleanOption, "Whether to print the logs from failing tests", True)),
- (OptionKey('install_umask'), BuiltinOption(UserUmaskOption, 'Default umask to apply on permissions of installed files', '022')),
- (OptionKey('layout'), BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])),
- (OptionKey('optimization'), BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['plain', '0', 'g', '1', '2', '3', 's'])),
- (OptionKey('prefer_static'), BuiltinOption(UserBooleanOption, 'Whether to try static linking before shared linking', False)),
- (OptionKey('stdsplit'), BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)),
- (OptionKey('strip'), BuiltinOption(UserBooleanOption, 'Strip targets on install', False)),
- (OptionKey('unity'), BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])),
- (OptionKey('unity_size'), BuiltinOption(UserIntegerOption, 'Unity block size', (2, None, 4))),
- (OptionKey('warning_level'), BuiltinOption(UserComboOption, 'Compiler warning level to use', '1', choices=['0', '1', '2', '3', 'everything'], yielding=False)),
- (OptionKey('werror'), BuiltinOption(UserBooleanOption, 'Treat warnings as errors', False, yielding=False)),
- (OptionKey('wrap_mode'), BuiltinOption(UserComboOption, 'Wrap mode', 'default', choices=['default', 'nofallback', 'nodownload', 'forcefallback', 'nopromote'])),
- (OptionKey('force_fallback_for'), BuiltinOption(UserArrayOption, 'Force fallback for those subprojects', [])),
- (OptionKey('vsenv'), BuiltinOption(UserBooleanOption, 'Activate Visual Studio environment', False, readonly=True)),
-
- # Pkgconfig module
- (OptionKey('relocatable', module='pkgconfig'),
- BuiltinOption(UserBooleanOption, 'Generate pkgconfig files as relocatable', False)),
-
- # Python module
- (OptionKey('bytecompile', module='python'),
- BuiltinOption(UserIntegerOption, 'Whether to compile bytecode', (-1, 2, 0))),
- (OptionKey('install_env', module='python'),
- BuiltinOption(UserComboOption, 'Which python environment to install to', 'prefix', choices=['auto', 'prefix', 'system', 'venv'])),
- (OptionKey('platlibdir', module='python'),
- BuiltinOption(UserStringOption, 'Directory for site-specific, platform-specific files.', '')),
- (OptionKey('purelibdir', module='python'),
- BuiltinOption(UserStringOption, 'Directory for site-specific, non-platform-specific files.', '')),
- (OptionKey('allow_limited_api', module='python'),
- BuiltinOption(UserBooleanOption, 'Whether to allow use of the Python Limited API', True)),
-])
-
-BUILTIN_OPTIONS = OrderedDict(chain(BUILTIN_DIR_OPTIONS.items(), BUILTIN_CORE_OPTIONS.items()))
-
-BUILTIN_OPTIONS_PER_MACHINE: T.Dict['OptionKey', 'BuiltinOption'] = OrderedDict([
- (OptionKey('pkg_config_path'), BuiltinOption(UserArrayOption, 'List of additional paths for pkg-config to search', [])),
- (OptionKey('cmake_prefix_path'), BuiltinOption(UserArrayOption, 'List of additional prefixes for cmake to search', [])),
-])
-
-# Special prefix-dependent defaults for installation directories that reside in
-# a path outside of the prefix in FHS and common usage.
-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'): {},
-}
+ def __len__(self) -> int:
+ return len(self.original_options)
FORBIDDEN_TARGET_NAMES = frozenset({
'clean',