interpreter: allow default_options and override_options as a dict

pull/11896/head
Dylan Baker 2 years ago
parent d0cbda99a3
commit be20e0809f
  1. 5
      docs/markdown/snippets/option_dict.md
  2. 3
      docs/yaml/functions/_build_target_base.yaml
  3. 3
      docs/yaml/functions/dependency.yaml
  4. 4
      docs/yaml/functions/project.yaml
  5. 12
      docs/yaml/functions/subproject.yaml
  6. 13
      mesonbuild/interpreter/dependencyfallbacks.py
  7. 25
      mesonbuild/interpreter/interpreter.py
  8. 8
      mesonbuild/interpreter/kwargs.py
  9. 23
      mesonbuild/interpreter/type_checking.py
  10. 2
      mesonbuild/modules/cmake.py

@ -0,0 +1,5 @@
## default_options and override_options may now be dictionaries
Instead of passing them as `default_options : ['key=value']`, they can now be
passed as `default_options : {'key': 'value'}`, and the same for
`override_options`.

@ -228,12 +228,13 @@ kwargs:
Set this to `[]`, or omit the keyword argument for the default behaviour. Set this to `[]`, or omit the keyword argument for the default behaviour.
override_options: override_options:
type: list[str] type: list[str] | dict[str]
since: 0.40.0 since: 0.40.0
description: | description: |
takes an array of strings in the same format as `project`'s `default_options` takes an array of strings in the same format as `project`'s `default_options`
overriding the values of these options overriding the values of these options
for this target only. for this target only.
*(since 1.2.0)*: A dictionary may now be passed.
gnu_symbol_visibility: gnu_symbol_visibility:
type: str type: str

@ -78,7 +78,7 @@ varargs:
kwargs: kwargs:
default_options: default_options:
type: list[str] type: list[str] | dict[str]
since: 0.38.0 since: 0.38.0
description: | description: |
An array of default option values An array of default option values
@ -86,6 +86,7 @@ kwargs:
(like `default_options` in [[project]], they only have (like `default_options` in [[project]], they only have
effect when Meson is run for the first time, and command line effect when Meson is run for the first time, and command line
arguments override any default options in build files) arguments override any default options in build files)
*(since 1.2.0)*: A dictionary may now be passed.
allow_fallback: allow_fallback:
type: bool type: bool

@ -38,7 +38,7 @@ varargs:
kwargs: kwargs:
default_options: default_options:
type: list[str] type: list[str] | dict[str]
description: | description: |
Accepts strings in the form `key=value` Accepts strings in the form `key=value`
which have the same format as options to `meson configure`. which have the same format as options to `meson configure`.
@ -54,6 +54,8 @@ kwargs:
environment variable is not used. Consider using environment variable is not used. Consider using
[[add_project_arguments()]] instead. [[add_project_arguments()]] instead.
*(since 1.2.0)*: A dictionary may now be passed.
version: version:
type: str | file type: str | file
description: | description: |

@ -12,8 +12,9 @@ description: |
that override those set in the subproject's `meson.options` that override those set in the subproject's `meson.options`
(like `default_options` in `project`, they only have effect when (like `default_options` in `project`, they only have effect when
Meson is run for the first time, and command line arguments override Meson is run for the first time, and command line arguments override
any default options in build files). *(since 0.54.0)*: `default_library` any default options in build files).
built-in option can also be overridden. *(since 0.54.0)*: `default_library` built-in option can also be overridden.
*(since 1.2.0)*: A dictionary may be passed instead of array.
- `version`: works just like the same as in `dependency`. - `version`: works just like the same as in `dependency`.
It specifies what version the subproject should be, as an example `>=1.0.1` It specifies what version the subproject should be, as an example `>=1.0.1`
- `required` *(since 0.48.0)*: By default, `required` is `true` and - `required` *(since 0.48.0)*: By default, `required` is `true` and
@ -41,15 +42,16 @@ posargs:
kwargs: kwargs:
default_options: default_options:
type: list[str] type: list[str] | dict[str]
since: 0.37.0 since: 0.37.0
description: | description: |
An array of default option values An array of default option values
that override those set in the subproject's `meson.options` that override those set in the subproject's `meson.options`
(like `default_options` in [[project]], they only have effect when (like `default_options` in [[project]], they only have effect when
Meson is run for the first time, and command line arguments override Meson is run for the first time, and command line arguments override
any default options in build files). *(since 0.54.0)*: `default_library` any default options in build files).
built-in option can also be overridden. *(since 0.54.0)*: `default_library` built-in option can also be overridden.
*(since 1.2.0)*: A dictionary may now be passed.
version: version:
type: str type: str

@ -19,7 +19,7 @@ if T.TYPE_CHECKING:
class DependencyFallbacksHolder(MesonInterpreterObject): class DependencyFallbacksHolder(MesonInterpreterObject):
def __init__(self, interpreter: 'Interpreter', names: T.List[str], allow_fallback: T.Optional[bool] = None, def __init__(self, interpreter: 'Interpreter', names: T.List[str], allow_fallback: T.Optional[bool] = None,
default_options: T.Optional[T.List[str]] = None) -> None: default_options: T.Optional[T.Dict[OptionKey, str]] = None) -> None:
super().__init__(subproject=interpreter.subproject) super().__init__(subproject=interpreter.subproject)
self.interpreter = interpreter self.interpreter = interpreter
self.subproject = interpreter.subproject self.subproject = interpreter.subproject
@ -30,7 +30,7 @@ class DependencyFallbacksHolder(MesonInterpreterObject):
self.allow_fallback = allow_fallback self.allow_fallback = allow_fallback
self.subproject_name: T.Optional[str] = None self.subproject_name: T.Optional[str] = None
self.subproject_varname: T.Optional[str] = None self.subproject_varname: T.Optional[str] = None
self.subproject_kwargs = {'default_options': default_options or []} self.subproject_kwargs = {'default_options': default_options or {}}
self.names: T.List[str] = [] self.names: T.List[str] = []
self.forcefallback: bool = False self.forcefallback: bool = False
self.nofallback: bool = False self.nofallback: bool = False
@ -114,12 +114,11 @@ class DependencyFallbacksHolder(MesonInterpreterObject):
# dependency('foo', static: true) should implicitly add # dependency('foo', static: true) should implicitly add
# default_options: ['default_library=static'] # default_options: ['default_library=static']
static = kwargs.get('static') static = kwargs.get('static')
default_options = stringlistify(func_kwargs.get('default_options', [])) default_options = func_kwargs.get('default_options', {})
if static is not None and not any('default_library' in i for i in default_options): if static is not None and 'default_library' not in default_options:
default_library = 'static' if static else 'shared' default_library = 'static' if static else 'shared'
opt = f'default_library={default_library}' mlog.log(f'Building fallback subproject with default_library={default_library}')
mlog.log(f'Building fallback subproject with {opt}') default_options[OptionKey('default_library')] = default_library
default_options.append(opt)
func_kwargs['default_options'] = default_options func_kwargs['default_options'] = default_options
# Configure the subproject # Configure the subproject

@ -80,6 +80,7 @@ from .type_checking import (
INSTALL_TAG_KW, INSTALL_TAG_KW,
LANGUAGE_KW, LANGUAGE_KW,
NATIVE_KW, NATIVE_KW,
OVERRIDE_OPTIONS_KW,
PRESERVE_PATH_KW, PRESERVE_PATH_KW,
REQUIRED_KW, REQUIRED_KW,
SOURCES_KW, SOURCES_KW,
@ -890,7 +891,7 @@ class Interpreter(InterpreterBase, HoldableObject):
mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled') mlog.log('Subproject', mlog.bold(subp_name), ':', 'skipped: feature', mlog.bold(feature), 'disabled')
return self.disabled_subproject(subp_name, disabled_feature=feature) return self.disabled_subproject(subp_name, disabled_feature=feature)
default_options = coredata.create_options_dict(kwargs['default_options'], subp_name) default_options = {k.evolve(subproject=subp_name): v for k, v in kwargs['default_options'].items()}
if subp_name == '': if subp_name == '':
raise InterpreterException('Subproject name must not be empty.') raise InterpreterException('Subproject name must not be empty.')
@ -1196,13 +1197,17 @@ class Interpreter(InterpreterBase, HoldableObject):
self.coredata.update_project_options(oi.options) self.coredata.update_project_options(oi.options)
self.add_build_def_file(option_file) self.add_build_def_file(option_file)
if self.subproject:
self.project_default_options = {k.evolve(subproject=self.subproject): v
for k, v in kwargs['default_options'].items()}
else:
self.project_default_options = kwargs['default_options']
# Do not set default_options on reconfigure otherwise it would override # Do not set default_options on reconfigure otherwise it would override
# values previously set from command line. That means that changing # values previously set from command line. That means that changing
# default_options in a project will trigger a reconfigure but won't # default_options in a project will trigger a reconfigure but won't
# have any effect. # have any effect.
self.project_default_options = coredata.create_options_dict( #
kwargs['default_options'], self.subproject)
# If this is the first invocation we always need to initialize # If this is the first invocation we always need to initialize
# builtins, if this is a subproject that is new in a re-invocation we # builtins, if this is a subproject that is new in a re-invocation we
# need to initialize builtins for that # need to initialize builtins for that
@ -1694,7 +1699,7 @@ class Interpreter(InterpreterBase, HoldableObject):
mlog.bold(' '.join(args))) mlog.bold(' '.join(args)))
sp_kwargs: kwtypes.DoSubproject = { sp_kwargs: kwtypes.DoSubproject = {
'required': required, 'required': required,
'default_options': [], 'default_options': {},
'version': [], 'version': [],
'cmake_options': [], 'cmake_options': [],
'options': None, 'options': None,
@ -1739,10 +1744,10 @@ class Interpreter(InterpreterBase, HoldableObject):
@FeatureNewKwargs('dependency', '0.50.0', ['not_found_message', 'cmake_module_path', 'cmake_args']) @FeatureNewKwargs('dependency', '0.50.0', ['not_found_message', 'cmake_module_path', 'cmake_args'])
@FeatureNewKwargs('dependency', '0.49.0', ['disabler']) @FeatureNewKwargs('dependency', '0.49.0', ['disabler'])
@FeatureNewKwargs('dependency', '0.40.0', ['method']) @FeatureNewKwargs('dependency', '0.40.0', ['method'])
@FeatureNewKwargs('dependency', '0.38.0', ['default_options'])
@disablerIfNotFound @disablerIfNotFound
@permittedKwargs(permitted_dependency_kwargs) @permittedKwargs(permitted_dependency_kwargs)
@typed_pos_args('dependency', varargs=str, min_varargs=1) @typed_pos_args('dependency', varargs=str, min_varargs=1)
@typed_kwargs('dependency', DEFAULT_OPTIONS.evolve(since='0.38.0'), allow_unknown=True)
def func_dependency(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]], kwargs) -> Dependency: def func_dependency(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]], kwargs) -> Dependency:
# Replace '' by empty list of names # Replace '' by empty list of names
names = [n for n in args[0] if n] names = [n for n in args[0] if n]
@ -1794,6 +1799,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@FeatureDeprecatedKwargs('executable', '0.56.0', ['gui_app'], extra_message="Use 'win_subsystem' instead.") @FeatureDeprecatedKwargs('executable', '0.56.0', ['gui_app'], extra_message="Use 'win_subsystem' instead.")
@permittedKwargs(build.known_exe_kwargs) @permittedKwargs(build.known_exe_kwargs)
@typed_pos_args('executable', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('executable', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('executable', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_executable(self, node: mparser.BaseNode, def func_executable(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[BuildTargetSource]], args: T.Tuple[str, T.List[BuildTargetSource]],
kwargs) -> build.Executable: kwargs) -> build.Executable:
@ -1801,6 +1807,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(build.known_stlib_kwargs) @permittedKwargs(build.known_stlib_kwargs)
@typed_pos_args('static_library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('static_library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('static_library', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_static_lib(self, node: mparser.BaseNode, def func_static_lib(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[BuildTargetSource]], args: T.Tuple[str, T.List[BuildTargetSource]],
kwargs) -> build.StaticLibrary: kwargs) -> build.StaticLibrary:
@ -1808,6 +1815,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(build.known_shlib_kwargs) @permittedKwargs(build.known_shlib_kwargs)
@typed_pos_args('shared_library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('shared_library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('shared_library', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_shared_lib(self, node: mparser.BaseNode, def func_shared_lib(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[BuildTargetSource]], args: T.Tuple[str, T.List[BuildTargetSource]],
kwargs) -> build.SharedLibrary: kwargs) -> build.SharedLibrary:
@ -1817,6 +1825,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(known_library_kwargs) @permittedKwargs(known_library_kwargs)
@typed_pos_args('both_libraries', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('both_libraries', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('both_libraries', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_both_lib(self, node: mparser.BaseNode, def func_both_lib(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[BuildTargetSource]], args: T.Tuple[str, T.List[BuildTargetSource]],
kwargs) -> build.BothLibraries: kwargs) -> build.BothLibraries:
@ -1825,6 +1834,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@FeatureNew('shared_module', '0.37.0') @FeatureNew('shared_module', '0.37.0')
@permittedKwargs(build.known_shmod_kwargs) @permittedKwargs(build.known_shmod_kwargs)
@typed_pos_args('shared_module', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('shared_module', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('shared_module', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_shared_module(self, node: mparser.BaseNode, def func_shared_module(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[BuildTargetSource]], args: T.Tuple[str, T.List[BuildTargetSource]],
kwargs) -> build.SharedModule: kwargs) -> build.SharedModule:
@ -1832,6 +1842,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(known_library_kwargs) @permittedKwargs(known_library_kwargs)
@typed_pos_args('library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('library', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('library', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_library(self, node: mparser.BaseNode, def func_library(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[BuildTargetSource]], args: T.Tuple[str, T.List[BuildTargetSource]],
kwargs) -> build.Executable: kwargs) -> build.Executable:
@ -1839,6 +1850,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@permittedKwargs(build.known_jar_kwargs) @permittedKwargs(build.known_jar_kwargs)
@typed_pos_args('jar', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('jar', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('jar', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_jar(self, node: mparser.BaseNode, def func_jar(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[T.Union[str, mesonlib.File, build.GeneratedTypes]]], args: T.Tuple[str, T.List[T.Union[str, mesonlib.File, build.GeneratedTypes]]],
kwargs) -> build.Jar: kwargs) -> build.Jar:
@ -1847,6 +1859,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@FeatureNewKwargs('build_target', '0.40.0', ['link_whole', 'override_options']) @FeatureNewKwargs('build_target', '0.40.0', ['link_whole', 'override_options'])
@permittedKwargs(known_build_target_kwargs) @permittedKwargs(known_build_target_kwargs)
@typed_pos_args('build_target', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget)) @typed_pos_args('build_target', str, varargs=(str, mesonlib.File, build.CustomTarget, build.CustomTargetIndex, build.GeneratedList, build.StructuredSources, build.ExtractedObjects, build.BuildTarget))
@typed_kwargs('build_target', OVERRIDE_OPTIONS_KW, allow_unknown=True)
def func_build_target(self, node: mparser.BaseNode, def func_build_target(self, node: mparser.BaseNode,
args: T.Tuple[str, T.List[BuildTargetSource]], args: T.Tuple[str, T.List[BuildTargetSource]],
kwargs) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary, kwargs) -> T.Union[build.Executable, build.StaticLibrary, build.SharedLibrary,

@ -12,7 +12,7 @@ from typing_extensions import TypedDict, Literal, Protocol
from .. import build from .. import build
from .. import coredata from .. import coredata
from ..compilers import Compiler from ..compilers import Compiler
from ..mesonlib import MachineChoice, File, FileMode, FileOrString from ..mesonlib import MachineChoice, File, FileMode, FileOrString, OptionKey
from ..modules.cmake import CMakeSubprojectOptions from ..modules.cmake import CMakeSubprojectOptions
from ..programs import ExternalProgram from ..programs import ExternalProgram
@ -203,7 +203,7 @@ class Project(TypedDict):
version: T.Optional[FileOrString] version: T.Optional[FileOrString]
meson_version: T.Optional[str] meson_version: T.Optional[str]
default_options: T.List[str] default_options: T.Dict[OptionKey, str]
license: T.List[str] license: T.List[str]
subproject_dir: str subproject_dir: str
@ -298,13 +298,13 @@ class ConfigureFile(TypedDict):
class Subproject(ExtractRequired): class Subproject(ExtractRequired):
default_options: T.List[str] default_options: T.Dict[OptionKey, str]
version: T.List[str] version: T.List[str]
class DoSubproject(ExtractRequired): class DoSubproject(ExtractRequired):
default_options: T.List[str] default_options: T.Dict[OptionKey, str]
version: T.List[str] version: T.List[str]
cmake_options: T.List[str] cmake_options: T.List[str]
options: T.Optional[CMakeSubprojectOptions] options: T.Optional[CMakeSubprojectOptions]

@ -281,21 +281,25 @@ COMMAND_KW: KwargInfo[T.List[T.Union[str, BuildTarget, CustomTarget, CustomTarge
default=[], default=[],
) )
def _override_options_convertor(raw: T.List[str]) -> T.Dict[OptionKey, str]: def _override_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, str]]) -> T.Dict[OptionKey, str]:
if isinstance(raw, str):
raw = [raw]
if isinstance(raw, list):
output: T.Dict[OptionKey, str] = {} output: T.Dict[OptionKey, str] = {}
for each in raw: for each in raw:
k, v = split_equal_string(each) k, v = split_equal_string(each)
output[OptionKey.from_string(k)] = v output[OptionKey.from_string(k)] = v
return output return output
return {OptionKey.from_string(k): v for k, v in raw.items()}
OVERRIDE_OPTIONS_KW: KwargInfo[T.List[str]] = KwargInfo( OVERRIDE_OPTIONS_KW: KwargInfo[T.Union[str, T.Dict[str, str], T.List[str]]] = KwargInfo(
'override_options', 'override_options',
ContainerTypeInfo(list, str), (str, ContainerTypeInfo(list, str), ContainerTypeInfo(dict, str)),
listify=True, default={},
default=[],
validator=_options_validator, validator=_options_validator,
convertor=_override_options_convertor, convertor=_override_options_convertor,
since_values={dict: '1.2.0'},
) )
@ -385,14 +389,7 @@ INCLUDE_DIRECTORIES: KwargInfo[T.List[T.Union[str, IncludeDirs]]] = KwargInfo(
default=[], default=[],
) )
# for cases like default_options and override_options DEFAULT_OPTIONS = OVERRIDE_OPTIONS_KW.evolve(name='default_options')
DEFAULT_OPTIONS: KwargInfo[T.List[str]] = KwargInfo(
'default_options',
ContainerTypeInfo(list, str),
listify=True,
default=[],
validator=_options_validator,
)
ENV_METHOD_KW = KwargInfo('method', str, default='set', since='0.62.0', ENV_METHOD_KW = KwargInfo('method', str, default='set', since='0.62.0',
validator=in_set_validator({'set', 'prepend', 'append'})) validator=in_set_validator({'set', 'prepend', 'append'}))

@ -431,7 +431,7 @@ class CmakeModule(ExtensionModule):
'required': kwargs_['required'], 'required': kwargs_['required'],
'options': kwargs_['options'], 'options': kwargs_['options'],
'cmake_options': kwargs_['cmake_options'], 'cmake_options': kwargs_['cmake_options'],
'default_options': [], 'default_options': {},
'version': [], 'version': [],
} }
subp = self.interpreter.do_subproject(dirname, 'cmake', kw) subp = self.interpreter.do_subproject(dirname, 'cmake', kw)

Loading…
Cancel
Save