Refactor option classes to their own file.

pull/13250/head
Jussi Pakkanen 6 months ago
parent 631b38577e
commit 5365d9a842
  1. 6
      mesonbuild/ast/introspection.py
  2. 8
      mesonbuild/cargo/interpreter.py
  3. 34
      mesonbuild/compilers/c.py
  4. 47
      mesonbuild/compilers/compilers.py
  5. 54
      mesonbuild/compilers/cpp.py
  6. 5
      mesonbuild/compilers/cuda.py
  7. 6
      mesonbuild/compilers/cython.py
  8. 4
      mesonbuild/compilers/fortran.py
  9. 3
      mesonbuild/compilers/mixins/emscripten.py
  10. 3
      mesonbuild/compilers/objc.py
  11. 3
      mesonbuild/compilers/objcpp.py
  12. 4
      mesonbuild/compilers/rust.py
  13. 569
      mesonbuild/coredata.py
  14. 5
      mesonbuild/interpreter/compiler.py
  15. 15
      mesonbuild/interpreter/interpreter.py
  16. 26
      mesonbuild/interpreter/interpreterobjects.py
  17. 4
      mesonbuild/interpreter/kwargs.py
  18. 2
      mesonbuild/interpreter/type_checking.py
  19. 2
      mesonbuild/interpreterbase/helpers.py
  20. 21
      mesonbuild/mconf.py
  21. 20
      mesonbuild/mintro.py
  22. 4
      mesonbuild/modules/_qt.py
  23. 2
      mesonbuild/modules/pkgconfig.py
  24. 2
      mesonbuild/modules/python.py
  25. 35
      mesonbuild/optinterpreter.py
  26. 480
      mesonbuild/options.py
  27. 3
      run_project_tests.py
  28. 3
      run_tests.py
  29. 3
      test cases/unit/116 empty project/expected_mods.json
  30. 5
      unittests/datatests.py
  31. 2
      unittests/platformagnostictests.py

@ -10,7 +10,7 @@ import copy
import os import os
import typing as T import typing as T
from .. import compilers, environment, mesonlib, optinterpreter from .. import compilers, environment, mesonlib, optinterpreter, options
from .. import coredata as cdata from .. import coredata as cdata
from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary
from ..compilers import detect_compiler_for from ..compilers import detect_compiler_for
@ -150,8 +150,8 @@ class IntrospectionInterpreter(AstInterpreter):
def func_add_languages(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> None: def func_add_languages(self, node: BaseNode, args: T.List[TYPE_var], kwargs: T.Dict[str, TYPE_var]) -> None:
kwargs = self.flatten_kwargs(kwargs) kwargs = self.flatten_kwargs(kwargs)
required = kwargs.get('required', True) required = kwargs.get('required', True)
assert isinstance(required, (bool, cdata.UserFeatureOption)), 'for mypy' assert isinstance(required, (bool, options.UserFeatureOption)), 'for mypy'
if isinstance(required, cdata.UserFeatureOption): if isinstance(required, options.UserFeatureOption):
required = required.is_enabled() required = required.is_enabled()
if 'native' in kwargs: if 'native' in kwargs:
native = kwargs.get('native', False) native = kwargs.get('native', False)

@ -23,7 +23,7 @@ import typing as T
from . import builder from . import builder
from . import version from . import version
from ..mesonlib import MesonException, Popen_safe, OptionKey from ..mesonlib import MesonException, Popen_safe, OptionKey
from .. import coredata from .. import coredata, options
if T.TYPE_CHECKING: if T.TYPE_CHECKING:
from types import ModuleType from types import ModuleType
@ -712,11 +712,11 @@ def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser.
build = builder.Builder(filename) build = builder.Builder(filename)
# Generate project options # Generate project options
options: T.Dict[OptionKey, coredata.UserOption] = {} project_options: T.Dict[OptionKey, options.UserOption] = {}
for feature in cargo.features: for feature in cargo.features:
key = OptionKey(_option_name(feature), subproject=subp_name) key = OptionKey(_option_name(feature), subproject=subp_name)
enabled = feature == 'default' enabled = feature == 'default'
options[key] = coredata.UserBooleanOption(key.name, f'Cargo {feature} feature', enabled) project_options[key] = options.UserBooleanOption(key.name, f'Cargo {feature} feature', enabled)
ast = _create_project(cargo, build) ast = _create_project(cargo, build)
ast += [build.assign(build.function('import', [build.string('rust')]), 'rust')] ast += [build.assign(build.function('import', [build.string('rust')]), 'rust')]
@ -730,4 +730,4 @@ def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser.
for crate_type in cargo.lib.crate_type: for crate_type in cargo.lib.crate_type:
ast.extend(_create_lib(cargo, build, crate_type)) ast.extend(_create_lib(cargo, build, crate_type))
return build.block(ast), options return build.block(ast), project_options

@ -6,7 +6,7 @@ from __future__ import annotations
import os.path import os.path
import typing as T import typing as T
from .. import coredata from .. import options
from .. import mlog from .. import mlog
from ..mesonlib import MesonException, version_compare, OptionKey from ..mesonlib import MesonException, version_compare, OptionKey
from .c_function_attributes import C_FUNC_ATTRIBUTES from .c_function_attributes import C_FUNC_ATTRIBUTES
@ -96,7 +96,7 @@ class CCompiler(CLikeCompiler, Compiler):
opts = super().get_options() opts = super().get_options()
key = OptionKey('std', machine=self.for_machine, lang=self.language) key = OptionKey('std', machine=self.for_machine, lang=self.language)
opts.update({ opts.update({
key: coredata.UserStdOption('C', _ALL_STDS), key: options.UserStdOption('C', _ALL_STDS),
}) })
return opts return opts
@ -128,7 +128,7 @@ class _ClangCStds(CompilerMixinBase):
if version_compare(self.version, self._C23_VERSION): if version_compare(self.version, self._C23_VERSION):
stds += ['c23'] stds += ['c23']
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(stds, gnu=True) std_opt.set_versions(stds, gnu=True)
return opts return opts
@ -154,7 +154,7 @@ class ClangCCompiler(_ClangCStds, ClangCompiler, CCompiler):
if self.info.is_windows() or self.info.is_cygwin(): if self.info.is_windows() or self.info.is_cygwin():
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserArrayOption, self.create_option(options.UserArrayOption,
OptionKey('winlibs', machine=self.for_machine, lang=self.language), OptionKey('winlibs', machine=self.for_machine, lang=self.language),
'Standard Win libraries to link against', 'Standard Win libraries to link against',
gnu_winlibs), gnu_winlibs),
@ -247,7 +247,7 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c90', 'c99', 'c11'], gnu=True) std_opt.set_versions(['c90', 'c99', 'c11'], gnu=True)
return opts return opts
@ -298,12 +298,12 @@ class GnuCCompiler(GnuCompiler, CCompiler):
stds += ['c23'] stds += ['c23']
key = OptionKey('std', machine=self.for_machine, lang=self.language) key = OptionKey('std', machine=self.for_machine, lang=self.language)
std_opt = opts[key] std_opt = opts[key]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(stds, gnu=True) std_opt.set_versions(stds, gnu=True)
if self.info.is_windows() or self.info.is_cygwin(): if self.info.is_windows() or self.info.is_cygwin():
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserArrayOption, self.create_option(options.UserArrayOption,
key.evolve('winlibs'), key.evolve('winlibs'),
'Standard Win libraries to link against', 'Standard Win libraries to link against',
gnu_winlibs), gnu_winlibs),
@ -377,7 +377,7 @@ class ElbrusCCompiler(ElbrusCompiler, CCompiler):
if version_compare(self.version, '>=1.26.00'): if version_compare(self.version, '>=1.26.00'):
stds += ['c17', 'c18', 'iso9899:2017', 'iso9899:2018', 'gnu17', 'gnu18'] stds += ['c17', 'c18', 'iso9899:2017', 'iso9899:2018', 'gnu17', 'gnu18']
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(stds) std_opt.set_versions(stds)
return opts return opts
@ -416,7 +416,7 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler):
if version_compare(self.version, '>=16.0.0'): if version_compare(self.version, '>=16.0.0'):
stds += ['c11'] stds += ['c11']
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(stds, gnu=True) std_opt.set_versions(stds, gnu=True)
return opts return opts
@ -441,7 +441,7 @@ class VisualStudioLikeCCompilerMixin(CompilerMixinBase):
return self.update_options( return self.update_options(
super().get_options(), super().get_options(),
self.create_option( self.create_option(
coredata.UserArrayOption, options.UserArrayOption,
OptionKey('winlibs', machine=self.for_machine, lang=self.language), OptionKey('winlibs', machine=self.for_machine, lang=self.language),
'Windows libs to link against.', 'Windows libs to link against.',
msvc_winlibs, msvc_winlibs,
@ -480,7 +480,7 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi
if version_compare(self.version, self._C17_VERSION): if version_compare(self.version, self._C17_VERSION):
stds += ['c17', 'c18'] stds += ['c17', 'c18']
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(stds, gnu=True, gnu_deprecated=True) std_opt.set_versions(stds, gnu=True, gnu_deprecated=True)
return opts return opts
@ -529,7 +529,7 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = super().get_options() opts = super().get_options()
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c89', 'c99', 'c11']) std_opt.set_versions(['c89', 'c99', 'c11'])
return opts return opts
@ -562,7 +562,7 @@ class ArmCCompiler(ArmCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c89', 'c99', 'c11']) std_opt.set_versions(['c89', 'c99', 'c11'])
return opts return opts
@ -591,7 +591,7 @@ class CcrxCCompiler(CcrxCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c89', 'c99']) std_opt.set_versions(['c89', 'c99'])
return opts return opts
@ -638,7 +638,7 @@ class Xc16CCompiler(Xc16Compiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c89', 'c99'], gnu=True) std_opt.set_versions(['c89', 'c99'], gnu=True)
return opts return opts
@ -683,7 +683,7 @@ class CompCertCCompiler(CompCertCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c89', 'c99']) std_opt.set_versions(['c89', 'c99'])
return opts return opts
@ -720,7 +720,7 @@ class TICCompiler(TICompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c89', 'c99', 'c11']) std_opt.set_versions(['c89', 'c99', 'c11'])
return opts return opts

@ -15,6 +15,7 @@ from functools import lru_cache
from .. import coredata from .. import coredata
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
from .. import options
from ..mesonlib import ( from ..mesonlib import (
HoldableObject, HoldableObject,
EnvironmentException, MesonException, EnvironmentException, MesonException,
@ -35,7 +36,7 @@ if T.TYPE_CHECKING:
CompilerType = T.TypeVar('CompilerType', bound='Compiler') CompilerType = T.TypeVar('CompilerType', bound='Compiler')
_T = T.TypeVar('_T') _T = T.TypeVar('_T')
UserOptionType = T.TypeVar('UserOptionType', bound=coredata.UserOption) UserOptionType = T.TypeVar('UserOptionType', bound=options.UserOption)
"""This file contains the data files of all compilers Meson knows """This file contains the data files of all compilers Meson knows
about. To support a new compiler, add its information below. about. To support a new compiler, add its information below.
@ -209,40 +210,40 @@ clike_debug_args: T.Dict[bool, T.List[str]] = {
MSCRT_VALS = ['none', 'md', 'mdd', 'mt', 'mtd'] MSCRT_VALS = ['none', 'md', 'mdd', 'mt', 'mtd']
@dataclass @dataclass
class BaseOption(T.Generic[coredata._T, coredata._U]): class BaseOption(T.Generic[options._T, options._U]):
opt_type: T.Type[coredata._U] opt_type: T.Type[options._U]
description: str description: str
default: T.Any = None default: T.Any = None
choices: T.Any = None choices: T.Any = None
def init_option(self, name: OptionKey) -> coredata._U: def init_option(self, name: OptionKey) -> options._U:
keywords = {'value': self.default} keywords = {'value': self.default}
if self.choices: if self.choices:
keywords['choices'] = self.choices keywords['choices'] = self.choices
return self.opt_type(name.name, self.description, **keywords) return self.opt_type(name.name, self.description, **keywords)
BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = { BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = {
OptionKey('b_pch'): BaseOption(coredata.UserBooleanOption, 'Use precompiled headers', True), OptionKey('b_pch'): BaseOption(options.UserBooleanOption, 'Use precompiled headers', True),
OptionKey('b_lto'): BaseOption(coredata.UserBooleanOption, 'Use link time optimization', False), OptionKey('b_lto'): BaseOption(options.UserBooleanOption, 'Use link time optimization', False),
OptionKey('b_lto_threads'): BaseOption(coredata.UserIntegerOption, 'Use multiple threads for Link Time Optimization', (None, None, 0)), OptionKey('b_lto_threads'): BaseOption(options.UserIntegerOption, 'Use multiple threads for Link Time Optimization', (None, None, 0)),
OptionKey('b_lto_mode'): BaseOption(coredata.UserComboOption, 'Select between different LTO modes.', 'default', OptionKey('b_lto_mode'): BaseOption(options.UserComboOption, 'Select between different LTO modes.', 'default',
choices=['default', 'thin']), choices=['default', 'thin']),
OptionKey('b_thinlto_cache'): BaseOption(coredata.UserBooleanOption, 'Use LLVM ThinLTO caching for faster incremental builds', False), OptionKey('b_thinlto_cache'): BaseOption(options.UserBooleanOption, 'Use LLVM ThinLTO caching for faster incremental builds', False),
OptionKey('b_thinlto_cache_dir'): BaseOption(coredata.UserStringOption, 'Directory to store ThinLTO cache objects', ''), OptionKey('b_thinlto_cache_dir'): BaseOption(options.UserStringOption, 'Directory to store ThinLTO cache objects', ''),
OptionKey('b_sanitize'): BaseOption(coredata.UserComboOption, 'Code sanitizer to use', 'none', OptionKey('b_sanitize'): BaseOption(options.UserComboOption, 'Code sanitizer to use', 'none',
choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined']), choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined']),
OptionKey('b_lundef'): BaseOption(coredata.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True), OptionKey('b_lundef'): BaseOption(options.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True),
OptionKey('b_asneeded'): BaseOption(coredata.UserBooleanOption, 'Use -Wl,--as-needed when linking', True), OptionKey('b_asneeded'): BaseOption(options.UserBooleanOption, 'Use -Wl,--as-needed when linking', True),
OptionKey('b_pgo'): BaseOption(coredata.UserComboOption, 'Use profile guided optimization', 'off', OptionKey('b_pgo'): BaseOption(options.UserComboOption, 'Use profile guided optimization', 'off',
choices=['off', 'generate', 'use']), choices=['off', 'generate', 'use']),
OptionKey('b_coverage'): BaseOption(coredata.UserBooleanOption, 'Enable coverage tracking.', False), OptionKey('b_coverage'): BaseOption(options.UserBooleanOption, 'Enable coverage tracking.', False),
OptionKey('b_colorout'): BaseOption(coredata.UserComboOption, 'Use colored output', 'always', OptionKey('b_colorout'): BaseOption(options.UserComboOption, 'Use colored output', 'always',
choices=['auto', 'always', 'never']), choices=['auto', 'always', 'never']),
OptionKey('b_ndebug'): BaseOption(coredata.UserComboOption, 'Disable asserts', 'false', choices=['true', 'false', 'if-release']), OptionKey('b_ndebug'): BaseOption(options.UserComboOption, 'Disable asserts', 'false', choices=['true', 'false', 'if-release']),
OptionKey('b_staticpic'): BaseOption(coredata.UserBooleanOption, 'Build static libraries as position independent', True), OptionKey('b_staticpic'): BaseOption(options.UserBooleanOption, 'Build static libraries as position independent', True),
OptionKey('b_pie'): BaseOption(coredata.UserBooleanOption, 'Build executables as position independent', False), OptionKey('b_pie'): BaseOption(options.UserBooleanOption, 'Build executables as position independent', False),
OptionKey('b_bitcode'): BaseOption(coredata.UserBooleanOption, 'Generate and embed bitcode (only macOS/iOS/tvOS)', False), OptionKey('b_bitcode'): BaseOption(options.UserBooleanOption, 'Generate and embed bitcode (only macOS/iOS/tvOS)', False),
OptionKey('b_vscrt'): BaseOption(coredata.UserComboOption, 'VS run-time library type to use.', 'from_buildtype', OptionKey('b_vscrt'): BaseOption(options.UserComboOption, 'VS run-time library type to use.', 'from_buildtype',
choices=MSCRT_VALS + ['from_buildtype', 'static_from_buildtype']), choices=MSCRT_VALS + ['from_buildtype', 'static_from_buildtype']),
} }
@ -1365,12 +1366,12 @@ def get_global_options(lang: str,
comp_options = env.options.get(comp_key, []) comp_options = env.options.get(comp_key, [])
link_options = env.options.get(largkey, []) link_options = env.options.get(largkey, [])
cargs = coredata.UserArrayOption( cargs = options.UserArrayOption(
f'{lang}_{argkey.name}', f'{lang}_{argkey.name}',
description + ' compiler', description + ' compiler',
comp_options, split_args=True, allow_dups=True) comp_options, split_args=True, allow_dups=True)
largs = coredata.UserArrayOption( largs = options.UserArrayOption(
f'{lang}_{largkey.name}', f'{lang}_{largkey.name}',
description + ' linker', description + ' linker',
link_options, split_args=True, allow_dups=True) link_options, split_args=True, allow_dups=True)

@ -8,7 +8,7 @@ import functools
import os.path import os.path
import typing as T import typing as T
from .. import coredata from .. import options
from .. import mlog from .. import mlog
from ..mesonlib import MesonException, version_compare, OptionKey from ..mesonlib import MesonException, version_compare, OptionKey
@ -174,7 +174,7 @@ class CPPCompiler(CLikeCompiler, Compiler):
opts = super().get_options() opts = super().get_options()
key = OptionKey('std', machine=self.for_machine, lang=self.language) key = OptionKey('std', machine=self.for_machine, lang=self.language)
opts.update({ opts.update({
key: coredata.UserStdOption('C++', _ALL_STDS), key: options.UserStdOption('C++', _ALL_STDS),
}) })
return opts return opts
@ -242,16 +242,16 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler):
key = OptionKey('key', machine=self.for_machine, lang=self.language) key = OptionKey('key', machine=self.for_machine, lang=self.language)
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
key.evolve('eh'), key.evolve('eh'),
'C++ exception handling type.', 'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('rtti'), key.evolve('rtti'),
'Enable RTTI', 'Enable RTTI',
True), True),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('debugstl'), key.evolve('debugstl'),
'STL debug mode', 'STL debug mode',
False), False),
@ -264,12 +264,12 @@ class ClangCPPCompiler(_StdCPPLibMixin, ClangCompiler, CPPCompiler):
if version_compare(self.version, self._CPP26_VERSION): if version_compare(self.version, self._CPP26_VERSION):
cppstd_choices.append('c++26') cppstd_choices.append('c++26')
std_opt = opts[key.evolve('std')] std_opt = opts[key.evolve('std')]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(cppstd_choices, gnu=True) std_opt.set_versions(cppstd_choices, gnu=True)
if self.info.is_windows() or self.info.is_cygwin(): if self.info.is_windows() or self.info.is_cygwin():
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserArrayOption, self.create_option(options.UserArrayOption,
key.evolve('winlibs'), key.evolve('winlibs'),
'Standard Win libraries to link against', 'Standard Win libraries to link against',
gnu_winlibs), gnu_winlibs),
@ -393,14 +393,14 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler):
key = OptionKey('std', machine=self.for_machine, lang=self.language) key = OptionKey('std', machine=self.for_machine, lang=self.language)
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
key.evolve('eh'), key.evolve('eh'),
'C++ exception handling type.', 'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
) )
std_opt = opts[key] std_opt = opts[key]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c++98', 'c++03', 'c++11', 'c++14', 'c++17'], gnu=True) std_opt.set_versions(['c++98', 'c++03', 'c++11', 'c++14', 'c++17'], gnu=True)
return opts return opts
@ -442,16 +442,16 @@ class GnuCPPCompiler(_StdCPPLibMixin, GnuCompiler, CPPCompiler):
opts = CPPCompiler.get_options(self) opts = CPPCompiler.get_options(self)
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
key.evolve('eh'), key.evolve('eh'),
'C++ exception handling type.', 'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('rtti'), key.evolve('rtti'),
'Enable RTTI', 'Enable RTTI',
True), True),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('debugstl'), key.evolve('debugstl'),
'STL debug mode', 'STL debug mode',
False), False),
@ -465,12 +465,12 @@ class GnuCPPCompiler(_StdCPPLibMixin, GnuCompiler, CPPCompiler):
if version_compare(self.version, '>=14.0.0'): if version_compare(self.version, '>=14.0.0'):
cppstd_choices.append('c++26') cppstd_choices.append('c++26')
std_opt = opts[key] std_opt = opts[key]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(cppstd_choices, gnu=True) std_opt.set_versions(cppstd_choices, gnu=True)
if self.info.is_windows() or self.info.is_cygwin(): if self.info.is_windows() or self.info.is_cygwin():
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserArrayOption, self.create_option(options.UserArrayOption,
key.evolve('winlibs'), key.evolve('winlibs'),
'Standard Win libraries to link against', 'Standard Win libraries to link against',
gnu_winlibs), gnu_winlibs),
@ -582,18 +582,18 @@ class ElbrusCPPCompiler(ElbrusCompiler, CPPCompiler):
key = OptionKey('std', machine=self.for_machine, lang=self.language) key = OptionKey('std', machine=self.for_machine, lang=self.language)
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
key.evolve('eh'), key.evolve('eh'),
'C++ exception handling type.', 'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('debugstl'), key.evolve('debugstl'),
'STL debug mode', 'STL debug mode',
False), False),
) )
std_opt = opts[key] std_opt = opts[key]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(cpp_stds, gnu=True) std_opt.set_versions(cpp_stds, gnu=True)
return opts return opts
@ -661,22 +661,22 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler):
key = OptionKey('std', machine=self.for_machine, lang=self.language) key = OptionKey('std', machine=self.for_machine, lang=self.language)
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
key.evolve('eh'), key.evolve('eh'),
'C++ exception handling type.', 'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('rtti'), key.evolve('rtti'),
'Enable RTTI', 'Enable RTTI',
True), True),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('debugstl'), key.evolve('debugstl'),
'STL debug mode', 'STL debug mode',
False), False),
) )
std_opt = opts[key] std_opt = opts[key]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(c_stds + g_stds) std_opt.set_versions(c_stds + g_stds)
return opts return opts
@ -734,22 +734,22 @@ class VisualStudioLikeCPPCompilerMixin(CompilerMixinBase):
key = OptionKey('std', machine=self.for_machine, lang=self.language) key = OptionKey('std', machine=self.for_machine, lang=self.language)
self.update_options( self.update_options(
opts, opts,
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
key.evolve('eh'), key.evolve('eh'),
'C++ exception handling type.', 'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
self.create_option(coredata.UserBooleanOption, self.create_option(options.UserBooleanOption,
key.evolve('rtti'), key.evolve('rtti'),
'Enable RTTI', 'Enable RTTI',
True), True),
self.create_option(coredata.UserArrayOption, self.create_option(options.UserArrayOption,
key.evolve('winlibs'), key.evolve('winlibs'),
'Windows libs to link against.', 'Windows libs to link against.',
msvc_winlibs), msvc_winlibs),
) )
std_opt = opts[key] std_opt = opts[key]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(cpp_stds) std_opt.set_versions(cpp_stds)
return opts return opts
@ -912,7 +912,7 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CPPCompiler.get_options(self) opts = CPPCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c++03', 'c++11']) std_opt.set_versions(['c++03', 'c++11'])
return opts return opts
@ -973,7 +973,7 @@ class TICPPCompiler(TICompiler, CPPCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CPPCompiler.get_options(self) opts = CPPCompiler.get_options(self)
std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)] std_opt = opts[OptionKey('std', machine=self.for_machine, lang=self.language)]
assert isinstance(std_opt, coredata.UserStdOption), 'for mypy' assert isinstance(std_opt, options.UserStdOption), 'for mypy'
std_opt.set_versions(['c++03']) std_opt.set_versions(['c++03'])
return opts return opts

@ -9,6 +9,7 @@ import string
import typing as T import typing as T
from .. import coredata from .. import coredata
from .. import options
from .. import mlog from .. import mlog
from ..mesonlib import ( from ..mesonlib import (
EnvironmentException, Popen_safe, EnvironmentException, Popen_safe,
@ -643,12 +644,12 @@ class CudaCompiler(Compiler):
return self.update_options( return self.update_options(
super().get_options(), super().get_options(),
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
OptionKey('std', machine=self.for_machine, lang=self.language), OptionKey('std', machine=self.for_machine, lang=self.language),
'C++ language standard to use with CUDA', 'C++ language standard to use with CUDA',
cpp_stds, cpp_stds,
'none'), 'none'),
self.create_option(coredata.UserStringOption, self.create_option(options.UserStringOption,
OptionKey('ccbindir', machine=self.for_machine, lang=self.language), OptionKey('ccbindir', machine=self.for_machine, lang=self.language),
'CUDA non-default toolchain directory to use (-ccbin)', 'CUDA non-default toolchain directory to use (-ccbin)',
''), ''),

@ -6,7 +6,7 @@ from __future__ import annotations
import typing as T import typing as T
from .. import coredata from .. import options
from ..mesonlib import EnvironmentException, OptionKey, version_compare from ..mesonlib import EnvironmentException, OptionKey, version_compare
from .compilers import Compiler from .compilers import Compiler
@ -69,12 +69,12 @@ class CythonCompiler(Compiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
return self.update_options( return self.update_options(
super().get_options(), super().get_options(),
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
OptionKey('version', machine=self.for_machine, lang=self.language), OptionKey('version', machine=self.for_machine, lang=self.language),
'Python version to target', 'Python version to target',
['2', '3'], ['2', '3'],
'3'), '3'),
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
OptionKey('language', machine=self.for_machine, lang=self.language), OptionKey('language', machine=self.for_machine, lang=self.language),
'Output C or C++ files', 'Output C or C++ files',
['c', 'cpp'], ['c', 'cpp'],

@ -6,7 +6,7 @@ from __future__ import annotations
import typing as T import typing as T
import os import os
from .. import coredata from .. import options
from .compilers import ( from .compilers import (
clike_debug_args, clike_debug_args,
Compiler, Compiler,
@ -114,7 +114,7 @@ class FortranCompiler(CLikeCompiler, Compiler):
def get_options(self) -> 'MutableKeyedOptionDictType': def get_options(self) -> 'MutableKeyedOptionDictType':
return self.update_options( return self.update_options(
super().get_options(), super().get_options(),
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
OptionKey('std', machine=self.for_machine, lang=self.language), OptionKey('std', machine=self.for_machine, lang=self.language),
'Fortran language standard to use', 'Fortran language standard to use',
['none'], ['none'],

@ -9,6 +9,7 @@ import os.path
import typing as T import typing as T
from ... import coredata from ... import coredata
from ... import options
from ... import mesonlib from ... import mesonlib
from ...mesonlib import OptionKey from ...mesonlib import OptionKey
from ...mesonlib import LibType from ...mesonlib import LibType
@ -59,7 +60,7 @@ class EmscriptenMixin(Compiler):
return self.update_options( return self.update_options(
super().get_options(), super().get_options(),
self.create_option( self.create_option(
coredata.UserIntegerOption, options.UserIntegerOption,
OptionKey('thread_count', machine=self.for_machine, lang=self.language), OptionKey('thread_count', machine=self.for_machine, lang=self.language),
'Number of threads to use in web assembly, set to 0 to disable', 'Number of threads to use in web assembly, set to 0 to disable',
(0, None, 4), # Default was picked at random (0, None, 4), # Default was picked at random

@ -6,6 +6,7 @@ from __future__ import annotations
import typing as T import typing as T
from .. import coredata from .. import coredata
from .. import options
from ..mesonlib import OptionKey from ..mesonlib import OptionKey
from .compilers import Compiler from .compilers import Compiler
@ -80,7 +81,7 @@ class ClangObjCCompiler(ClangCompiler, ObjCCompiler):
def get_options(self) -> 'coredata.MutableKeyedOptionDictType': def get_options(self) -> 'coredata.MutableKeyedOptionDictType':
return self.update_options( return self.update_options(
super().get_options(), super().get_options(),
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
OptionKey('std', machine=self.for_machine, lang='c'), OptionKey('std', machine=self.for_machine, lang='c'),
'C language standard to use', 'C language standard to use',
['none', 'c89', 'c99', 'c11', 'c17', 'gnu89', 'gnu99', 'gnu11', 'gnu17'], ['none', 'c89', 'c99', 'c11', 'c17', 'gnu89', 'gnu99', 'gnu11', 'gnu17'],

@ -6,6 +6,7 @@ from __future__ import annotations
import typing as T import typing as T
from .. import coredata from .. import coredata
from .. import options
from ..mesonlib import OptionKey from ..mesonlib import OptionKey
from .mixins.clike import CLikeCompiler from .mixins.clike import CLikeCompiler
@ -80,7 +81,7 @@ class ClangObjCPPCompiler(ClangCompiler, ObjCPPCompiler):
def get_options(self) -> coredata.MutableKeyedOptionDictType: def get_options(self) -> coredata.MutableKeyedOptionDictType:
return self.update_options( return self.update_options(
super().get_options(), super().get_options(),
self.create_option(coredata.UserComboOption, self.create_option(options.UserComboOption,
OptionKey('std', machine=self.for_machine, lang='cpp'), OptionKey('std', machine=self.for_machine, lang='cpp'),
'C++ language standard to use', 'C++ language standard to use',
['none', 'c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++2b', ['none', 'c++98', 'c++11', 'c++14', 'c++17', 'c++20', 'c++2b',

@ -9,7 +9,7 @@ import textwrap
import re import re
import typing as T import typing as T
from .. import coredata from .. import options
from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged, OptionKey from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged, OptionKey
from .compilers import Compiler, clike_debug_args from .compilers import Compiler, clike_debug_args
@ -158,7 +158,7 @@ class RustCompiler(Compiler):
# use_linker_args method instead. # use_linker_args method instead.
def get_options(self) -> MutableKeyedOptionDictType: def get_options(self) -> MutableKeyedOptionDictType:
return dict((self.create_option(coredata.UserComboOption, return dict((self.create_option(options.UserComboOption,
OptionKey('std', machine=self.for_machine, lang=self.language), OptionKey('std', machine=self.for_machine, lang=self.language),
'Rust edition to use', 'Rust edition to use',
['none', '2015', '2018', '2021'], ['none', '2015', '2018', '2021'],

@ -6,7 +6,7 @@ from __future__ import annotations
import copy import copy
from . import mlog, mparser from . import mlog, mparser, options
import pickle, os, uuid import pickle, os, uuid
import sys import sys
from itertools import chain from itertools import chain
@ -15,12 +15,10 @@ from collections import OrderedDict, abc
from dataclasses import dataclass from dataclasses import dataclass
from .mesonlib import ( from .mesonlib import (
HoldableObject, MesonBugException, MesonBugException,
MesonException, EnvironmentException, MachineChoice, PerMachine, MesonException, EnvironmentException, MachineChoice, PerMachine,
PerMachineDefaultable, default_libdir, default_libexecdir, PerMachineDefaultable,
default_prefix, default_datadir, default_includedir, default_infodir, OptionKey, OptionType, stringlistify,
default_localedir, default_mandir, default_sbindir, default_sysconfdir,
listify_array_value, OptionKey, OptionType, stringlistify,
pickle_load pickle_load
) )
import ast import ast
@ -56,8 +54,8 @@ if T.TYPE_CHECKING:
cross_file: T.List[str] cross_file: T.List[str]
native_file: T.List[str] native_file: T.List[str]
OptionDictType = T.Union[T.Dict[str, 'UserOption[T.Any]'], 'OptionsView'] OptionDictType = T.Union[T.Dict[str, 'options.UserOption[T.Any]'], 'OptionsView']
MutableKeyedOptionDictType = T.Dict['OptionKey', 'UserOption[T.Any]'] MutableKeyedOptionDictType = T.Dict['OptionKey', 'options.UserOption[T.Any]']
KeyedOptionDictType = T.Union[MutableKeyedOptionDictType, 'OptionsView'] KeyedOptionDictType = T.Union[MutableKeyedOptionDictType, 'OptionsView']
CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, FileOrString, T.Tuple[str, ...], CompileCheckMode] CompilerCheckCacheKey = T.Tuple[T.Tuple[str, ...], str, FileOrString, T.Tuple[str, ...], CompileCheckMode]
# code, args # code, args
@ -82,20 +80,11 @@ if stable_version.endswith('.99'):
stable_version_array[-2] = str(int(stable_version_array[-2]) + 1) stable_version_array[-2] = str(int(stable_version_array[-2]) + 1)
stable_version = '.'.join(stable_version_array) 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]: def get_genvs_default_buildtype_list() -> list[str]:
# just debug, debugoptimized, and release for now # just debug, debugoptimized, and release for now
# but this should probably be configurable through some extra option, alongside --genvslite. # but this should probably be configurable through some extra option, alongside --genvslite.
return buildtypelist[1:-2] return options.buildtypelist[1:-2]
class MesonVersionMismatchException(MesonException): class MesonVersionMismatchException(MesonException):
@ -108,312 +97,6 @@ class MesonVersionMismatchException(MesonException):
self.current_version = current_version 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): class DependencyCacheType(enum.Enum):
OTHER = 0 OTHER = 0
@ -664,7 +347,7 @@ class CoreData:
# getting the "system default" is always wrong on multiarch # getting the "system default" is always wrong on multiarch
# platforms as it gets a value like lib/x86_64-linux-gnu. # platforms as it gets a value like lib/x86_64-linux-gnu.
if self.cross_files: if self.cross_files:
BUILTIN_OPTIONS[OptionKey('libdir')].default = 'lib' options.BUILTIN_OPTIONS[OptionKey('libdir')].default = 'lib'
def sanitize_prefix(self, prefix: str) -> str: def sanitize_prefix(self, prefix: str) -> str:
prefix = os.path.expanduser(prefix) prefix = os.path.expanduser(prefix)
@ -698,7 +381,7 @@ class CoreData:
except TypeError: except TypeError:
return value return value
if option.name.endswith('dir') and value.is_absolute() and \ 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:
# Try to relativize the path. # Try to relativize the path.
value = value.relative_to(prefix) value = value.relative_to(prefix)
@ -717,15 +400,15 @@ class CoreData:
def init_builtins(self, subproject: str) -> None: def init_builtins(self, subproject: str) -> None:
# Create builtin options with default values # 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) self.add_builtin_option(self.options, key.evolve(subproject=subproject), opt)
for for_machine in iter(MachineChoice): 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) self.add_builtin_option(self.options, key.evolve(subproject=subproject, machine=for_machine), opt)
@staticmethod @staticmethod
def add_builtin_option(opts_map: 'MutableKeyedOptionDictType', key: OptionKey, def add_builtin_option(opts_map: 'MutableKeyedOptionDictType', key: OptionKey,
opt: 'BuiltinOption') -> None: opt: 'options.BuiltinOption') -> None:
if key.subproject: if key.subproject:
if opt.yielding: if opt.yielding:
# This option is global and not per-subproject # This option is global and not per-subproject
@ -733,17 +416,17 @@ class CoreData:
value = opts_map[key.as_root()].value value = opts_map[key.as_root()].value
else: else:
value = None 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: def init_backend_options(self, backend_name: str) -> None:
if backend_name == 'ninja': if backend_name == 'ninja':
self.options[OptionKey('backend_max_links')] = UserIntegerOption( self.options[OptionKey('backend_max_links')] = options.UserIntegerOption(
'backend_max_links', 'backend_max_links',
'Maximum number of linker processes to run or 0 for no ' 'Maximum number of linker processes to run or 0 for no '
'limit', 'limit',
(0, None, 0)) (0, None, 0))
elif backend_name.startswith('vs'): elif backend_name.startswith('vs'):
self.options[OptionKey('backend_startup_project')] = UserStringOption( self.options[OptionKey('backend_startup_project')] = options.UserStringOption(
'backend_startup_project', 'backend_startup_project',
'Default project to execute in Visual Studio', 'Default project to execute in Visual Studio',
'') '')
@ -881,7 +564,7 @@ class CoreData:
@staticmethod @staticmethod
def is_per_machine_option(optname: OptionKey) -> bool: 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 True
return optname.lang is not None return optname.lang is not None
@ -930,7 +613,7 @@ class CoreData:
def copy_build_options_from_regular_ones(self) -> bool: def copy_build_options_from_regular_ones(self) -> bool:
dirty = False dirty = False
assert not self.is_cross_build() 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] o = self.options[k]
dirty |= self.options[k.as_build()].set_value(o.value) dirty |= self.options[k.as_build()].set_value(o.value)
for bk, bv in self.options.items(): for bk, bv in self.options.items():
@ -944,21 +627,21 @@ class CoreData:
return dirty 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 dirty = False
if not self.is_cross_build(): 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 # Set prefix first because it's needed to sanitize other options
pfk = OptionKey('prefix') pfk = OptionKey('prefix')
if pfk in options: if pfk in opts_to_set:
prefix = self.sanitize_prefix(options[pfk]) prefix = self.sanitize_prefix(opts_to_set[pfk])
dirty |= self.options[OptionKey('prefix')].set_value(prefix) dirty |= self.options[OptionKey('prefix')].set_value(prefix)
for key in BUILTIN_DIR_NOPREFIX_OPTIONS: for key in options.BUILTIN_DIR_NOPREFIX_OPTIONS:
if key not in options: if key not in opts_to_set:
dirty |= self.options[key].set_value(BUILTIN_OPTIONS[key].prefixed_default(key, prefix)) dirty |= self.options[key].set_value(options.BUILTIN_OPTIONS[key].prefixed_default(key, prefix))
unknown_options: T.List[OptionKey] = [] unknown_options: T.List[OptionKey] = []
for k, v in options.items(): for k, v in opts_to_set.items():
if k == pfk: if k == pfk:
continue continue
elif k in self.options: 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: 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, '') 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), parser, ' (just for host machine)')
b.add_to_argparse(str(n.as_build()), parser, ' (just for build 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", 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. # Merge builtin options set with --option into the dict.
for key in chain( for key in chain(
BUILTIN_OPTIONS.keys(), options.BUILTIN_OPTIONS.keys(),
(k.as_build() for k in BUILTIN_OPTIONS_PER_MACHINE.keys()), (k.as_build() for k in options.BUILTIN_OPTIONS_PER_MACHINE.keys()),
BUILTIN_OPTIONS_PER_MACHINE.keys(), options.BUILTIN_OPTIONS_PER_MACHINE.keys(),
): ):
name = str(key) name = str(key)
value = getattr(args, name, None) value = getattr(args, name, None)
if value is not None: if value is not None:
if key in args.cmd_line_options: 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( raise MesonException(
f'Got argument {name} as both -D{name} and {cmdline_name}. Pick one.') f'Got argument {name} as both -D{name} and {cmdline_name}. Pick one.')
args.cmd_line_options[key] = value args.cmd_line_options[key] = value
delattr(args, name) 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]) # TODO: the typing here could be made more explicit using a TypeDict from
# python 3.8 or typing_extensions
class BuiltinOption(T.Generic[_T, _U]): original_options: KeyedOptionDictType
subproject: T.Optional[str] = None
"""Class for a builtin option type. overrides: T.Optional[T.Mapping[OptionKey, T.Union[str, int, bool, T.List[str]]]] = None
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
@staticmethod def __getitem__(self, key: OptionKey) -> options.UserOption:
def argparse_name_to_arg(name: str) -> str: # FIXME: This is fundamentally the same algorithm than interpreter.get_option_internal().
if name == 'warning_level': # We should try to share the code somehow.
return '--warnlevel' 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: else:
return '--' + name.replace('_', '-') opt = self.original_options[key]
if opt.yielding:
def prefixed_default(self, name: 'OptionKey', prefix: str = '') -> T.Any: opt = self.original_options.get(key.as_root(), opt)
if self.opt_type in [UserComboOption, UserIntegerOption]: if self.overrides:
return self.default override_value = self.overrides.get(key.as_root())
try: if override_value is not None:
return BUILTIN_DIR_NOPREFIX_OPTIONS[name][prefix] opt = copy.copy(opt)
except KeyError: opt.set_value(override_value)
pass return opt
return self.default
def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffix: str) -> None: def __iter__(self) -> T.Iterator[OptionKey]:
kwargs = OrderedDict() return iter(self.original_options)
c = self._argparse_choices() def __len__(self) -> int:
b = self._argparse_action() return len(self.original_options)
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'): {},
}
FORBIDDEN_TARGET_NAMES = frozenset({ FORBIDDEN_TARGET_NAMES = frozenset({
'clean', 'clean',

@ -13,6 +13,7 @@ import typing as T
from .. import build from .. import build
from .. import coredata from .. import coredata
from .. import dependencies from .. import dependencies
from .. import options
from .. import mesonlib from .. import mesonlib
from .. import mlog from .. import mlog
from ..compilers import SUFFIX_TO_LANG, RunResult from ..compilers import SUFFIX_TO_LANG, RunResult
@ -89,7 +90,7 @@ if T.TYPE_CHECKING:
header_include_directories: T.List[build.IncludeDirs] header_include_directories: T.List[build.IncludeDirs]
header_no_builtin_args: bool header_no_builtin_args: bool
header_prefix: str header_prefix: str
header_required: T.Union[bool, coredata.UserFeatureOption] header_required: T.Union[bool, options.UserFeatureOption]
class PreprocessKW(TypedDict): class PreprocessKW(TypedDict):
output: str output: str
@ -685,7 +686,7 @@ class CompilerHolder(ObjectHolder['Compiler']):
@typed_pos_args('compiler.find_library', str) @typed_pos_args('compiler.find_library', str)
@typed_kwargs( @typed_kwargs(
'compiler.find_library', 'compiler.find_library',
KwargInfo('required', (bool, coredata.UserFeatureOption), default=True), KwargInfo('required', (bool, options.UserFeatureOption), default=True),
KwargInfo('has_headers', ContainerTypeInfo(list, str), listify=True, default=[], since='0.50.0'), KwargInfo('has_headers', ContainerTypeInfo(list, str), listify=True, default=[], since='0.50.0'),
KwargInfo('static', (bool, NoneType), since='0.51.0'), KwargInfo('static', (bool, NoneType), since='0.51.0'),
KwargInfo('disabler', bool, default=False, since='0.49.0'), KwargInfo('disabler', bool, default=False, since='0.49.0'),

@ -11,6 +11,7 @@ from .. import environment
from .. import coredata from .. import coredata
from .. import dependencies from .. import dependencies
from .. import mlog from .. import mlog
from .. import options
from .. import build from .. import build
from .. import optinterpreter from .. import optinterpreter
from .. import compilers from .. import compilers
@ -163,7 +164,7 @@ class Summary:
elif isinstance(i, Disabler): elif isinstance(i, Disabler):
FeatureNew.single_use('disabler in summary', '0.64.0', subproject) FeatureNew.single_use('disabler in summary', '0.64.0', subproject)
formatted_values.append(mlog.red('NO')) formatted_values.append(mlog.red('NO'))
elif isinstance(i, coredata.UserOption): elif isinstance(i, options.UserOption):
FeatureNew.single_use('feature option in summary', '0.58.0', subproject) FeatureNew.single_use('feature option in summary', '0.58.0', subproject)
formatted_values.append(i.printable_value()) formatted_values.append(i.printable_value())
else: else:
@ -450,7 +451,7 @@ class Interpreter(InterpreterBase, HoldableObject):
build.StructuredSources: OBJ.StructuredSourcesHolder, build.StructuredSources: OBJ.StructuredSourcesHolder,
compilers.RunResult: compilerOBJ.TryRunResultHolder, compilers.RunResult: compilerOBJ.TryRunResultHolder,
dependencies.ExternalLibrary: OBJ.ExternalLibraryHolder, dependencies.ExternalLibrary: OBJ.ExternalLibraryHolder,
coredata.UserFeatureOption: OBJ.FeatureOptionHolder, options.UserFeatureOption: OBJ.FeatureOptionHolder,
envconfig.MachineInfo: OBJ.MachineHolder, envconfig.MachineInfo: OBJ.MachineHolder,
build.ConfigurationData: OBJ.ConfigurationDataHolder, build.ConfigurationData: OBJ.ConfigurationDataHolder,
}) })
@ -1047,7 +1048,7 @@ class Interpreter(InterpreterBase, HoldableObject):
# FIXME: Are there other files used by cargo interpreter? # FIXME: Are there other files used by cargo interpreter?
[os.path.join(subdir, 'Cargo.toml')]) [os.path.join(subdir, 'Cargo.toml')])
def get_option_internal(self, optname: str) -> coredata.UserOption: def get_option_internal(self, optname: str) -> options.UserOption:
key = OptionKey.from_string(optname).evolve(subproject=self.subproject) key = OptionKey.from_string(optname).evolve(subproject=self.subproject)
if not key.is_project(): if not key.is_project():
@ -1056,7 +1057,7 @@ class Interpreter(InterpreterBase, HoldableObject):
if v is None or v.yielding: if v is None or v.yielding:
v = opts.get(key.as_root()) v = opts.get(key.as_root())
if v is not None: if v is not None:
assert isinstance(v, coredata.UserOption), 'for mypy' assert isinstance(v, options.UserOption), 'for mypy'
return v return v
try: try:
@ -1085,7 +1086,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@typed_pos_args('get_option', str) @typed_pos_args('get_option', str)
@noKwargs @noKwargs
def func_get_option(self, nodes: mparser.BaseNode, args: T.Tuple[str], def func_get_option(self, nodes: mparser.BaseNode, args: T.Tuple[str],
kwargs: 'TYPE_kwargs') -> T.Union[coredata.UserOption, 'TYPE_var']: kwargs: 'TYPE_kwargs') -> T.Union[options.UserOption, 'TYPE_var']:
optname = args[0] optname = args[0]
if ':' in optname: if ':' in optname:
raise InterpreterException('Having a colon in option name is forbidden, ' raise InterpreterException('Having a colon in option name is forbidden, '
@ -1096,10 +1097,10 @@ class Interpreter(InterpreterBase, HoldableObject):
raise InterpreterException(f'Invalid option name {optname!r}') raise InterpreterException(f'Invalid option name {optname!r}')
opt = self.get_option_internal(optname) opt = self.get_option_internal(optname)
if isinstance(opt, coredata.UserFeatureOption): if isinstance(opt, options.UserFeatureOption):
opt.name = optname opt.name = optname
return opt return opt
elif isinstance(opt, coredata.UserOption): elif isinstance(opt, options.UserOption):
if isinstance(opt.value, str): if isinstance(opt.value, str):
return P_OBJ.OptionString(opt.value, f'{{{optname}}}') return P_OBJ.OptionString(opt.value, f'{{{optname}}}')
return opt.value return opt.value

@ -8,7 +8,7 @@ import textwrap
from pathlib import Path, PurePath from pathlib import Path, PurePath
from .. import mesonlib from .. import mesonlib
from .. import coredata from .. import options
from .. import build from .. import build
from .. import mlog from .. import mlog
@ -52,7 +52,7 @@ def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired',
disabled = False disabled = False
required = False required = False
feature: T.Optional[str] = None feature: T.Optional[str] = None
if isinstance(val, coredata.UserFeatureOption): if isinstance(val, options.UserFeatureOption):
if not feature_check: if not feature_check:
feature_check = FeatureNew('User option "feature"', '0.47.0') feature_check = FeatureNew('User option "feature"', '0.47.0')
feature_check.use(subproject) feature_check.use(subproject)
@ -85,12 +85,12 @@ def extract_search_dirs(kwargs: 'kwargs.ExtractSearchDirs') -> T.List[str]:
raise InvalidCode(f'Search directory {d} is not an absolute path.') raise InvalidCode(f'Search directory {d} is not an absolute path.')
return [str(s) for s in search_dirs] return [str(s) for s in search_dirs]
class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]): class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]):
def __init__(self, option: coredata.UserFeatureOption, interpreter: 'Interpreter'): def __init__(self, option: options.UserFeatureOption, interpreter: 'Interpreter'):
super().__init__(option, interpreter) super().__init__(option, interpreter)
if option and option.is_auto(): if option and option.is_auto():
# TODO: we need to cast here because options is not a TypedDict # TODO: we need to cast here because options is not a TypedDict
auto = T.cast('coredata.UserFeatureOption', self.env.coredata.options[OptionKey('auto_features')]) auto = T.cast('options.UserFeatureOption', self.env.coredata.options[OptionKey('auto_features')])
self.held_object = copy.copy(auto) self.held_object = copy.copy(auto)
self.held_object.name = option.name self.held_object.name = option.name
self.methods.update({'enabled': self.enabled_method, self.methods.update({'enabled': self.enabled_method,
@ -108,12 +108,12 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
def value(self) -> str: def value(self) -> str:
return 'disabled' if not self.held_object else self.held_object.value return 'disabled' if not self.held_object else self.held_object.value
def as_disabled(self) -> coredata.UserFeatureOption: def as_disabled(self) -> options.UserFeatureOption:
disabled = copy.deepcopy(self.held_object) disabled = copy.deepcopy(self.held_object)
disabled.value = 'disabled' disabled.value = 'disabled'
return disabled return disabled
def as_enabled(self) -> coredata.UserFeatureOption: def as_enabled(self) -> options.UserFeatureOption:
enabled = copy.deepcopy(self.held_object) enabled = copy.deepcopy(self.held_object)
enabled.value = 'enabled' enabled.value = 'enabled'
return enabled return enabled
@ -139,7 +139,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
def auto_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool: def auto_method(self, args: T.List[TYPE_var], kwargs: TYPE_kwargs) -> bool:
return self.value == 'auto' return self.value == 'auto'
def _disable_if(self, condition: bool, message: T.Optional[str]) -> coredata.UserFeatureOption: def _disable_if(self, condition: bool, message: T.Optional[str]) -> options.UserFeatureOption:
if not condition: if not condition:
return copy.deepcopy(self.held_object) return copy.deepcopy(self.held_object)
@ -156,7 +156,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
'feature_option.require', 'feature_option.require',
_ERROR_MSG_KW, _ERROR_MSG_KW,
) )
def require_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> coredata.UserFeatureOption: def require_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> options.UserFeatureOption:
return self._disable_if(not args[0], kwargs['error_message']) return self._disable_if(not args[0], kwargs['error_message'])
@FeatureNew('feature_option.disable_if()', '1.1.0') @FeatureNew('feature_option.disable_if()', '1.1.0')
@ -165,7 +165,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
'feature_option.disable_if', 'feature_option.disable_if',
_ERROR_MSG_KW, _ERROR_MSG_KW,
) )
def disable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> coredata.UserFeatureOption: def disable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> options.UserFeatureOption:
return self._disable_if(args[0], kwargs['error_message']) return self._disable_if(args[0], kwargs['error_message'])
@FeatureNew('feature_option.enable_if()', '1.1.0') @FeatureNew('feature_option.enable_if()', '1.1.0')
@ -174,7 +174,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
'feature_option.enable_if', 'feature_option.enable_if',
_ERROR_MSG_KW, _ERROR_MSG_KW,
) )
def enable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> coredata.UserFeatureOption: def enable_if_method(self, args: T.Tuple[bool], kwargs: 'kwargs.FeatureOptionRequire') -> options.UserFeatureOption:
if not args[0]: if not args[0]:
return copy.deepcopy(self.held_object) return copy.deepcopy(self.held_object)
@ -188,13 +188,13 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
@FeatureNew('feature_option.disable_auto_if()', '0.59.0') @FeatureNew('feature_option.disable_auto_if()', '0.59.0')
@noKwargs @noKwargs
@typed_pos_args('feature_option.disable_auto_if', bool) @typed_pos_args('feature_option.disable_auto_if', bool)
def disable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> coredata.UserFeatureOption: def disable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> options.UserFeatureOption:
return copy.deepcopy(self.held_object) if self.value != 'auto' or not args[0] else self.as_disabled() return copy.deepcopy(self.held_object) if self.value != 'auto' or not args[0] else self.as_disabled()
@FeatureNew('feature_option.enable_auto_if()', '1.1.0') @FeatureNew('feature_option.enable_auto_if()', '1.1.0')
@noKwargs @noKwargs
@typed_pos_args('feature_option.enable_auto_if', bool) @typed_pos_args('feature_option.enable_auto_if', bool)
def enable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> coredata.UserFeatureOption: def enable_auto_if_method(self, args: T.Tuple[bool], kwargs: TYPE_kwargs) -> options.UserFeatureOption:
return self.as_enabled() if self.value == 'auto' and args[0] else copy.deepcopy(self.held_object) return self.as_enabled() if self.value == 'auto' and args[0] else copy.deepcopy(self.held_object)

@ -10,7 +10,7 @@ import typing as T
from typing_extensions import TypedDict, Literal, Protocol, NotRequired from typing_extensions import TypedDict, Literal, Protocol, NotRequired
from .. import build from .. import build
from .. import coredata from .. import options
from ..compilers import Compiler from ..compilers import Compiler
from ..dependencies.base import Dependency from ..dependencies.base import Dependency
from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString, OptionKey from ..mesonlib import EnvironmentVariables, MachineChoice, File, FileMode, FileOrString, OptionKey
@ -73,7 +73,7 @@ class ExtractRequired(TypedDict):
a boolean or a feature option should inherit it's arguments from this class. a boolean or a feature option should inherit it's arguments from this class.
""" """
required: T.Union[bool, coredata.UserFeatureOption] required: T.Union[bool, options.UserFeatureOption]
class ExtractSearchDirs(TypedDict): class ExtractSearchDirs(TypedDict):

@ -11,7 +11,7 @@ from .. import compilers
from ..build import (CustomTarget, BuildTarget, from ..build import (CustomTarget, BuildTarget,
CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs, CustomTargetIndex, ExtractedObjects, GeneratedList, IncludeDirs,
BothLibraries, SharedLibrary, StaticLibrary, Jar, Executable, StructuredSources) BothLibraries, SharedLibrary, StaticLibrary, Jar, Executable, StructuredSources)
from ..coredata import UserFeatureOption from ..options import UserFeatureOption
from ..dependencies import Dependency, InternalDependency from ..dependencies import Dependency, InternalDependency
from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo from ..interpreterbase.decorators import KwargInfo, ContainerTypeInfo
from ..mesonlib import (File, FileMode, MachineChoice, listify, has_path_sep, from ..mesonlib import (File, FileMode, MachineChoice, listify, has_path_sep,

@ -5,7 +5,7 @@ from __future__ import annotations
from .. import mesonlib, mparser from .. import mesonlib, mparser
from .exceptions import InterpreterException, InvalidArguments from .exceptions import InterpreterException, InvalidArguments
from ..coredata import UserOption from ..options import UserOption
import collections.abc import collections.abc

@ -14,6 +14,7 @@ import collections
from . import build from . import build
from . import coredata from . import coredata
from . import options
from . import environment from . import environment
from . import mesonlib from . import mesonlib
from . import mintro from . import mintro
@ -83,12 +84,12 @@ class Conf:
# if the option file has been updated, reload it # if the option file has been updated, reload it
# This cannot handle options for a new subproject that has not yet # This cannot handle options for a new subproject that has not yet
# been configured. # been configured.
for sub, options in self.coredata.options_files.items(): for sub, conf_options in self.coredata.options_files.items():
if options is not None and os.path.exists(options[0]): if conf_options is not None and os.path.exists(conf_options[0]):
opfile = options[0] opfile = conf_options[0]
with open(opfile, 'rb') as f: with open(opfile, 'rb') as f:
ophash = hashlib.sha1(f.read()).hexdigest() ophash = hashlib.sha1(f.read()).hexdigest()
if ophash != options[1]: if ophash != conf_options[1]:
oi = OptionInterpreter(sub) oi = OptionInterpreter(sub)
oi.process(opfile) oi.process(opfile)
self.coredata.update_project_options(oi.options, sub) self.coredata.update_project_options(oi.options, sub)
@ -223,18 +224,18 @@ class Conf:
self._add_line(mlog.normal_yellow(section + ':'), '', '', '') self._add_line(mlog.normal_yellow(section + ':'), '', '', '')
self.print_margin = 2 self.print_margin = 2
def print_options(self, title: str, options: 'coredata.KeyedOptionDictType') -> None: def print_options(self, title: str, opts: 'coredata.KeyedOptionDictType') -> None:
if not options: if not opts:
return return
if title: if title:
self.add_title(title) self.add_title(title)
auto = T.cast('coredata.UserFeatureOption', self.coredata.options[OptionKey('auto_features')]) auto = T.cast('options.UserFeatureOption', self.coredata.options[OptionKey('auto_features')])
for k, o in sorted(options.items()): for k, o in sorted(opts.items()):
printable_value = o.printable_value() printable_value = o.printable_value()
root = k.as_root() root = k.as_root()
if o.yielding and k.subproject and root in self.coredata.options: if o.yielding and k.subproject and root in self.coredata.options:
printable_value = '<inherited from main project>' printable_value = '<inherited from main project>'
if isinstance(o, coredata.UserFeatureOption) and o.is_auto(): if isinstance(o, options.UserFeatureOption) and o.is_auto():
printable_value = auto.printable_value() printable_value = auto.printable_value()
self.add_option(str(root), o.description, printable_value, o.choices) self.add_option(str(root), o.description, printable_value, o.choices)
@ -255,7 +256,7 @@ class Conf:
if not self.default_values_only: if not self.default_values_only:
mlog.log(' Build dir ', self.build_dir) mlog.log(' Build dir ', self.build_dir)
dir_option_names = set(coredata.BUILTIN_DIR_OPTIONS) dir_option_names = set(options.BUILTIN_DIR_OPTIONS)
test_option_names = {OptionKey('errorlogs'), test_option_names = {OptionKey('errorlogs'),
OptionKey('stdsplit')} OptionKey('stdsplit')}

@ -19,7 +19,7 @@ from pathlib import Path, PurePath
import sys import sys
import typing as T import typing as T
from . import build, mesonlib, coredata as cdata from . import build, mesonlib, options, coredata as cdata
from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstJSONPrinter from .ast import IntrospectionInterpreter, BUILD_TARGET_FUNCTIONS, AstConditionLevel, AstIDGenerator, AstIndentationGenerator, AstJSONPrinter
from .backend import backends from .backend import backends
from .dependencies import Dependency from .dependencies import Dependency
@ -88,7 +88,7 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
flag = '--' + key.replace('_', '-') flag = '--' + key.replace('_', '-')
parser.add_argument(flag, action='store_true', dest=key, default=False, help=val.desc) parser.add_argument(flag, action='store_true', dest=key, default=False, help=val.desc)
parser.add_argument('--backend', choices=sorted(cdata.backendlist), dest='backend', default='ninja', parser.add_argument('--backend', choices=sorted(options.backendlist), dest='backend', default='ninja',
help='The backend to use for the --buildoptions introspection.') help='The backend to use for the --buildoptions introspection.')
parser.add_argument('-a', '--all', action='store_true', dest='all', default=False, parser.add_argument('-a', '--all', action='store_true', dest='all', default=False,
help='Print all available information.') help='Print all available information.')
@ -284,7 +284,7 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s
optlist: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = [] optlist: T.List[T.Dict[str, T.Union[str, bool, int, T.List[str]]]] = []
subprojects = subprojects or [] subprojects = subprojects or []
dir_option_names = set(cdata.BUILTIN_DIR_OPTIONS) dir_option_names = set(options.BUILTIN_DIR_OPTIONS)
test_option_names = {OptionKey('errorlogs'), test_option_names = {OptionKey('errorlogs'),
OptionKey('stdsplit')} OptionKey('stdsplit')}
@ -302,20 +302,20 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s
for s in subprojects: for s in subprojects:
core_options[k.evolve(subproject=s)] = v core_options[k.evolve(subproject=s)] = v
def add_keys(options: 'cdata.KeyedOptionDictType', section: str) -> None: def add_keys(opts: 'cdata.KeyedOptionDictType', section: str) -> None:
for key, opt in sorted(options.items()): for key, opt in sorted(opts.items()):
optdict = {'name': str(key), 'value': opt.value, 'section': section, optdict = {'name': str(key), 'value': opt.value, 'section': section,
'machine': key.machine.get_lower_case_name() if coredata.is_per_machine_option(key) else 'any'} 'machine': key.machine.get_lower_case_name() if coredata.is_per_machine_option(key) else 'any'}
if isinstance(opt, cdata.UserStringOption): if isinstance(opt, options.UserStringOption):
typestr = 'string' typestr = 'string'
elif isinstance(opt, cdata.UserBooleanOption): elif isinstance(opt, options.UserBooleanOption):
typestr = 'boolean' typestr = 'boolean'
elif isinstance(opt, cdata.UserComboOption): elif isinstance(opt, options.UserComboOption):
optdict['choices'] = opt.choices optdict['choices'] = opt.choices
typestr = 'combo' typestr = 'combo'
elif isinstance(opt, cdata.UserIntegerOption): elif isinstance(opt, options.UserIntegerOption):
typestr = 'integer' typestr = 'integer'
elif isinstance(opt, cdata.UserArrayOption): elif isinstance(opt, options.UserArrayOption):
typestr = 'array' typestr = 'array'
if opt.choices: if opt.choices:
optdict['choices'] = opt.choices optdict['choices'] = opt.choices

@ -11,7 +11,7 @@ import xml.etree.ElementTree as ET
from . import ModuleReturnValue, ExtensionModule from . import ModuleReturnValue, ExtensionModule
from .. import build from .. import build
from .. import coredata from .. import options
from .. import mlog from .. import mlog
from ..dependencies import find_external_dependency, Dependency, ExternalLibrary, InternalDependency from ..dependencies import find_external_dependency, Dependency, ExternalLibrary, InternalDependency
from ..mesonlib import MesonException, File, version_compare, Popen_safe from ..mesonlib import MesonException, File, version_compare, Popen_safe
@ -256,7 +256,7 @@ class QtBaseModule(ExtensionModule):
@noPosargs @noPosargs
@typed_kwargs( @typed_kwargs(
'qt.has_tools', 'qt.has_tools',
KwargInfo('required', (bool, coredata.UserFeatureOption), default=False), KwargInfo('required', (bool, options.UserFeatureOption), default=False),
KwargInfo('method', str, default='auto'), KwargInfo('method', str, default='auto'),
) )
def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs') -> bool: def has_tools(self, state: 'ModuleState', args: T.Tuple, kwargs: 'HasToolKwArgs') -> bool:

@ -14,7 +14,7 @@ from .. import build
from .. import dependencies from .. import dependencies
from .. import mesonlib from .. import mesonlib
from .. import mlog from .. import mlog
from ..coredata import BUILTIN_DIR_OPTIONS from ..options import BUILTIN_DIR_OPTIONS
from ..dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface from ..dependencies.pkgconfig import PkgConfigDependency, PkgConfigInterface
from ..interpreter.type_checking import D_MODULE_VERSIONS_KW, INSTALL_DIR_KW, VARIABLES_KW, NoneType from ..interpreter.type_checking import D_MODULE_VERSIONS_KW, INSTALL_DIR_KW, VARIABLES_KW, NoneType
from ..interpreterbase import FeatureNew, FeatureDeprecated from ..interpreterbase import FeatureNew, FeatureDeprecated

@ -9,7 +9,7 @@ import typing as T
from . import ExtensionModule, ModuleInfo from . import ExtensionModule, ModuleInfo
from .. import mesonlib from .. import mesonlib
from .. import mlog from .. import mlog
from ..coredata import UserFeatureOption from ..options import UserFeatureOption
from ..build import known_shmod_kwargs, CustomTarget, CustomTargetIndex, BuildTarget, GeneratedList, StructuredSources, ExtractedObjects, SharedModule from ..build import known_shmod_kwargs, CustomTarget, CustomTargetIndex, BuildTarget, GeneratedList, StructuredSources, ExtractedObjects, SharedModule
from ..dependencies import NotFoundDependency from ..dependencies import NotFoundDependency
from ..dependencies.detect import get_dep_identifier, find_external_dependency from ..dependencies.detect import get_dep_identifier, find_external_dependency

@ -7,6 +7,7 @@ import re
import typing as T import typing as T
from . import coredata from . import coredata
from . import options
from . import mesonlib from . import mesonlib
from . import mparser from . import mparser
from . import mlog from . import mlog
@ -66,7 +67,7 @@ class OptionInterpreter:
def __init__(self, subproject: 'SubProject') -> None: def __init__(self, subproject: 'SubProject') -> None:
self.options: 'coredata.MutableKeyedOptionDictType' = {} self.options: 'coredata.MutableKeyedOptionDictType' = {}
self.subproject = subproject self.subproject = subproject
self.option_types: T.Dict[str, T.Callable[..., coredata.UserOption]] = { self.option_types: T.Dict[str, T.Callable[..., options.UserOption]] = {
'string': self.string_parser, 'string': self.string_parser,
'boolean': self.boolean_parser, 'boolean': self.boolean_parser,
'combo': self.combo_parser, 'combo': self.combo_parser,
@ -179,7 +180,7 @@ class OptionInterpreter:
since='0.60.0', since='0.60.0',
since_values={str: '0.63.0'}, since_values={str: '0.63.0'},
), ),
KwargInfo('yield', bool, default=coredata.DEFAULT_YIELDING, since='0.45.0'), KwargInfo('yield', bool, default=options.DEFAULT_YIELDING, since='0.45.0'),
allow_unknown=True, allow_unknown=True,
) )
@typed_pos_args('option', str) @typed_pos_args('option', str)
@ -208,8 +209,8 @@ class OptionInterpreter:
'string option', 'string option',
KwargInfo('value', str, default=''), KwargInfo('value', str, default=''),
) )
def string_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArgs) -> coredata.UserOption: def string_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArgs) -> options.UserOption:
return coredata.UserStringOption(name, description, kwargs['value'], *args) return options.UserStringOption(name, description, kwargs['value'], *args)
@typed_kwargs( @typed_kwargs(
'boolean option', 'boolean option',
@ -221,20 +222,20 @@ class OptionInterpreter:
deprecated_values={str: ('1.1.0', 'use a boolean, not a string')}, deprecated_values={str: ('1.1.0', 'use a boolean, not a string')},
), ),
) )
def boolean_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: BooleanArgs) -> coredata.UserOption: def boolean_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: BooleanArgs) -> options.UserOption:
return coredata.UserBooleanOption(name, description, kwargs['value'], *args) return options.UserBooleanOption(name, description, kwargs['value'], *args)
@typed_kwargs( @typed_kwargs(
'combo option', 'combo option',
KwargInfo('value', (str, NoneType)), KwargInfo('value', (str, NoneType)),
KwargInfo('choices', ContainerTypeInfo(list, str, allow_empty=False), required=True), KwargInfo('choices', ContainerTypeInfo(list, str, allow_empty=False), required=True),
) )
def combo_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: ComboArgs) -> coredata.UserOption: def combo_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: ComboArgs) -> options.UserOption:
choices = kwargs['choices'] choices = kwargs['choices']
value = kwargs['value'] value = kwargs['value']
if value is None: if value is None:
value = kwargs['choices'][0] value = kwargs['choices'][0]
return coredata.UserComboOption(name, description, choices, value, *args) return options.UserComboOption(name, description, choices, value, *args)
@typed_kwargs( @typed_kwargs(
'integer option', 'integer option',
@ -248,17 +249,17 @@ class OptionInterpreter:
KwargInfo('min', (int, NoneType)), KwargInfo('min', (int, NoneType)),
KwargInfo('max', (int, NoneType)), KwargInfo('max', (int, NoneType)),
) )
def integer_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: IntegerArgs) -> coredata.UserOption: def integer_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: IntegerArgs) -> options.UserOption:
value = kwargs['value'] value = kwargs['value']
inttuple = (kwargs['min'], kwargs['max'], value) inttuple = (kwargs['min'], kwargs['max'], value)
return coredata.UserIntegerOption(name, description, inttuple, *args) return options.UserIntegerOption(name, description, inttuple, *args)
@typed_kwargs( @typed_kwargs(
'string array option', 'string array option',
KwargInfo('value', (ContainerTypeInfo(list, str), str, NoneType)), KwargInfo('value', (ContainerTypeInfo(list, str), str, NoneType)),
KwargInfo('choices', ContainerTypeInfo(list, str), default=[]), KwargInfo('choices', ContainerTypeInfo(list, str), default=[]),
) )
def string_array_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArrayArgs) -> coredata.UserOption: def string_array_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArrayArgs) -> options.UserOption:
choices = kwargs['choices'] choices = kwargs['choices']
value = kwargs['value'] if kwargs['value'] is not None else choices value = kwargs['value'] if kwargs['value'] is not None else choices
if isinstance(value, str): if isinstance(value, str):
@ -266,14 +267,14 @@ class OptionInterpreter:
FeatureDeprecated('String value for array option', '1.3.0').use(self.subproject) FeatureDeprecated('String value for array option', '1.3.0').use(self.subproject)
else: else:
raise mesonlib.MesonException('Value does not define an array: ' + value) raise mesonlib.MesonException('Value does not define an array: ' + value)
return coredata.UserArrayOption(name, description, value, return options.UserArrayOption(name, description, value,
choices=choices, choices=choices,
yielding=args[0], yielding=args[0],
deprecated=args[1]) deprecated=args[1])
@typed_kwargs( @typed_kwargs(
'feature option', 'feature option',
KwargInfo('value', str, default='auto', validator=in_set_validator({'auto', 'enabled', 'disabled'})), KwargInfo('value', str, default='auto', validator=in_set_validator({'auto', 'enabled', 'disabled'})),
) )
def feature_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: FeatureArgs) -> coredata.UserOption: def feature_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: FeatureArgs) -> options.UserOption:
return coredata.UserFeatureOption(name, description, kwargs['value'], *args) return options.UserFeatureOption(name, description, kwargs['value'], *args)

@ -0,0 +1,480 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright 2013-2024 Contributors to the The Meson project
from collections import OrderedDict
from itertools import chain
import argparse
from .mesonlib import (
HoldableObject,
OptionKey,
default_prefix,
default_datadir,
default_includedir,
default_infodir,
default_libdir,
default_libexecdir,
default_localedir,
default_mandir,
default_sbindir,
default_sysconfdir,
MesonException,
listify_array_value,
)
from . import mlog
import typing as T
DEFAULT_YIELDING = False
# Can't bind this near the class method it seems, sadly.
_T = T.TypeVar('_T')
backendlist = ['ninja', 'vs', 'vs2010', 'vs2012', 'vs2013', 'vs2015', 'vs2017', 'vs2019', 'vs2022', 'xcode', 'none']
genvslitelist = ['vs2022']
buildtypelist = ['plain', 'debug', 'debugoptimized', 'release', 'minsize', 'custom']
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
_U = T.TypeVar('_U', bound=UserOption[_T])
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}')
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
@staticmethod
def argparse_name_to_arg(name: str) -> str:
if name == 'warning_level':
return '--warnlevel'
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
def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffix: str) -> None:
kwargs = OrderedDict()
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'): {},
}
class OptionStore:
def __init__(self):
# This class will hold all options for a given build directory
self.dummy = None

@ -41,7 +41,8 @@ from mesonbuild.compilers import compiler_from_language
from mesonbuild.build import ConfigurationData from mesonbuild.build import ConfigurationData
from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof, setup_vsenv from mesonbuild.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof, setup_vsenv
from mesonbuild.mlog import blue, bold, cyan, green, red, yellow, normal_green from mesonbuild.mlog import blue, bold, cyan, green, red, yellow, normal_green
from mesonbuild.coredata import backendlist, version as meson_version from mesonbuild.coredata import version as meson_version
from mesonbuild.options import backendlist
from mesonbuild.modules.python import PythonExternalProgram from mesonbuild.modules.python import PythonExternalProgram
from run_tests import ( from run_tests import (
get_fake_options, run_configure, get_meson_script, get_backend_commands, get_fake_options, run_configure, get_meson_script, get_backend_commands,

@ -33,7 +33,8 @@ from mesonbuild import mesonmain
from mesonbuild import mtest from mesonbuild import mtest
from mesonbuild import mlog from mesonbuild import mlog
from mesonbuild.environment import Environment, detect_ninja, detect_machine_info from mesonbuild.environment import Environment, detect_ninja, detect_machine_info
from mesonbuild.coredata import backendlist, version as meson_version from mesonbuild.coredata import version as meson_version
from mesonbuild.options import backendlist
from mesonbuild.mesonlib import OptionKey, setup_vsenv from mesonbuild.mesonlib import OptionKey, setup_vsenv
if T.TYPE_CHECKING: if T.TYPE_CHECKING:

@ -225,6 +225,7 @@
"mesonbuild.mparser", "mesonbuild.mparser",
"mesonbuild.msetup", "mesonbuild.msetup",
"mesonbuild.optinterpreter", "mesonbuild.optinterpreter",
"mesonbuild.options",
"mesonbuild.programs", "mesonbuild.programs",
"mesonbuild.scripts", "mesonbuild.scripts",
"mesonbuild.scripts.meson_exe", "mesonbuild.scripts.meson_exe",
@ -237,6 +238,6 @@
"mesonbuild.wrap", "mesonbuild.wrap",
"mesonbuild.wrap.wrap" "mesonbuild.wrap.wrap"
], ],
"count": 68 "count": 69
} }
} }

@ -14,6 +14,7 @@ import mesonbuild.dependencies.factory
import mesonbuild.envconfig import mesonbuild.envconfig
import mesonbuild.environment import mesonbuild.environment
import mesonbuild.coredata import mesonbuild.coredata
import mesonbuild.options
import mesonbuild.modules.gnome import mesonbuild.modules.gnome
from mesonbuild.interpreter import Interpreter from mesonbuild.interpreter import Interpreter
from mesonbuild.ast import AstInterpreter from mesonbuild.ast import AstInterpreter
@ -139,8 +140,8 @@ class DataTests(unittest.TestCase):
found_entries |= options found_entries |= options
self.assertEqual(found_entries, { self.assertEqual(found_entries, {
*(str(k.evolve(module=None)) for k in mesonbuild.coredata.BUILTIN_OPTIONS), *(str(k.evolve(module=None)) for k in mesonbuild.options.BUILTIN_OPTIONS),
*(str(k.evolve(module=None)) for k in mesonbuild.coredata.BUILTIN_OPTIONS_PER_MACHINE), *(str(k.evolve(module=None)) for k in mesonbuild.options.BUILTIN_OPTIONS_PER_MACHINE),
}) })
# Check that `buildtype` table inside `Core options` matches how # Check that `buildtype` table inside `Core options` matches how

@ -274,7 +274,7 @@ class PlatformAgnosticTests(BasePlatformTests):
expected = json.load(f)['meson']['modules'] expected = json.load(f)['meson']['modules']
self.assertEqual(data['modules'], expected) self.assertEqual(data['modules'], expected)
self.assertEqual(data['count'], 68) self.assertEqual(data['count'], 69)
def test_meson_package_cache_dir(self): def test_meson_package_cache_dir(self):
# Copy testdir into temporary directory to not pollute meson source tree. # Copy testdir into temporary directory to not pollute meson source tree.

Loading…
Cancel
Save