interpreter: add feature.require()
Add a method to perform a logical AND on a feature object. The method also takes care of raising an error if 'enabled' is ANDed with false. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
5298d8eaf1
commit
2f2d99e1d8
|
@ -2819,6 +2819,21 @@ The following methods are defined for all [`feature` options](Build-options.md#f
|
|||
- `disabled()`: returns whether the feature was set to `'disabled'`
|
||||
- `auto()`: returns whether the feature was set to `'auto'`
|
||||
- `allowed()` *(since 0.59.0)*: returns whether the feature was set to `'enabled'` or `'auto'`
|
||||
- `require(value, error_message: '')` *(since 0.59.0)*: returns
|
||||
the object itself if the value is true; an error if the object is
|
||||
`'enabled'` and the value is false; a disabled feature if the object
|
||||
is `'auto'` or `'disabled'` and the value is false.
|
||||
|
||||
`require` is useful to restrict the applicability of `'auto'` features,
|
||||
for example based on other features or on properties of the host machine:
|
||||
|
||||
```
|
||||
if get_option('directx').require(host_machine.system() == 'windows',
|
||||
error_message: 'DirectX only available on Windows').allowed() then
|
||||
src += ['directx.c']
|
||||
config.set10('HAVE_DIRECTX', 1)
|
||||
endif
|
||||
```
|
||||
|
||||
### `generator` object
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ class FeatureOptionHolder(InterpreterObject, ObjectHolder[coredata.UserFeatureOp
|
|||
def __init__(self, env: 'Environment', name: str, option: coredata.UserFeatureOption):
|
||||
InterpreterObject.__init__(self)
|
||||
ObjectHolder.__init__(self, option)
|
||||
if option.is_auto():
|
||||
if option and option.is_auto():
|
||||
# TODO: we need to case here because options is not a TypedDict
|
||||
self.held_object = T.cast(coredata.UserFeatureOption, env.coredata.options[OptionKey('auto_features')])
|
||||
self.name = name
|
||||
|
@ -74,11 +74,15 @@ class FeatureOptionHolder(InterpreterObject, ObjectHolder[coredata.UserFeatureOp
|
|||
'disabled': self.disabled_method,
|
||||
'allowed': self.allowed_method,
|
||||
'auto': self.auto_method,
|
||||
'require': self.require_method,
|
||||
})
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self.held_object.value
|
||||
return 'disabled' if not self.held_object else self.held_object.value
|
||||
|
||||
def as_disabled(self):
|
||||
return FeatureOptionHolder(None, self.name, None)
|
||||
|
||||
@noPosargs
|
||||
@permittedKwargs({})
|
||||
|
@ -100,6 +104,25 @@ class FeatureOptionHolder(InterpreterObject, ObjectHolder[coredata.UserFeatureOp
|
|||
def auto_method(self, args, kwargs):
|
||||
return self.value == 'auto'
|
||||
|
||||
@permittedKwargs({'error_message'})
|
||||
def require_method(self, args, kwargs):
|
||||
if len(args) != 1:
|
||||
raise InvalidArguments('Expected 1 argument, got %d.' % (len(args), ))
|
||||
if not isinstance(args[0], bool):
|
||||
raise InvalidArguments('boolean argument expected.')
|
||||
error_message = kwargs.pop('error_message', '')
|
||||
if error_message and not isinstance(error_message, str):
|
||||
raise InterpreterException("Error message must be a string.")
|
||||
if args[0]:
|
||||
return self
|
||||
|
||||
if self.value == 'enabled':
|
||||
prefix = 'Feature {} cannot be enabled'.format(self.name)
|
||||
prefix = prefix + ': ' if error_message else ''
|
||||
raise InterpreterException(prefix + error_message)
|
||||
return self.as_disabled()
|
||||
|
||||
|
||||
class RunProcess(InterpreterObject):
|
||||
|
||||
def __init__(self, cmd, args, env, source_dir, build_dir, subdir, mesonintrospect, in_builddir=False, check=False, capture=True):
|
||||
|
|
|
@ -14,16 +14,21 @@ assert(required_opt.enabled(), 'Should be enabled option')
|
|||
assert(not required_opt.disabled(), 'Should be enabled option')
|
||||
assert(not required_opt.auto(), 'Should be enabled option')
|
||||
assert(required_opt.allowed(), 'Should be enabled option')
|
||||
assert(required_opt.require(true, error_message: 'xyz').enabled(), 'Should be enabled option')
|
||||
|
||||
assert(not optional_opt.enabled(), 'Should be auto option')
|
||||
assert(not optional_opt.disabled(), 'Should be auto option')
|
||||
assert(optional_opt.auto(), 'Should be auto option')
|
||||
assert(optional_opt.allowed(), 'Should be auto option')
|
||||
assert(optional_opt.require(true).auto(), 'Should be auto option')
|
||||
assert(optional_opt.require(false, error_message: 'xyz').disabled(), 'Should be disabled auto option')
|
||||
|
||||
assert(not disabled_opt.enabled(), 'Should be disabled option')
|
||||
assert(disabled_opt.disabled(), 'Should be disabled option')
|
||||
assert(not disabled_opt.auto(), 'Should be disabled option')
|
||||
assert(not disabled_opt.allowed(), 'Should be disabled option')
|
||||
assert(disabled_opt.require(true).disabled(), 'Should be disabled option')
|
||||
assert(disabled_opt.require(false, error_message: 'xyz').disabled(), 'Should be disabled option')
|
||||
|
||||
dep = dependency('threads', required : required_opt)
|
||||
assert(dep.found(), 'Should find required "threads" dep')
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
project('no fallback', 'c')
|
||||
foo = get_option('reqfeature').require(false, error_message: 'frobnicator not available')
|
|
@ -0,0 +1,2 @@
|
|||
option('reqfeature', type : 'feature', value : 'enabled', description : 'A required feature')
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"stdout": [
|
||||
{
|
||||
"match": "re",
|
||||
"line": ".*/meson\\.build:2:0: ERROR: Feature reqfeature cannot be enabled: frobnicator not available"
|
||||
}
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue