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 typing as T
from .. import compilers, environment, mesonlib, optinterpreter
from .. import compilers, environment, mesonlib, optinterpreter, options
from .. import coredata as cdata
from ..build import Executable, Jar, SharedLibrary, SharedModule, StaticLibrary
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:
kwargs = self.flatten_kwargs(kwargs)
required = kwargs.get('required', True)
assert isinstance(required, (bool, cdata.UserFeatureOption)), 'for mypy'
if isinstance(required, cdata.UserFeatureOption):
assert isinstance(required, (bool, options.UserFeatureOption)), 'for mypy'
if isinstance(required, options.UserFeatureOption):
required = required.is_enabled()
if 'native' in kwargs:
native = kwargs.get('native', False)

@ -23,7 +23,7 @@ import typing as T
from . import builder
from . import version
from ..mesonlib import MesonException, Popen_safe, OptionKey
from .. import coredata
from .. import coredata, options
if T.TYPE_CHECKING:
from types import ModuleType
@ -712,11 +712,11 @@ def interpret(subp_name: str, subdir: str, env: Environment) -> T.Tuple[mparser.
build = builder.Builder(filename)
# Generate project options
options: T.Dict[OptionKey, coredata.UserOption] = {}
project_options: T.Dict[OptionKey, options.UserOption] = {}
for feature in cargo.features:
key = OptionKey(_option_name(feature), subproject=subp_name)
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 += [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:
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 typing as T
from .. import coredata
from .. import options
from .. import mlog
from ..mesonlib import MesonException, version_compare, OptionKey
from .c_function_attributes import C_FUNC_ATTRIBUTES
@ -96,7 +96,7 @@ class CCompiler(CLikeCompiler, Compiler):
opts = super().get_options()
key = OptionKey('std', machine=self.for_machine, lang=self.language)
opts.update({
key: coredata.UserStdOption('C', _ALL_STDS),
key: options.UserStdOption('C', _ALL_STDS),
})
return opts
@ -128,7 +128,7 @@ class _ClangCStds(CompilerMixinBase):
if version_compare(self.version, self._C23_VERSION):
stds += ['c23']
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)
return opts
@ -154,7 +154,7 @@ class ClangCCompiler(_ClangCStds, ClangCompiler, CCompiler):
if self.info.is_windows() or self.info.is_cygwin():
self.update_options(
opts,
self.create_option(coredata.UserArrayOption,
self.create_option(options.UserArrayOption,
OptionKey('winlibs', machine=self.for_machine, lang=self.language),
'Standard Win libraries to link against',
gnu_winlibs),
@ -247,7 +247,7 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
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)
return opts
@ -298,12 +298,12 @@ class GnuCCompiler(GnuCompiler, CCompiler):
stds += ['c23']
key = OptionKey('std', machine=self.for_machine, lang=self.language)
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)
if self.info.is_windows() or self.info.is_cygwin():
self.update_options(
opts,
self.create_option(coredata.UserArrayOption,
self.create_option(options.UserArrayOption,
key.evolve('winlibs'),
'Standard Win libraries to link against',
gnu_winlibs),
@ -377,7 +377,7 @@ class ElbrusCCompiler(ElbrusCompiler, CCompiler):
if version_compare(self.version, '>=1.26.00'):
stds += ['c17', 'c18', 'iso9899:2017', 'iso9899:2018', 'gnu17', 'gnu18']
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)
return opts
@ -416,7 +416,7 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler):
if version_compare(self.version, '>=16.0.0'):
stds += ['c11']
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)
return opts
@ -441,7 +441,7 @@ class VisualStudioLikeCCompilerMixin(CompilerMixinBase):
return self.update_options(
super().get_options(),
self.create_option(
coredata.UserArrayOption,
options.UserArrayOption,
OptionKey('winlibs', machine=self.for_machine, lang=self.language),
'Windows libs to link against.',
msvc_winlibs,
@ -480,7 +480,7 @@ class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompi
if version_compare(self.version, self._C17_VERSION):
stds += ['c17', 'c18']
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)
return opts
@ -529,7 +529,7 @@ class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerM
def get_options(self) -> 'MutableKeyedOptionDictType':
opts = super().get_options()
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'])
return opts
@ -562,7 +562,7 @@ class ArmCCompiler(ArmCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
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'])
return opts
@ -591,7 +591,7 @@ class CcrxCCompiler(CcrxCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
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'])
return opts
@ -638,7 +638,7 @@ class Xc16CCompiler(Xc16Compiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
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)
return opts
@ -683,7 +683,7 @@ class CompCertCCompiler(CompCertCompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
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'])
return opts
@ -720,7 +720,7 @@ class TICCompiler(TICompiler, CCompiler):
def get_options(self) -> 'MutableKeyedOptionDictType':
opts = CCompiler.get_options(self)
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'])
return opts

@ -15,6 +15,7 @@ from functools import lru_cache
from .. import coredata
from .. import mlog
from .. import mesonlib
from .. import options
from ..mesonlib import (
HoldableObject,
EnvironmentException, MesonException,
@ -35,7 +36,7 @@ if T.TYPE_CHECKING:
CompilerType = T.TypeVar('CompilerType', bound='Compiler')
_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
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']
@dataclass
class BaseOption(T.Generic[coredata._T, coredata._U]):
opt_type: T.Type[coredata._U]
class BaseOption(T.Generic[options._T, options._U]):
opt_type: T.Type[options._U]
description: str
default: 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}
if self.choices:
keywords['choices'] = self.choices
return self.opt_type(name.name, self.description, **keywords)
BASE_OPTIONS: T.Mapping[OptionKey, BaseOption] = {
OptionKey('b_pch'): BaseOption(coredata.UserBooleanOption, 'Use precompiled headers', True),
OptionKey('b_lto'): BaseOption(coredata.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_mode'): BaseOption(coredata.UserComboOption, 'Select between different LTO modes.', 'default',
OptionKey('b_pch'): BaseOption(options.UserBooleanOption, 'Use precompiled headers', True),
OptionKey('b_lto'): BaseOption(options.UserBooleanOption, 'Use link time optimization', False),
OptionKey('b_lto_threads'): BaseOption(options.UserIntegerOption, 'Use multiple threads for Link Time Optimization', (None, None, 0)),
OptionKey('b_lto_mode'): BaseOption(options.UserComboOption, 'Select between different LTO modes.', 'default',
choices=['default', 'thin']),
OptionKey('b_thinlto_cache'): BaseOption(coredata.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_sanitize'): BaseOption(coredata.UserComboOption, 'Code sanitizer to use', 'none',
OptionKey('b_thinlto_cache'): BaseOption(options.UserBooleanOption, 'Use LLVM ThinLTO caching for faster incremental builds', False),
OptionKey('b_thinlto_cache_dir'): BaseOption(options.UserStringOption, 'Directory to store ThinLTO cache objects', ''),
OptionKey('b_sanitize'): BaseOption(options.UserComboOption, 'Code sanitizer to use', 'none',
choices=['none', 'address', 'thread', 'undefined', 'memory', 'leak', 'address,undefined']),
OptionKey('b_lundef'): BaseOption(coredata.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True),
OptionKey('b_asneeded'): BaseOption(coredata.UserBooleanOption, 'Use -Wl,--as-needed when linking', True),
OptionKey('b_pgo'): BaseOption(coredata.UserComboOption, 'Use profile guided optimization', 'off',
OptionKey('b_lundef'): BaseOption(options.UserBooleanOption, 'Use -Wl,--no-undefined when linking', True),
OptionKey('b_asneeded'): BaseOption(options.UserBooleanOption, 'Use -Wl,--as-needed when linking', True),
OptionKey('b_pgo'): BaseOption(options.UserComboOption, 'Use profile guided optimization', 'off',
choices=['off', 'generate', 'use']),
OptionKey('b_coverage'): BaseOption(coredata.UserBooleanOption, 'Enable coverage tracking.', False),
OptionKey('b_colorout'): BaseOption(coredata.UserComboOption, 'Use colored output', 'always',
OptionKey('b_coverage'): BaseOption(options.UserBooleanOption, 'Enable coverage tracking.', False),
OptionKey('b_colorout'): BaseOption(options.UserComboOption, 'Use colored output', 'always',
choices=['auto', 'always', 'never']),
OptionKey('b_ndebug'): BaseOption(coredata.UserComboOption, 'Disable asserts', 'false', choices=['true', 'false', 'if-release']),
OptionKey('b_staticpic'): BaseOption(coredata.UserBooleanOption, 'Build static libraries as position independent', True),
OptionKey('b_pie'): BaseOption(coredata.UserBooleanOption, 'Build executables as position independent', False),
OptionKey('b_bitcode'): BaseOption(coredata.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_ndebug'): BaseOption(options.UserComboOption, 'Disable asserts', 'false', choices=['true', 'false', 'if-release']),
OptionKey('b_staticpic'): BaseOption(options.UserBooleanOption, 'Build static libraries as position independent', True),
OptionKey('b_pie'): BaseOption(options.UserBooleanOption, 'Build executables as position independent', False),
OptionKey('b_bitcode'): BaseOption(options.UserBooleanOption, 'Generate and embed bitcode (only macOS/iOS/tvOS)', False),
OptionKey('b_vscrt'): BaseOption(options.UserComboOption, 'VS run-time library type to use.', '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, [])
link_options = env.options.get(largkey, [])
cargs = coredata.UserArrayOption(
cargs = options.UserArrayOption(
f'{lang}_{argkey.name}',
description + ' compiler',
comp_options, split_args=True, allow_dups=True)
largs = coredata.UserArrayOption(
largs = options.UserArrayOption(
f'{lang}_{largkey.name}',
description + ' linker',
link_options, split_args=True, allow_dups=True)

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

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

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

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

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

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

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

@ -9,7 +9,7 @@ import textwrap
import re
import typing as T
from .. import coredata
from .. import options
from ..mesonlib import EnvironmentException, MesonException, Popen_safe_logged, OptionKey
from .compilers import Compiler, clike_debug_args
@ -158,7 +158,7 @@ class RustCompiler(Compiler):
# use_linker_args method instead.
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),
'Rust edition to use',
['none', '2015', '2018', '2021'],

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

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

@ -11,6 +11,7 @@ from .. import environment
from .. import coredata
from .. import dependencies
from .. import mlog
from .. import options
from .. import build
from .. import optinterpreter
from .. import compilers
@ -163,7 +164,7 @@ class Summary:
elif isinstance(i, Disabler):
FeatureNew.single_use('disabler in summary', '0.64.0', subproject)
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)
formatted_values.append(i.printable_value())
else:
@ -450,7 +451,7 @@ class Interpreter(InterpreterBase, HoldableObject):
build.StructuredSources: OBJ.StructuredSourcesHolder,
compilers.RunResult: compilerOBJ.TryRunResultHolder,
dependencies.ExternalLibrary: OBJ.ExternalLibraryHolder,
coredata.UserFeatureOption: OBJ.FeatureOptionHolder,
options.UserFeatureOption: OBJ.FeatureOptionHolder,
envconfig.MachineInfo: OBJ.MachineHolder,
build.ConfigurationData: OBJ.ConfigurationDataHolder,
})
@ -1047,7 +1048,7 @@ class Interpreter(InterpreterBase, HoldableObject):
# FIXME: Are there other files used by cargo interpreter?
[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)
if not key.is_project():
@ -1056,7 +1057,7 @@ class Interpreter(InterpreterBase, HoldableObject):
if v is None or v.yielding:
v = opts.get(key.as_root())
if v is not None:
assert isinstance(v, coredata.UserOption), 'for mypy'
assert isinstance(v, options.UserOption), 'for mypy'
return v
try:
@ -1085,7 +1086,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@typed_pos_args('get_option', str)
@noKwargs
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]
if ':' in optname:
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}')
opt = self.get_option_internal(optname)
if isinstance(opt, coredata.UserFeatureOption):
if isinstance(opt, options.UserFeatureOption):
opt.name = optname
return opt
elif isinstance(opt, coredata.UserOption):
elif isinstance(opt, options.UserOption):
if isinstance(opt.value, str):
return P_OBJ.OptionString(opt.value, f'{{{optname}}}')
return opt.value

@ -8,7 +8,7 @@ import textwrap
from pathlib import Path, PurePath
from .. import mesonlib
from .. import coredata
from .. import options
from .. import build
from .. import mlog
@ -52,7 +52,7 @@ def extract_required_kwarg(kwargs: 'kwargs.ExtractRequired',
disabled = False
required = False
feature: T.Optional[str] = None
if isinstance(val, coredata.UserFeatureOption):
if isinstance(val, options.UserFeatureOption):
if not feature_check:
feature_check = FeatureNew('User option "feature"', '0.47.0')
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.')
return [str(s) for s in search_dirs]
class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
def __init__(self, option: coredata.UserFeatureOption, interpreter: 'Interpreter'):
class FeatureOptionHolder(ObjectHolder[options.UserFeatureOption]):
def __init__(self, option: options.UserFeatureOption, interpreter: 'Interpreter'):
super().__init__(option, interpreter)
if option and option.is_auto():
# 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.name = option.name
self.methods.update({'enabled': self.enabled_method,
@ -108,12 +108,12 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
def value(self) -> str:
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.value = 'disabled'
return disabled
def as_enabled(self) -> coredata.UserFeatureOption:
def as_enabled(self) -> options.UserFeatureOption:
enabled = copy.deepcopy(self.held_object)
enabled.value = '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:
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:
return copy.deepcopy(self.held_object)
@ -156,7 +156,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
'feature_option.require',
_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'])
@FeatureNew('feature_option.disable_if()', '1.1.0')
@ -165,7 +165,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
'feature_option.disable_if',
_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'])
@FeatureNew('feature_option.enable_if()', '1.1.0')
@ -174,7 +174,7 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
'feature_option.enable_if',
_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]:
return copy.deepcopy(self.held_object)
@ -188,13 +188,13 @@ class FeatureOptionHolder(ObjectHolder[coredata.UserFeatureOption]):
@FeatureNew('feature_option.disable_auto_if()', '0.59.0')
@noKwargs
@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()
@FeatureNew('feature_option.enable_auto_if()', '1.1.0')
@noKwargs
@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)

@ -10,7 +10,7 @@ import typing as T
from typing_extensions import TypedDict, Literal, Protocol, NotRequired
from .. import build
from .. import coredata
from .. import options
from ..compilers import Compiler
from ..dependencies.base import Dependency
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.
"""
required: T.Union[bool, coredata.UserFeatureOption]
required: T.Union[bool, options.UserFeatureOption]
class ExtractSearchDirs(TypedDict):

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

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

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

@ -19,7 +19,7 @@ from pathlib import Path, PurePath
import sys
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 .backend import backends
from .dependencies import Dependency
@ -88,7 +88,7 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
flag = '--' + key.replace('_', '-')
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.')
parser.add_argument('-a', '--all', action='store_true', dest='all', default=False,
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]]]] = []
subprojects = subprojects or []
dir_option_names = set(cdata.BUILTIN_DIR_OPTIONS)
dir_option_names = set(options.BUILTIN_DIR_OPTIONS)
test_option_names = {OptionKey('errorlogs'),
OptionKey('stdsplit')}
@ -302,20 +302,20 @@ def list_buildoptions(coredata: cdata.CoreData, subprojects: T.Optional[T.List[s
for s in subprojects:
core_options[k.evolve(subproject=s)] = v
def add_keys(options: 'cdata.KeyedOptionDictType', section: str) -> None:
for key, opt in sorted(options.items()):
def add_keys(opts: 'cdata.KeyedOptionDictType', section: str) -> None:
for key, opt in sorted(opts.items()):
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'}
if isinstance(opt, cdata.UserStringOption):
if isinstance(opt, options.UserStringOption):
typestr = 'string'
elif isinstance(opt, cdata.UserBooleanOption):
elif isinstance(opt, options.UserBooleanOption):
typestr = 'boolean'
elif isinstance(opt, cdata.UserComboOption):
elif isinstance(opt, options.UserComboOption):
optdict['choices'] = opt.choices
typestr = 'combo'
elif isinstance(opt, cdata.UserIntegerOption):
elif isinstance(opt, options.UserIntegerOption):
typestr = 'integer'
elif isinstance(opt, cdata.UserArrayOption):
elif isinstance(opt, options.UserArrayOption):
typestr = 'array'
if opt.choices:
optdict['choices'] = opt.choices

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

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

@ -9,7 +9,7 @@ import typing as T
from . import ExtensionModule, ModuleInfo
from .. import mesonlib
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 ..dependencies import NotFoundDependency
from ..dependencies.detect import get_dep_identifier, find_external_dependency

@ -7,6 +7,7 @@ import re
import typing as T
from . import coredata
from . import options
from . import mesonlib
from . import mparser
from . import mlog
@ -66,7 +67,7 @@ class OptionInterpreter:
def __init__(self, subproject: 'SubProject') -> None:
self.options: 'coredata.MutableKeyedOptionDictType' = {}
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,
'boolean': self.boolean_parser,
'combo': self.combo_parser,
@ -179,7 +180,7 @@ class OptionInterpreter:
since='0.60.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,
)
@typed_pos_args('option', str)
@ -208,8 +209,8 @@ class OptionInterpreter:
'string option',
KwargInfo('value', str, default=''),
)
def string_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArgs) -> coredata.UserOption:
return coredata.UserStringOption(name, description, kwargs['value'], *args)
def string_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: StringArgs) -> options.UserOption:
return options.UserStringOption(name, description, kwargs['value'], *args)
@typed_kwargs(
'boolean option',
@ -221,20 +222,20 @@ class OptionInterpreter:
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:
return coredata.UserBooleanOption(name, description, kwargs['value'], *args)
def boolean_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: BooleanArgs) -> options.UserOption:
return options.UserBooleanOption(name, description, kwargs['value'], *args)
@typed_kwargs(
'combo option',
KwargInfo('value', (str, NoneType)),
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']
value = kwargs['value']
if value is None:
value = kwargs['choices'][0]
return coredata.UserComboOption(name, description, choices, value, *args)
return options.UserComboOption(name, description, choices, value, *args)
@typed_kwargs(
'integer option',
@ -248,17 +249,17 @@ class OptionInterpreter:
KwargInfo('min', (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']
inttuple = (kwargs['min'], kwargs['max'], value)
return coredata.UserIntegerOption(name, description, inttuple, *args)
return options.UserIntegerOption(name, description, inttuple, *args)
@typed_kwargs(
'string array option',
KwargInfo('value', (ContainerTypeInfo(list, str), str, NoneType)),
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']
value = kwargs['value'] if kwargs['value'] is not None else choices
if isinstance(value, str):
@ -266,14 +267,14 @@ class OptionInterpreter:
FeatureDeprecated('String value for array option', '1.3.0').use(self.subproject)
else:
raise mesonlib.MesonException('Value does not define an array: ' + value)
return coredata.UserArrayOption(name, description, value,
choices=choices,
yielding=args[0],
deprecated=args[1])
return options.UserArrayOption(name, description, value,
choices=choices,
yielding=args[0],
deprecated=args[1])
@typed_kwargs(
'feature option',
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:
return coredata.UserFeatureOption(name, description, kwargs['value'], *args)
def feature_parser(self, name: str, description: str, args: T.Tuple[bool, _DEPRECATED_ARGS], kwargs: FeatureArgs) -> options.UserOption:
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.mesonlib import MachineChoice, Popen_safe, TemporaryDirectoryWinProof, setup_vsenv
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 run_tests import (
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 mlog
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
if T.TYPE_CHECKING:

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

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

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

Loading…
Cancel
Save