Merge pull request #2390 from dcbaker/submit/options-list

Add an array type to user options
pull/2730/head
Jussi Pakkanen 7 years ago committed by GitHub
commit 793fc002fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      docs/markdown/Build-options.md
  2. 17
      docs/markdown/snippets/option-array-type.md
  3. 33
      mesonbuild/coredata.py
  4. 16
      mesonbuild/optinterpreter.py
  5. 48
      run_unittests.py
  6. 17
      test cases/common/166 array option/meson.build
  7. 19
      test cases/common/166 array option/meson_options.txt
  8. 5
      test cases/common/47 options/meson.build
  9. 1
      test cases/common/47 options/meson_options.txt
  10. 15
      test cases/unit/18 array option/meson.build
  11. 20
      test cases/unit/18 array option/meson_options.txt

@ -16,18 +16,37 @@ Here is a simple option file.
option('someoption', type : 'string', value : 'optval', description : 'An option')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'three'], value : 'three')
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])
```
This demonstrates the three basic option types and their usage. String
option is just a free form string and a boolean option is,
unsurprisingly, true or false. The combo option can have any value
from the strings listed in argument `choices`. If `value` is not set,
it defaults to empty string for strings, `true` for booleans or the
first element in a combo. You can specify `description`, which is a
free form piece of text describing the option. It defaults to option
name.
All types allow a `description` value to be set describing the option, if no
option is set then the name of the option will be used instead.
These options are accessed in Meson code with the `get_option` function.
### Strings
The string type is a free form string. If the default value is not set then an
empty string will be used as the default.
### Booleans
Booleans may have values of either `true` or `false`. If not default value is
supplied then `true` will be used as the default.
### Combos
A combo allows any one of the values in the `choices` parameter to be selected.
If no default value is set then the first value will be the default.
### Arrays
Arrays allow one or more of the values in the `choices` parameter to be selected.
If the `value` parameter is unset then the values of `choices` will be used as
the default.
This type is new in version 0.44.0
## Using build options
```meson
optval = get_option('opt_name')

@ -0,0 +1,17 @@
# An array type for user options
Previously to have an option that took more than one value a string value would
have to be created and split, but validating this was difficult. A new array type
has been added to the meson_options.txt for this case. It works like a 'combo', but
allows more than one option to be passed. When used on the command line (with -D),
values are passed as a comma separated list.
```meson
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one'])
```
These can be overwritten on the command line,
```meson
meson _build -Darray_opt=two,three
```

@ -128,24 +128,37 @@ class UserComboOption(UserOption):
class UserStringArrayOption(UserOption):
def __init__(self, name, description, value, **kwargs):
super().__init__(name, description, kwargs.get('choices', []))
self.set_value(value)
def validate(self, value):
if isinstance(value, str):
if not value.startswith('['):
raise MesonException('Valuestring does not define an array: ' + value)
newvalue = ast.literal_eval(value)
self.set_value(value, user_input=False)
def validate(self, value, user_input):
# User input is for options defined on the command line (via -D
# options). Users should put their input in as a comma separated
# string, but for defining options in meson_options.txt the format
# should match that of a combo
if not user_input:
if isinstance(value, str):
if not value.startswith('['):
raise MesonException('Valuestring does not define an array: ' + value)
newvalue = ast.literal_eval(value)
else:
newvalue = value
else:
newvalue = value
assert isinstance(value, str)
newvalue = [v.strip() for v in value.split(',')]
if not isinstance(newvalue, list):
raise MesonException('"{0}" should be a string array, but it is not'.format(str(newvalue)))
for i in newvalue:
if not isinstance(i, str):
raise MesonException('String array element "{0}" is not a string.'.format(str(newvalue)))
if self.choices:
bad = [x for x in newvalue if x not in self.choices]
if bad:
raise MesonException('Options "{}" are not in allowed choices: "{}"'.format(
', '.join(bad), ', '.join(self.choices)))
return newvalue
def set_value(self, newvalue):
self.value = self.validate(newvalue)
def set_value(self, newvalue, user_input=True):
self.value = self.validate(newvalue, user_input)
def validate_value(self, value):
self.validate(value)

@ -84,9 +84,25 @@ def ComboParser(name, description, kwargs):
raise OptionException('Combo choice elements must be strings.')
return coredata.UserComboOption(name, description, choices, kwargs.get('value', choices[0]))
@permitted_kwargs({'value', 'choices'})
def string_array_parser(name, description, kwargs):
if 'choices' not in kwargs:
raise OptionException('Array option missing "choices" keyword.')
choices = kwargs['choices']
if not isinstance(choices, list):
raise OptionException('Array choices must be an array.')
for i in choices:
if not isinstance(i, str):
raise OptionException('Array choice elements must be strings.')
value = kwargs.get('value', choices)
if not isinstance(value, list):
raise OptionException('Array choices must be passed as an array.')
return coredata.UserStringArrayOption(name, description, value, choices=choices)
option_types = {'string': StringParser,
'boolean': BooleanParser,
'combo': ComboParser,
'array': string_array_parser,
}
class OptionInterpreter:

@ -1,4 +1,3 @@
#!/usr/bin/env python3
# Copyright 2016-2017 The Meson development team
@ -1565,6 +1564,53 @@ int main(int argc, char **argv) {
cargs = ['-I' + incdir.as_posix()]
self.assertEqual(foo_dep.get_compile_args(), cargs)
def test_array_option_change(self):
def get_opt():
opts = self.introspect('--buildoptions')
for x in opts:
if x.get('name') == 'list':
return x
raise Exception(opts)
expected = {
'name': 'list',
'description': 'list',
'type': 'stringarray',
'value': ['foo', 'bar'],
}
tdir = os.path.join(self.unit_test_dir, '18 array option')
self.init(tdir)
original = get_opt()
self.assertDictEqual(original, expected)
expected['value'] = ['oink', 'boink']
self.setconf('-Dlist=oink,boink')
changed = get_opt()
self.assertEqual(changed, expected)
def test_array_option_bad_change(self):
def get_opt():
opts = self.introspect('--buildoptions')
for x in opts:
if x.get('name') == 'list':
return x
raise Exception(opts)
expected = {
'name': 'list',
'description': 'list',
'type': 'stringarray',
'value': ['foo', 'bar'],
}
tdir = os.path.join(self.unit_test_dir, '18 array option')
self.init(tdir)
original = get_opt()
self.assertDictEqual(original, expected)
with self.assertRaises(subprocess.CalledProcessError):
self.setconf('-Dlist=bad')
changed = get_opt()
self.assertDictEqual(changed, expected)
class FailureTests(BasePlatformTests):
'''

@ -0,0 +1,17 @@
# Copyright © 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
project('stringarray default options')
assert(get_option('array') == ['foo', 'bar'], 'Default value for array is not equal to choices')

@ -0,0 +1,19 @@
# Copyright © 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
option(
'array',
type : 'array',
choices : ['foo', 'bar'],
)

@ -12,6 +12,11 @@ if get_option('combo_opt') != 'combo'
error('Incorrect value to combo option.')
endif
if get_option('array_opt') != ['one', 'two']
message(get_option('array_opt'))
error('Incorrect value for array option')
endif
# If the default changes, update test cases/unit/13 reconfigure
if get_option('b_lto') != false
error('Incorrect value in base option.')

@ -1,3 +1,4 @@
option('testoption', type : 'string', value : 'optval', description : 'An option to do something')
option('other_one', type : 'boolean', value : false)
option('combo_opt', type : 'combo', choices : ['one', 'two', 'combo'], value : 'combo')
option('array_opt', type : 'array', choices : ['one', 'two', 'three'], value : ['one', 'two'])

@ -0,0 +1,15 @@
# Copyright © 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
project('array option test')

@ -0,0 +1,20 @@
# Copyright © 2017 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
option(
'list',
type : 'array',
value : ['foo', 'bar'],
choices : ['foo', 'bar', 'oink', 'boink'],
)
Loading…
Cancel
Save