aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2018-04-11 10:13:14 -0400
committerNirbheek Chauhan <nirbheek.chauhan@gmail.com>2018-06-18 04:57:32 +0000
commite565945253662ef6e2151241b6686a999b78a43d (patch)
tree72c98fe3715acbb6704bcd80c902e9b49bb2a65b /mesonbuild
parent5290f41f31439180b15600bca4ce4456983e3900 (diff)
downloadmeson-e565945253662ef6e2151241b6686a999b78a43d.zip
meson-e565945253662ef6e2151241b6686a999b78a43d.tar.gz
meson-e565945253662ef6e2151241b6686a999b78a43d.tar.bz2
Add UserFeatureOption type
This is a special type of option to be passed to most 'required' keyword arguments. It adds a 3rd state to the traditional boolean value to cause those methods to always return not-found even if the dependency could be found. Since integrators doesn't want enabled features to be a surprise there is a global option "auto_features" to enable or disable all automatic features.
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/coredata.py18
-rw-r--r--mesonbuild/interpreter.py128
-rw-r--r--mesonbuild/optinterpreter.py8
3 files changed, 129 insertions, 25 deletions
diff --git a/mesonbuild/coredata.py b/mesonbuild/coredata.py
index 4db8e4a..557aabc 100644
--- a/mesonbuild/coredata.py
+++ b/mesonbuild/coredata.py
@@ -178,6 +178,21 @@ class UserArrayOption(UserOption):
', '.join(bad), ', '.join(self.choices)))
return newvalue
+class UserFeatureOption(UserComboOption):
+ static_choices = ['enabled', 'disabled', 'auto']
+
+ def __init__(self, name, description, value, yielding=None):
+ super().__init__(name, description, self.static_choices, value, yielding)
+
+ def is_enabled(self):
+ return self.value == 'enabled'
+
+ def is_disabled(self):
+ return self.value == 'disabled'
+
+ def is_auto(self):
+ return self.value == 'auto'
+
# This class contains all data that must persist over multiple
# invocations of Meson. It is roughly the same thing as
# cmakecache.
@@ -437,6 +452,8 @@ def get_builtin_option_choices(optname):
return builtin_options[optname][2]
elif builtin_options[optname][0] == UserBooleanOption:
return [True, False]
+ elif builtin_options[optname][0] == UserFeatureOption:
+ return UserFeatureOption.static_choices
else:
return None
else:
@@ -549,6 +566,7 @@ builtin_options = {
'stdsplit': [UserBooleanOption, 'Split stdout and stderr in test logs.', True],
'errorlogs': [UserBooleanOption, "Whether to print the logs from failing tests.", True],
'install_umask': [UserUmaskOption, 'Default umask to apply on permissions of installed files.', '022'],
+ 'auto_features': [UserFeatureOption, "Override value of all 'auto' features.", 'auto'],
}
# Special prefix-dependent defaults for installation directories that reside in
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 421ddd9..3de58bd 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -62,6 +62,55 @@ class ObjectHolder:
def __repr__(self):
return '<Holder: {!r}>'.format(self.held_object)
+class FeatureOptionHolder(InterpreterObject, ObjectHolder):
+ def __init__(self, env, option):
+ InterpreterObject.__init__(self)
+ ObjectHolder.__init__(self, option)
+ if option.is_auto():
+ self.held_object = env.coredata.builtins['auto_features']
+ self.name = option.name
+ self.methods.update({'enabled': self.enabled_method,
+ 'disabled': self.disabled_method,
+ 'auto': self.auto_method,
+ })
+
+ @noPosargs
+ @permittedKwargs({})
+ def enabled_method(self, args, kwargs):
+ return self.held_object.is_enabled()
+
+ @noPosargs
+ @permittedKwargs({})
+ def disabled_method(self, args, kwargs):
+ return self.held_object.is_disabled()
+
+ @noPosargs
+ @permittedKwargs({})
+ def auto_method(self, args, kwargs):
+ return self.held_object.is_auto()
+
+def extract_required_kwarg(kwargs):
+ val = kwargs.get('required', True)
+ disabled = False
+ required = False
+ feature = None
+ if isinstance(val, FeatureOptionHolder):
+ option = val.held_object
+ feature = val.name
+ if option.is_disabled():
+ disabled = True
+ elif option.is_enabled():
+ required = True
+ elif isinstance(required, bool):
+ required = val
+ else:
+ raise InterpreterException('required keyword argument must be boolean or a feature option')
+
+ # Keep boolean value in kwargs to simplify other places where this kwarg is
+ # checked.
+ kwargs['required'] = required
+
+ return disabled, required, feature
class TryRunResultHolder(InterpreterObject):
def __init__(self, res):
@@ -1337,9 +1386,16 @@ class CompilerHolder(InterpreterObject):
libname = args[0]
if not isinstance(libname, str):
raise InterpreterException('Library name not a string.')
- required = kwargs.get('required', True)
- if not isinstance(required, bool):
- raise InterpreterException('required must be boolean.')
+
+ disabled, required, feature = extract_required_kwarg(kwargs)
+ if disabled:
+ mlog.log('Library', mlog.bold(libname), 'skipped: feature', mlog.bold(feature), 'disabled')
+ lib = dependencies.ExternalLibrary(libname, None,
+ self.environment,
+ self.compiler.language,
+ silent=True)
+ return ExternalLibraryHolder(lib)
+
search_dirs = mesonlib.stringlistify(kwargs.get('dirs', []))
for i in search_dirs:
if not os.path.isabs(i):
@@ -2168,44 +2224,54 @@ external dependencies (including libraries) must go to "dependencies".''')
self.build_def_files += subi.build_def_files
return self.subprojects[dirname]
- @stringArgs
- @noKwargs
- def func_get_option(self, nodes, args, kwargs):
- if len(args) != 1:
- raise InterpreterException('Argument required for get_option.')
- undecorated_optname = optname = args[0]
- if ':' in optname:
- raise InterpreterException('''Having a colon in option name is forbidden, projects are not allowed
-to directly access options of other subprojects.''')
+ def get_option_internal(self, optname):
+ undecorated_optname = optname
try:
- return self.environment.get_coredata().base_options[optname].value
+ return self.coredata.base_options[optname]
except KeyError:
pass
try:
- return self.environment.coredata.get_builtin_option(optname)
- except RuntimeError:
+ return self.coredata.builtins[optname]
+ except KeyError:
pass
try:
- return self.environment.coredata.compiler_options[optname].value
+ return self.coredata.compiler_options[optname]
except KeyError:
pass
if not coredata.is_builtin_option(optname) and self.is_subproject():
optname = self.subproject + ':' + optname
try:
- opt = self.environment.coredata.user_options[optname]
+ opt = self.coredata.user_options[optname]
if opt.yielding and ':' in optname:
# If option not present in superproject, keep the original.
- opt = self.environment.coredata.user_options.get(undecorated_optname, opt)
- return opt.value
+ opt = self.coredata.user_options.get(undecorated_optname, opt)
+ return opt
except KeyError:
pass
# Some base options are not defined in some environments, return the default value.
try:
- return compilers.base_options[optname].value
+ return compilers.base_options[optname]
except KeyError:
pass
raise InterpreterException('Tried to access unknown option "%s".' % optname)
+ @stringArgs
+ @noKwargs
+ def func_get_option(self, nodes, args, kwargs):
+ if len(args) != 1:
+ raise InterpreterException('Argument required for get_option.')
+ optname = args[0]
+ if ':' in optname:
+ raise InterpreterException('Having a colon in option name is forbidden, '
+ 'projects are not allowed to directly access '
+ 'options of other subprojects.')
+ opt = self.get_option_internal(optname)
+ if isinstance(opt, coredata.UserFeatureOption):
+ return FeatureOptionHolder(self.environment, opt)
+ elif isinstance(opt, coredata.UserOption):
+ return opt.value
+ return opt
+
@noKwargs
def func_configuration_data(self, node, args, kwargs):
if args:
@@ -2350,7 +2416,12 @@ to directly access options of other subprojects.''')
@permittedKwargs(permitted_kwargs['add_languages'])
@stringArgs
def func_add_languages(self, node, args, kwargs):
- return self.add_languages(args, kwargs.get('required', True))
+ disabled, required, feature = extract_required_kwarg(kwargs)
+ if disabled:
+ for lang in sorted(args, key=compilers.sort_clike):
+ mlog.log('Compiler for language', mlog.bold(lang), 'skipped: feature', mlog.bold(feature), 'disabled')
+ return False
+ return self.add_languages(args, required)
def get_message_string_arg(self, node):
# reduce arguments again to avoid flattening posargs
@@ -2604,7 +2675,12 @@ to directly access options of other subprojects.''')
def func_find_program(self, node, args, kwargs):
if not args:
raise InterpreterException('No program name specified.')
- required = kwargs.get('required', True)
+
+ disabled, required, feature = extract_required_kwarg(kwargs)
+ if disabled:
+ mlog.log('Program', mlog.bold(' '.join(args)), 'skipped: feature', mlog.bold(feature), 'disabled')
+ return ExternalProgramHolder(dependencies.NonExistingExternalProgram())
+
if not isinstance(required, bool):
raise InvalidArguments('"required" argument must be a boolean.')
use_native = kwargs.get('native', False)
@@ -2699,11 +2775,13 @@ to directly access options of other subprojects.''')
@permittedKwargs(permitted_kwargs['dependency'])
def func_dependency(self, node, args, kwargs):
self.validate_arguments(args, 1, [str])
- required = kwargs.get('required', True)
- if not isinstance(required, bool):
- raise DependencyException('Keyword "required" must be a boolean.')
name = args[0]
+ disabled, required, feature = extract_required_kwarg(kwargs)
+ if disabled:
+ mlog.log('Dependency', mlog.bold(name), 'skipped: feature', mlog.bold(feature), 'disabled')
+ return DependencyHolder(NotFoundDependency(self.environment))
+
if name == '':
if required:
raise InvalidArguments('Dependency is both required and not-found')
diff --git a/mesonbuild/optinterpreter.py b/mesonbuild/optinterpreter.py
index 4207f45..cd3139b 100644
--- a/mesonbuild/optinterpreter.py
+++ b/mesonbuild/optinterpreter.py
@@ -116,11 +116,19 @@ def string_array_parser(name, description, kwargs):
choices=choices,
yielding=kwargs.get('yield', coredata.default_yielding))
+@permitted_kwargs({'value', 'yield'})
+def FeatureParser(name, description, kwargs):
+ return coredata.UserFeatureOption(name,
+ description,
+ kwargs.get('value', 'enabled'),
+ yielding=kwargs.get('yield', coredata.default_yielding))
+
option_types = {'string': StringParser,
'boolean': BooleanParser,
'combo': ComboParser,
'integer': IntegerParser,
'array': string_array_parser,
+ 'feature': FeatureParser,
}
class OptionInterpreter: