UserOption no longer has a name field.

This avoids the duplication where the option is stored in a dict at its
name, and also contains its own name. In general, the maxim in
programming is things shouldn't know their own name, so removed the name
field just leaving the option's position in the dictionary as its name.
pull/4910/head
John Ericson 6 years ago committed by Jussi Pakkanen
parent 7b8ef78bc0
commit 4030e7cb7a
  1. 5
      mesonbuild/backend/backends.py
  2. 19
      mesonbuild/compilers/c.py
  3. 33
      mesonbuild/compilers/compilers.py
  4. 44
      mesonbuild/compilers/cpp.py
  5. 90
      mesonbuild/coredata.py
  6. 6
      mesonbuild/interpreter.py
  7. 4
      mesonbuild/mintro.py
  8. 34
      mesonbuild/optinterpreter.py

@ -103,8 +103,7 @@ class TestSerialisation:
self.protocol = protocol self.protocol = protocol
class OptionProxy: class OptionProxy:
def __init__(self, name, value): def __init__(self, value):
self.name = name
self.value = value self.value = value
class OptionOverrideProxy: class OptionOverrideProxy:
@ -122,7 +121,7 @@ class OptionOverrideProxy:
def _get_override(self, option_name, base_opt): def _get_override(self, option_name, base_opt):
if option_name in self.overrides: if option_name in self.overrides:
return OptionProxy(base_opt.name, base_opt.validate_value(self.overrides[option_name])) return OptionProxy(base_opt.validate_value(self.overrides[option_name]))
return base_opt return base_opt
def get_backend_from_name(backend, build): def get_backend_from_name(backend, build):

@ -96,7 +96,7 @@ class ClangCCompiler(ClangCompiler, CCompiler):
if version_compare(self.version, v): if version_compare(self.version, v):
c_stds += ['c17'] c_stds += ['c17']
g_stds += ['gnu17'] g_stds += ['gnu17']
opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none'] + c_stds + g_stds, ['none'] + c_stds + g_stds,
'none')}) 'none')})
return opts return opts
@ -130,7 +130,7 @@ class ArmclangCCompiler(ArmclangCompiler, CCompiler):
def get_options(self): def get_options(self):
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none', 'c90', 'c99', 'c11', ['none', 'c90', 'c99', 'c11',
'gnu90', 'gnu99', 'gnu11'], 'gnu90', 'gnu99', 'gnu11'],
'none')}) 'none')})
@ -165,12 +165,12 @@ class GnuCCompiler(GnuCompiler, CCompiler):
if version_compare(self.version, v): if version_compare(self.version, v):
c_stds += ['c17', 'c18'] c_stds += ['c17', 'c18']
g_stds += ['gnu17', 'gnu18'] g_stds += ['gnu17', 'gnu18']
opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none'] + c_stds + g_stds, ['none'] + c_stds + g_stds,
'none')}) 'none')})
if self.compiler_type.is_windows_compiler: if self.compiler_type.is_windows_compiler:
opts.update({ opts.update({
'c_winlibs': coredata.UserArrayOption('c_winlibs', 'Standard Win libraries to link against', 'c_winlibs': coredata.UserArrayOption('Standard Win libraries to link against',
gnu_winlibs), }) gnu_winlibs), })
return opts return opts
@ -204,7 +204,7 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler):
# It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports. # It does support some various ISO standards and c/gnu 90, 9x, 1x in addition to those which GNU CC supports.
def get_options(self): def get_options(self):
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none', 'c89', 'c90', 'c9x', 'c99', 'c1x', 'c11', ['none', 'c89', 'c90', 'c9x', 'c99', 'c1x', 'c11',
'gnu89', 'gnu90', 'gnu9x', 'gnu99', 'gnu1x', 'gnu11', 'gnu89', 'gnu90', 'gnu9x', 'gnu99', 'gnu1x', 'gnu11',
'iso9899:2011', 'iso9899:1990', 'iso9899:199409', 'iso9899:1999'], 'iso9899:2011', 'iso9899:1990', 'iso9899:199409', 'iso9899:1999'],
@ -239,7 +239,7 @@ class IntelCCompiler(IntelGnuLikeCompiler, CCompiler):
g_stds = ['gnu89', 'gnu99'] g_stds = ['gnu89', 'gnu99']
if version_compare(self.version, '>=16.0.0'): if version_compare(self.version, '>=16.0.0'):
c_stds += ['c11'] c_stds += ['c11']
opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none'] + c_stds + g_stds, ['none'] + c_stds + g_stds,
'none')}) 'none')})
return opts return opts
@ -258,8 +258,7 @@ class VisualStudioLikeCCompilerMixin:
def get_options(self): def get_options(self):
opts = super().get_options() opts = super().get_options()
opts.update({'c_winlibs': coredata.UserArrayOption('c_winlibs', opts.update({'c_winlibs': coredata.UserArrayOption('Windows libs to link against.',
'Windows libs to link against.',
msvc_winlibs)}) msvc_winlibs)})
return opts return opts
@ -317,7 +316,7 @@ class ArmCCompiler(ArmCompiler, CCompiler):
def get_options(self): def get_options(self):
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none', 'c90', 'c99'], ['none', 'c90', 'c99'],
'none')}) 'none')})
return opts return opts
@ -340,7 +339,7 @@ class CcrxCCompiler(CcrxCompiler, CCompiler):
def get_options(self): def get_options(self):
opts = CCompiler.get_options(self) opts = CCompiler.get_options(self)
opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', opts.update({'c_std': coredata.UserComboOption('C language standard to use',
['none', 'c89', 'c99'], ['none', 'c89', 'c99'],
'none')}) 'none')})
return opts return opts

@ -381,35 +381,30 @@ msvc_debug_args = {False: [],
ccrx_debug_args = {False: [], ccrx_debug_args = {False: [],
True: ['-debug']} True: ['-debug']}
base_options = {'b_pch': coredata.UserBooleanOption('b_pch', 'Use precompiled headers', True), base_options = {'b_pch': coredata.UserBooleanOption('Use precompiled headers', True),
'b_lto': coredata.UserBooleanOption('b_lto', 'Use link time optimization', False), 'b_lto': coredata.UserBooleanOption('Use link time optimization', False),
'b_sanitize': coredata.UserComboOption('b_sanitize', 'b_sanitize': coredata.UserComboOption('Code sanitizer to use',
'Code sanitizer to use',
['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'], ['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'],
'none'), 'none'),
'b_lundef': coredata.UserBooleanOption('b_lundef', 'Use -Wl,--no-undefined when linking', True), 'b_lundef': coredata.UserBooleanOption('Use -Wl,--no-undefined when linking', True),
'b_asneeded': coredata.UserBooleanOption('b_asneeded', 'Use -Wl,--as-needed when linking', True), 'b_asneeded': coredata.UserBooleanOption('Use -Wl,--as-needed when linking', True),
'b_pgo': coredata.UserComboOption('b_pgo', 'Use profile guided optimization', 'b_pgo': coredata.UserComboOption('Use profile guided optimization',
['off', 'generate', 'use'], ['off', 'generate', 'use'],
'off'), 'off'),
'b_coverage': coredata.UserBooleanOption('b_coverage', 'b_coverage': coredata.UserBooleanOption('Enable coverage tracking.',
'Enable coverage tracking.',
False), False),
'b_colorout': coredata.UserComboOption('b_colorout', 'Use colored output', 'b_colorout': coredata.UserComboOption('Use colored output',
['auto', 'always', 'never'], ['auto', 'always', 'never'],
'always'), 'always'),
'b_ndebug': coredata.UserComboOption('b_ndebug', 'Disable asserts', 'b_ndebug': coredata.UserComboOption('Disable asserts',
['true', 'false', 'if-release'], 'false'), ['true', 'false', 'if-release'], 'false'),
'b_staticpic': coredata.UserBooleanOption('b_staticpic', 'b_staticpic': coredata.UserBooleanOption('Build static libraries as position independent',
'Build static libraries as position independent',
True), True),
'b_pie': coredata.UserBooleanOption('b_pie', 'b_pie': coredata.UserBooleanOption('Build executables as position independent',
'Build executables as position independent',
False), False),
'b_bitcode': coredata.UserBooleanOption('b_bitcode', 'b_bitcode': coredata.UserBooleanOption('Generate and embed bitcode (only macOS and iOS)',
'Generate and embed bitcode (only macOS and iOS)',
False), False),
'b_vscrt': coredata.UserComboOption('b_vscrt', 'VS run-time library type to use.', 'b_vscrt': coredata.UserComboOption('VS run-time library type to use.',
['none', 'md', 'mdd', 'mt', 'mtd', 'from_buildtype'], ['none', 'md', 'mdd', 'mt', 'mtd', 'from_buildtype'],
'from_buildtype'), 'from_buildtype'),
} }
@ -1044,11 +1039,9 @@ class Compiler:
description = 'Extra arguments passed to the {}'.format(self.get_display_language()) description = 'Extra arguments passed to the {}'.format(self.get_display_language())
opts.update({ opts.update({
self.language + '_args': coredata.UserArrayOption( self.language + '_args': coredata.UserArrayOption(
self.language + '_args',
description + ' compiler', description + ' compiler',
[], shlex_split=True, user_input=True, allow_dups=True), [], shlex_split=True, user_input=True, allow_dups=True),
self.language + '_link_args': coredata.UserArrayOption( self.language + '_link_args': coredata.UserArrayOption(
self.language + '_link_args',
description + ' linker', description + ' linker',
[], shlex_split=True, user_input=True, allow_dups=True), [], shlex_split=True, user_input=True, allow_dups=True),
}) })

@ -158,11 +158,10 @@ class ClangCPPCompiler(ClangCompiler, CPPCompiler):
def get_options(self): def get_options(self):
opts = CPPCompiler.get_options(self) opts = CPPCompiler.get_options(self)
opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.',
'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', 'cpp_std': coredata.UserComboOption('C++ language standard to use',
['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a',
'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'],
'none')}) 'none')})
@ -201,7 +200,7 @@ class ArmclangCPPCompiler(ArmclangCompiler, CPPCompiler):
'C++ exception handling type.', 'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', 'cpp_std': coredata.UserComboOption('C++ language standard to use',
['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17',
'gnu++98', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17'], 'gnu++98', 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17'],
'none')}) 'none')})
@ -233,20 +232,18 @@ class GnuCPPCompiler(GnuCompiler, CPPCompiler):
def get_options(self): def get_options(self):
opts = CPPCompiler.get_options(self) opts = CPPCompiler.get_options(self)
opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.',
'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', 'cpp_std': coredata.UserComboOption('C++ language standard to use',
['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a', ['none', 'c++98', 'c++03', 'c++11', 'c++14', 'c++17', 'c++1z', 'c++2a',
'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'], 'gnu++03', 'gnu++11', 'gnu++14', 'gnu++17', 'gnu++1z', 'gnu++2a'],
'none'), 'none'),
'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', 'cpp_debugstl': coredata.UserBooleanOption('STL debug mode',
'STL debug mode',
False)}) False)})
if self.compiler_type.is_windows_compiler: if self.compiler_type.is_windows_compiler:
opts.update({ opts.update({
'cpp_winlibs': coredata.UserArrayOption('cpp_winlibs', 'Standard Win libraries to link against', 'cpp_winlibs': coredata.UserArrayOption('Standard Win libraries to link against',
gnu_winlibs), }) gnu_winlibs), })
return opts return opts
@ -288,16 +285,14 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler):
# It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98. # It does not support c++/gnu++ 17 and 1z, but still does support 0x, 1y, and gnu++98.
def get_options(self): def get_options(self):
opts = CPPCompiler.get_options(self) opts = CPPCompiler.get_options(self)
opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.',
'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', 'cpp_std': coredata.UserComboOption('C++ language standard to use',
['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y', ['none', 'c++98', 'c++03', 'c++0x', 'c++11', 'c++14', 'c++1y',
'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'], 'gnu++98', 'gnu++03', 'gnu++0x', 'gnu++11', 'gnu++14', 'gnu++1y'],
'none'), 'none'),
'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', 'cpp_debugstl': coredata.UserBooleanOption('STL debug mode',
'STL debug mode',
False)}) False)})
return opts return opts
@ -338,15 +333,13 @@ class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler):
c_stds += ['c++17'] c_stds += ['c++17']
if version_compare(self.version, '>=17.0.0'): if version_compare(self.version, '>=17.0.0'):
g_stds += ['gnu++14'] g_stds += ['gnu++14']
opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.',
'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', 'cpp_std': coredata.UserComboOption('C++ language standard to use',
['none'] + c_stds + g_stds, ['none'] + c_stds + g_stds,
'none'), 'none'),
'cpp_debugstl': coredata.UserBooleanOption('cpp_debugstl', 'cpp_debugstl': coredata.UserBooleanOption('STL debug mode',
'STL debug mode',
False)}) False)})
return opts return opts
@ -387,16 +380,13 @@ class VisualStudioLikeCPPCompilerMixin:
return options['cpp_winlibs'].value[:] return options['cpp_winlibs'].value[:]
def _get_options_impl(self, opts, cpp_stds: typing.List[str]): def _get_options_impl(self, opts, cpp_stds: typing.List[str]):
opts.update({'cpp_eh': coredata.UserComboOption('cpp_eh', opts.update({'cpp_eh': coredata.UserComboOption('C++ exception handling type.',
'C++ exception handling type.',
['none', 'default', 'a', 's', 'sc'], ['none', 'default', 'a', 's', 'sc'],
'default'), 'default'),
'cpp_std': coredata.UserComboOption('cpp_std', 'cpp_std': coredata.UserComboOption('C++ language standard to use',
'C++ language standard to use',
cpp_stds, cpp_stds,
'none'), 'none'),
'cpp_winlibs': coredata.UserArrayOption('cpp_winlibs', 'cpp_winlibs': coredata.UserArrayOption('Windows libs to link against.',
'Windows libs to link against.',
msvc_winlibs)}) msvc_winlibs)})
return opts return opts
@ -513,7 +503,7 @@ class ArmCPPCompiler(ArmCompiler, CPPCompiler):
def get_options(self): def get_options(self):
opts = CPPCompiler.get_options(self) opts = CPPCompiler.get_options(self)
opts.update({'cpp_std': coredata.UserComboOption('cpp_std', 'C++ language standard to use', opts.update({'cpp_std': coredata.UserComboOption('C++ language standard to use',
['none', 'c++03', 'c++11'], ['none', 'c++03', 'c++11'],
'none')}) 'none')})
return opts return opts

@ -26,17 +26,19 @@ from .wrap import WrapMode
import ast import ast
import argparse import argparse
import configparser import configparser
from typing import Optional, Any, TypeVar, Generic, Type, List from typing import Optional, Any, TypeVar, Generic, Type, List, Union
version = '0.50.999' version = '0.50.999'
backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode'] backendlist = ['ninja', 'vs', 'vs2010', 'vs2015', 'vs2017', 'vs2019', 'xcode']
default_yielding = False default_yielding = False
class UserOption: # Can't bind this near the class method it seems, sadly.
def __init__(self, name, description, choices, yielding): _T = TypeVar('_T')
class UserOption(Generic[_T]):
def __init__(self, description, choices, yielding):
super().__init__() super().__init__()
self.name = name
self.choices = choices self.choices = choices
self.description = description self.description = description
if yielding is None: if yielding is None:
@ -51,31 +53,31 @@ class UserOption:
# Check that the input is a valid value and return the # Check that the input is a valid value and return the
# "cleaned" or "native" version. For example the Boolean # "cleaned" or "native" version. For example the Boolean
# option could take the string "true" and return True. # option could take the string "true" and return True.
def validate_value(self, value): def validate_value(self, value: Any) -> _T:
raise RuntimeError('Derived option class did not override validate_value.') raise RuntimeError('Derived option class did not override validate_value.')
def set_value(self, newvalue): def set_value(self, newvalue):
self.value = self.validate_value(newvalue) self.value = self.validate_value(newvalue)
class UserStringOption(UserOption): class UserStringOption(UserOption[str]):
def __init__(self, name, description, value, choices=None, yielding=None): def __init__(self, description, value, choices=None, yielding=None):
super().__init__(name, description, choices, yielding) super().__init__(description, choices, yielding)
self.set_value(value) self.set_value(value)
def validate_value(self, value): def validate_value(self, value):
if not isinstance(value, str): if not isinstance(value, str):
raise MesonException('Value "%s" for string option "%s" is not a string.' % (str(value), self.name)) raise MesonException('Value "%s" for string option is not a string.' % str(value))
return value return value
class UserBooleanOption(UserOption): class UserBooleanOption(UserOption[bool]):
def __init__(self, name, description, value, yielding=None): def __init__(self, description, value, yielding=None):
super().__init__(name, description, [True, False], yielding) super().__init__(description, [True, False], yielding)
self.set_value(value) self.set_value(value)
def __bool__(self): def __bool__(self) -> bool:
return self.value return self.value
def validate_value(self, value): def validate_value(self, value) -> bool:
if isinstance(value, bool): if isinstance(value, bool):
return value return value
if value.lower() == 'true': if value.lower() == 'true':
@ -84,9 +86,9 @@ class UserBooleanOption(UserOption):
return False return False
raise MesonException('Value %s is not boolean (true or false).' % value) raise MesonException('Value %s is not boolean (true or false).' % value)
class UserIntegerOption(UserOption): class UserIntegerOption(UserOption[int]):
def __init__(self, name, description, min_value, max_value, value, yielding=None): def __init__(self, description, min_value, max_value, value, yielding=None):
super().__init__(name, description, [True, False], yielding) super().__init__(description, [True, False], yielding)
self.min_value = min_value self.min_value = min_value
self.max_value = max_value self.max_value = max_value
self.set_value(value) self.set_value(value)
@ -97,7 +99,7 @@ class UserIntegerOption(UserOption):
c.append('<=' + str(max_value)) c.append('<=' + str(max_value))
self.choices = ', '.join(c) self.choices = ', '.join(c)
def validate_value(self, value): def validate_value(self, value) -> int:
if isinstance(value, str): if isinstance(value, str):
value = self.toint(value) value = self.toint(value)
if not isinstance(value, int): if not isinstance(value, int):
@ -108,15 +110,15 @@ class UserIntegerOption(UserOption):
raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value)) raise MesonException('New value %d is more than maximum value %d.' % (value, self.max_value))
return value return value
def toint(self, valuestring): def toint(self, valuestring) -> int:
try: try:
return int(valuestring) return int(valuestring)
except ValueError: except ValueError:
raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring) raise MesonException('Value string "%s" is not convertable to an integer.' % valuestring)
class UserUmaskOption(UserIntegerOption): class UserUmaskOption(UserIntegerOption, UserOption[Union[str, int]]):
def __init__(self, name, description, value, yielding=None): def __init__(self, description, value, yielding=None):
super().__init__(name, description, 0, 0o777, value, yielding) super().__init__(description, 0, 0o777, value, yielding)
self.choices = ['preserve', '0000-0777'] self.choices = ['preserve', '0000-0777']
def printable_value(self): def printable_value(self):
@ -135,9 +137,9 @@ class UserUmaskOption(UserIntegerOption):
except ValueError as e: except ValueError as e:
raise MesonException('Invalid mode: {}'.format(e)) raise MesonException('Invalid mode: {}'.format(e))
class UserComboOption(UserOption): class UserComboOption(UserOption[str]):
def __init__(self, name, description, choices, value, yielding=None): def __init__(self, description, choices: List[str], value, yielding=None):
super().__init__(name, description, choices, yielding) super().__init__(description, choices, yielding)
if not isinstance(self.choices, list): if not isinstance(self.choices, list):
raise MesonException('Combo choices must be an array.') raise MesonException('Combo choices must be an array.')
for i in self.choices: for i in self.choices:
@ -148,17 +150,17 @@ class UserComboOption(UserOption):
def validate_value(self, value): def validate_value(self, value):
if value not in self.choices: if value not in self.choices:
optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices]) optionsstring = ', '.join(['"%s"' % (item,) for item in self.choices])
raise MesonException('Value "%s" for combo option "%s" is not one of the choices. Possible choices are: %s.' % (value, self.name, optionsstring)) raise MesonException('Value "%s" for combo option is not one of the choices. Possible choices are: %s.' % (value, optionsstring))
return value return value
class UserArrayOption(UserOption): class UserArrayOption(UserOption[List[str]]):
def __init__(self, name, description, value, shlex_split=False, user_input=False, allow_dups=False, **kwargs): def __init__(self, description, value, shlex_split=False, user_input=False, allow_dups=False, **kwargs):
super().__init__(name, description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None)) super().__init__(description, kwargs.get('choices', []), yielding=kwargs.get('yielding', None))
self.shlex_split = shlex_split self.shlex_split = shlex_split
self.allow_dups = allow_dups self.allow_dups = allow_dups
self.value = self.validate_value(value, user_input=user_input) self.value = self.validate_value(value, user_input=user_input)
def validate_value(self, value, user_input=True): def validate_value(self, value, user_input=True) -> List[str]:
# User input is for options defined on the command line (via -D # User input is for options defined on the command line (via -D
# options). Users can put their input in as a comma separated # options). Users can put their input in as a comma separated
# string, but for defining options in meson_options.txt the format # string, but for defining options in meson_options.txt the format
@ -182,8 +184,8 @@ class UserArrayOption(UserOption):
raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue))) raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
if not self.allow_dups and len(set(newvalue)) != len(newvalue): if not self.allow_dups and len(set(newvalue)) != len(newvalue):
msg = 'Duplicated values in array option "%s" is deprecated. ' \ msg = 'Duplicated values in array option is deprecated. ' \
'This will become a hard error in the future.' % (self.name) 'This will become a hard error in the future.'
mlog.deprecation(msg) mlog.deprecation(msg)
for i in newvalue: for i in newvalue:
if not isinstance(i, str): if not isinstance(i, str):
@ -199,8 +201,8 @@ class UserArrayOption(UserOption):
class UserFeatureOption(UserComboOption): class UserFeatureOption(UserComboOption):
static_choices = ['enabled', 'disabled', 'auto'] static_choices = ['enabled', 'disabled', 'auto']
def __init__(self, name, description, value, yielding=None): def __init__(self, description, value, yielding=None):
super().__init__(name, description, self.static_choices, value, yielding) super().__init__(description, self.static_choices, value, yielding)
def is_enabled(self): def is_enabled(self):
return self.value == 'enabled' return self.value == 'enabled'
@ -334,22 +336,20 @@ class CoreData:
# Create builtin options with default values # Create builtin options with default values
self.builtins = {} self.builtins = {}
for key, opt in builtin_options.items(): for key, opt in builtin_options.items():
self.builtins[key] = opt.init_option(key) self.builtins[key] = opt.init_option()
if opt.separate_cross: if opt.separate_cross:
self.builtins['cross_' + key] = opt.init_option(key) self.builtins['cross_' + key] = opt.init_option()
def init_backend_options(self, backend_name): def init_backend_options(self, backend_name):
if backend_name == 'ninja': if backend_name == 'ninja':
self.backend_options['backend_max_links'] = \ self.backend_options['backend_max_links'] = \
UserIntegerOption( UserIntegerOption(
'backend_max_links',
'Maximum number of linker processes to run or 0 for no ' 'Maximum number of linker processes to run or 0 for no '
'limit', 'limit',
0, None, 0) 0, None, 0)
elif backend_name.startswith('vs'): elif backend_name.startswith('vs'):
self.backend_options['backend_startup_project'] = \ self.backend_options['backend_startup_project'] = \
UserStringOption( UserStringOption(
'backend_startup_project',
'Default project to execute in Visual Studio', 'Default project to execute in Visual Studio',
'') '')
@ -433,7 +433,11 @@ class CoreData:
for opts in self.get_all_options(): for opts in self.get_all_options():
if option_name in opts: if option_name in opts:
opt = opts[option_name] opt = opts[option_name]
return opt.validate_value(override_value) try:
return opt.validate_value(override_value)
except MesonException as e:
raise type(e)(('Validation failed for option %s: ' % option_name) + str(e)) \
.with_traceback(sys.exc_into()[2])
raise MesonException('Tried to validate unknown option %s.' % option_name) raise MesonException('Tried to validate unknown option %s.' % option_name)
def get_external_args(self, for_machine: MachineChoice, lang): def get_external_args(self, for_machine: MachineChoice, lang):
@ -695,9 +699,9 @@ def parse_cmd_line_options(args):
delattr(args, name) delattr(args, name)
_U = TypeVar('_U', bound=UserOption) _U = TypeVar('_U', bound=UserOption[_T])
class BuiltinOption(Generic[_U]): class BuiltinOption(Generic[_T, _U]):
"""Class for a builtin option type. """Class for a builtin option type.
@ -713,12 +717,12 @@ class BuiltinOption(Generic[_U]):
self.yielding = yielding self.yielding = yielding
self.separate_cross = separate_cross self.separate_cross = separate_cross
def init_option(self, name: str) -> _U: def init_option(self) -> _U:
"""Create an instance of opt_type and return it.""" """Create an instance of opt_type and return it."""
keywords = {'yielding': self.yielding, 'value': self.default} keywords = {'yielding': self.yielding, 'value': self.default}
if self.choices: if self.choices:
keywords['choices'] = self.choices keywords['choices'] = self.choices
return self.opt_type(name, self.description, **keywords) return self.opt_type(self.description, **keywords)
def _argparse_action(self) -> Optional[str]: def _argparse_action(self) -> Optional[str]:
if self.default is True: if self.default is True:

@ -60,12 +60,12 @@ def stringifyUserArguments(args):
class FeatureOptionHolder(InterpreterObject, ObjectHolder): class FeatureOptionHolder(InterpreterObject, ObjectHolder):
def __init__(self, env, option): def __init__(self, env, name, option):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
ObjectHolder.__init__(self, option) ObjectHolder.__init__(self, option)
if option.is_auto(): if option.is_auto():
self.held_object = env.coredata.builtins['auto_features'] self.held_object = env.coredata.builtins['auto_features']
self.name = option.name self.name = name
self.methods.update({'enabled': self.enabled_method, self.methods.update({'enabled': self.enabled_method,
'disabled': self.disabled_method, 'disabled': self.disabled_method,
'auto': self.auto_method, 'auto': self.auto_method,
@ -2536,7 +2536,7 @@ external dependencies (including libraries) must go to "dependencies".''')
'options of other subprojects.') 'options of other subprojects.')
opt = self.get_option_internal(optname) opt = self.get_option_internal(optname)
if isinstance(opt, coredata.UserFeatureOption): if isinstance(opt, coredata.UserFeatureOption):
return FeatureOptionHolder(self.environment, opt) return FeatureOptionHolder(self.environment, optname, opt)
elif isinstance(opt, coredata.UserOption): elif isinstance(opt, coredata.UserOption):
return opt.value return opt.value
return opt return opt

@ -26,7 +26,7 @@ from .ast import IntrospectionInterpreter, build_target_functions, AstConditionL
from . import mlog from . import mlog
from .backend import backends from .backend import backends
from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode from .mparser import FunctionNode, ArrayNode, ArgumentNode, StringNode
from typing import List, Optional from typing import Dict, List, Optional
import os import os
import pathlib import pathlib
@ -236,7 +236,7 @@ def list_buildoptions(coredata: cdata.CoreData) -> List[dict]:
add_keys(optlist, test_options, 'test') add_keys(optlist, test_options, 'test')
return optlist return optlist
def add_keys(optlist, options, section): def add_keys(optlist, options: Dict[str, cdata.UserOption], section):
keys = list(options.keys()) keys = list(options.keys())
keys.sort() keys.sort()
for key in keys: for key in keys:

@ -14,6 +14,7 @@
import os, re import os, re
import functools import functools
import typing
from . import mparser from . import mparser
from . import coredata from . import coredata
@ -49,7 +50,7 @@ def permitted_kwargs(permitted):
if bad: if bad:
raise OptionException('Invalid kwargs for option "{}": "{}"'.format( raise OptionException('Invalid kwargs for option "{}": "{}"'.format(
name, ' '.join(bad))) name, ' '.join(bad)))
return func(name, description, kwargs) return func(description, kwargs)
return _inner return _inner
return _wraps return _wraps
@ -57,21 +58,20 @@ def permitted_kwargs(permitted):
optname_regex = re.compile('[^a-zA-Z0-9_-]') optname_regex = re.compile('[^a-zA-Z0-9_-]')
@permitted_kwargs({'value', 'yield'}) @permitted_kwargs({'value', 'yield'})
def StringParser(name, description, kwargs): def StringParser(description, kwargs):
return coredata.UserStringOption(name, return coredata.UserStringOption(description,
description,
kwargs.get('value', ''), kwargs.get('value', ''),
kwargs.get('choices', []), kwargs.get('choices', []),
kwargs.get('yield', coredata.default_yielding)) kwargs.get('yield', coredata.default_yielding))
@permitted_kwargs({'value', 'yield'}) @permitted_kwargs({'value', 'yield'})
def BooleanParser(name, description, kwargs): def BooleanParser(description, kwargs):
return coredata.UserBooleanOption(name, description, return coredata.UserBooleanOption(description,
kwargs.get('value', True), kwargs.get('value', True),
kwargs.get('yield', coredata.default_yielding)) kwargs.get('yield', coredata.default_yielding))
@permitted_kwargs({'value', 'yield', 'choices'}) @permitted_kwargs({'value', 'yield', 'choices'})
def ComboParser(name, description, kwargs): def ComboParser(description, kwargs):
if 'choices' not in kwargs: if 'choices' not in kwargs:
raise OptionException('Combo option missing "choices" keyword.') raise OptionException('Combo option missing "choices" keyword.')
choices = kwargs['choices'] choices = kwargs['choices']
@ -80,19 +80,17 @@ def ComboParser(name, description, kwargs):
for i in choices: for i in choices:
if not isinstance(i, str): if not isinstance(i, str):
raise OptionException('Combo choice elements must be strings.') raise OptionException('Combo choice elements must be strings.')
return coredata.UserComboOption(name, return coredata.UserComboOption(description,
description,
choices, choices,
kwargs.get('value', choices[0]), kwargs.get('value', choices[0]),
kwargs.get('yield', coredata.default_yielding),) kwargs.get('yield', coredata.default_yielding),)
@permitted_kwargs({'value', 'min', 'max', 'yield'}) @permitted_kwargs({'value', 'min', 'max', 'yield'})
def IntegerParser(name, description, kwargs): def IntegerParser(description, kwargs):
if 'value' not in kwargs: if 'value' not in kwargs:
raise OptionException('Integer option must contain value argument.') raise OptionException('Integer option must contain value argument.')
return coredata.UserIntegerOption(name, return coredata.UserIntegerOption(description,
description,
kwargs.get('min', None), kwargs.get('min', None),
kwargs.get('max', None), kwargs.get('max', None),
kwargs['value'], kwargs['value'],
@ -102,7 +100,7 @@ def IntegerParser(name, description, kwargs):
# reading options in project(). See func_project() in interpreter.py # reading options in project(). See func_project() in interpreter.py
#@FeatureNew('array type option()', '0.44.0') #@FeatureNew('array type option()', '0.44.0')
@permitted_kwargs({'value', 'yield', 'choices'}) @permitted_kwargs({'value', 'yield', 'choices'})
def string_array_parser(name, description, kwargs): def string_array_parser(description, kwargs):
if 'choices' in kwargs: if 'choices' in kwargs:
choices = kwargs['choices'] choices = kwargs['choices']
if not isinstance(choices, list): if not isinstance(choices, list):
@ -116,16 +114,14 @@ def string_array_parser(name, description, kwargs):
value = kwargs.get('value', []) value = kwargs.get('value', [])
if not isinstance(value, list): if not isinstance(value, list):
raise OptionException('Array choices must be passed as an array.') raise OptionException('Array choices must be passed as an array.')
return coredata.UserArrayOption(name, return coredata.UserArrayOption(description,
description,
value, value,
choices=choices, choices=choices,
yielding=kwargs.get('yield', coredata.default_yielding)) yielding=kwargs.get('yield', coredata.default_yielding))
@permitted_kwargs({'value', 'yield'}) @permitted_kwargs({'value', 'yield'})
def FeatureParser(name, description, kwargs): def FeatureParser(description, kwargs):
return coredata.UserFeatureOption(name, return coredata.UserFeatureOption(description,
description,
kwargs.get('value', 'auto'), kwargs.get('value', 'auto'),
yielding=kwargs.get('yield', coredata.default_yielding)) yielding=kwargs.get('yield', coredata.default_yielding))
@ -135,7 +131,7 @@ option_types = {'string': StringParser,
'integer': IntegerParser, 'integer': IntegerParser,
'array': string_array_parser, 'array': string_array_parser,
'feature': FeatureParser, 'feature': FeatureParser,
} } # type: typing.Dict[str, typing.Callable[[str, typing.Dict], coredata.UserOption]]
class OptionInterpreter: class OptionInterpreter:
def __init__(self, subproject): def __init__(self, subproject):

Loading…
Cancel
Save