mesonlib: Replace unholder argument to listify

listify shouldn't be unholdering, it's a function to turn scalar values
into lists, or flatten lists. Having a separate function is clearer,
easier to understand, and can be run recursively if necessary.
pull/6736/head
Dylan Baker 5 years ago
parent 1a82880730
commit a8293dd59c
  1. 24
      mesonbuild/build.py
  2. 2
      mesonbuild/compilers/compilers.py
  3. 24
      mesonbuild/interpreter.py
  4. 19
      mesonbuild/mesonlib.py
  5. 6
      mesonbuild/modules/gnome.py
  6. 4
      mesonbuild/modules/pkgconfig.py
  7. 24
      run_unittests.py

@ -26,7 +26,7 @@ from . import mlog
from .mesonlib import (
File, MesonException, MachineChoice, PerMachine, OrderedSet, listify,
extract_as_list, typeslistify, stringlistify, classify_unity_sources,
get_filenames_templates_dict, substitute_values, has_path_sep,
get_filenames_templates_dict, substitute_values, has_path_sep, unholder
)
from .compilers import Compiler, is_object, clink_langs, sort_clink, lang_suffixes
from .linkers import StaticLinker
@ -856,7 +856,7 @@ just like those detected with the dependency() function.''')
if dfeature_debug:
dfeatures['debug'] = dfeature_debug
if 'd_import_dirs' in kwargs:
dfeature_import_dirs = extract_as_list(kwargs, 'd_import_dirs', unholder=True)
dfeature_import_dirs = unholder(extract_as_list(kwargs, 'd_import_dirs'))
for d in dfeature_import_dirs:
if not isinstance(d, IncludeDirs):
raise InvalidArguments('Arguments to d_import_dirs must be include_directories.')
@ -1083,7 +1083,7 @@ You probably should put it in link_with instead.''')
return isinstance(self, StaticLibrary) and not self.need_install
def link(self, target):
for t in listify(target, unholder=True):
for t in unholder(listify(target)):
if isinstance(self, StaticLibrary) and self.need_install and t.is_internal():
# When we're a static library and we link_with to an
# internal/convenience library, promote to link_whole.
@ -1105,7 +1105,7 @@ You probably should put it in link_with instead.''')
self.link_targets.append(t)
def link_whole(self, target):
for t in listify(target, unholder=True):
for t in unholder(listify(target)):
if isinstance(t, (CustomTarget, CustomTargetIndex)):
if not t.is_linkable_target():
raise InvalidArguments('Custom target {!r} is not linkable.'.format(t))
@ -1261,7 +1261,7 @@ You probably should put it in link_with instead.''')
if dl != linker.language:
stdlib_args += all_compilers[dl].language_stdlib_only_link_flags()
added_languages.add(dl)
# Type of var 'linker' is Compiler.
# Type of var 'linker' is Compiler.
# Pretty hard to fix because the return value is passed everywhere
return linker, stdlib_args
@ -1372,7 +1372,7 @@ class Generator:
raise InvalidArguments('Capture must be boolean.')
self.capture = capture
if 'depends' in kwargs:
depends = listify(kwargs['depends'], unholder=True)
depends = unholder(listify(kwargs['depends']))
for d in depends:
if not isinstance(d, BuildTarget):
raise InvalidArguments('Depends entries must be build targets.')
@ -2054,7 +2054,7 @@ class CustomTarget(Target):
return bdeps
def flatten_command(self, cmd):
cmd = listify(cmd, unholder=True)
cmd = unholder(listify(cmd))
final_cmd = []
for c in cmd:
if isinstance(c, str):
@ -2082,7 +2082,7 @@ class CustomTarget(Target):
def process_kwargs(self, kwargs, backend):
self.process_kwargs_base(kwargs)
self.sources = extract_as_list(kwargs, 'input', unholder=True)
self.sources = unholder(extract_as_list(kwargs, 'input'))
if 'output' not in kwargs:
raise InvalidArguments('Missing keyword argument "output".')
self.outputs = listify(kwargs['output'])
@ -2411,18 +2411,18 @@ class ConfigureFile:
class ConfigurationData:
def __init__(self) -> None:
super().__init__()
self.values = {}
self.values = {} # T.Dict[str, T.Union[str, int, bool]]
def __repr__(self):
return repr(self.values)
def __contains__(self, value):
def __contains__(self, value: str) -> bool:
return value in self.values
def get(self, name):
def get(self, name: str) -> T.Tuple[T.Union[str, int, bool], T.Optional[str]]:
return self.values[name] # (val, desc)
def keys(self):
def keys(self) -> T.Iterator[str]:
return self.values.keys()
# A bit poorly named, but this represents plain data files to copy

@ -35,6 +35,8 @@ if T.TYPE_CHECKING:
from ..environment import Environment
from ..linkers import DynamicLinker # noqa: F401
CompilerType = T.TypeVar('CompilerType', bound=Compiler)
"""This file contains the data files of all compilers Meson knows
about. To support a new compiler, add its information below.
Also add corresponding autodetection code in environment.py."""

@ -21,7 +21,7 @@ from . import optinterpreter
from . import compilers
from .wrap import wrap, WrapMode
from . import mesonlib
from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep
from .mesonlib import FileMode, MachineChoice, Popen_safe, listify, extract_as_list, has_path_sep, unholder
from .dependencies import ExternalProgram
from .dependencies import InternalDependency, Dependency, NotFoundDependency, DependencyException
from .depfile import DepFile
@ -2460,11 +2460,11 @@ class Interpreter(InterpreterBase):
if not isinstance(version, str):
raise InterpreterException('Version must be a string.')
incs = self.extract_incdirs(kwargs)
libs = extract_as_list(kwargs, 'link_with', unholder=True)
libs_whole = extract_as_list(kwargs, 'link_whole', unholder=True)
libs = unholder(extract_as_list(kwargs, 'link_with'))
libs_whole = unholder(extract_as_list(kwargs, 'link_whole'))
sources = extract_as_list(kwargs, 'sources')
sources = listify(self.source_strings_to_files(sources), unholder=True)
deps = extract_as_list(kwargs, 'dependencies', unholder=True)
sources = unholder(listify(self.source_strings_to_files(sources)))
deps = unholder(extract_as_list(kwargs, 'dependencies'))
compile_args = mesonlib.stringlistify(kwargs.get('compile_args', []))
link_args = mesonlib.stringlistify(kwargs.get('link_args', []))
variables = kwargs.get('variables', {})
@ -3581,12 +3581,12 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
if 'command' not in kwargs:
raise InterpreterException('Missing "command" keyword argument')
all_args = extract_as_list(kwargs, 'command')
deps = extract_as_list(kwargs, 'depends', unholder=True)
deps = unholder(extract_as_list(kwargs, 'depends'))
else:
raise InterpreterException('Run_target needs at least one positional argument.')
cleaned_args = []
for i in listify(all_args, unholder=True):
for i in unholder(listify(all_args)):
if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)):
mlog.debug('Wrong type:', str(i))
raise InterpreterException('Invalid argument to run_target.')
@ -3617,7 +3617,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
name = args[0]
if not isinstance(name, str):
raise InterpreterException('First argument must be a string.')
deps = listify(args[1:], unholder=True)
deps = unholder(listify(args[1:]))
for d in deps:
if not isinstance(d, (build.BuildTarget, build.CustomTarget)):
raise InterpreterException('Depends items must be build targets.')
@ -3675,7 +3675,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
par = kwargs.get('is_parallel', True)
if not isinstance(par, bool):
raise InterpreterException('Keyword argument is_parallel must be a boolean.')
cmd_args = extract_as_list(kwargs, 'args', unholder=True)
cmd_args = unholder(extract_as_list(kwargs, 'args'))
for i in cmd_args:
if not isinstance(i, (str, mesonlib.File, build.Target)):
raise InterpreterException('Command line arguments must be strings, files or targets.')
@ -3703,7 +3703,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
if len(s) > 0:
s = ':' + s
suite.append(prj.replace(' ', '_').replace(':', '_') + s)
depends = extract_as_list(kwargs, 'depends', unholder=True)
depends = unholder(extract_as_list(kwargs, 'depends'))
for dep in depends:
if not isinstance(dep, (build.CustomTarget, build.BuildTarget)):
raise InterpreterException('Depends items must be build targets.')
@ -4066,7 +4066,7 @@ This will become a hard error in the future.''' % kwargs['input'], location=self
return mesonlib.File.from_built_file(self.subdir, output)
def extract_incdirs(self, kwargs):
prospectives = listify(kwargs.get('include_directories', []), unholder=True)
prospectives = unholder(extract_as_list(kwargs, 'include_directories'))
result = []
for p in prospectives:
if isinstance(p, build.IncludeDirs):
@ -4127,7 +4127,7 @@ different subdirectory.
if ":" not in setup_name:
setup_name = (self.subproject if self.subproject else self.build.project_name) + ":" + setup_name
try:
inp = extract_as_list(kwargs, 'exe_wrapper', unholder=True)
inp = unholder(extract_as_list(kwargs, 'exe_wrapper'))
exe_wrapper = []
for i in inp:
if isinstance(i, str):

@ -1058,34 +1058,25 @@ def unholder(item):
return item
def listify(item: T.Any,
flatten: bool = True,
unholder: bool = False) -> T.List[T.Any]:
def listify(item: T.Any, flatten: bool = True) -> T.List[T.Any]:
'''
Returns a list with all args embedded in a list if they are not a list.
This function preserves order.
@flatten: Convert lists of lists to a flat list
@unholder: Replace each item with the object it holds, if required
Note: unholding only works recursively when flattening
'''
if not isinstance(item, list):
if unholder and hasattr(item, 'held_object'):
item = item.held_object
return [item]
result = [] # type: T.List[T.Any]
for i in item:
if unholder and hasattr(i, 'held_object'):
i = i.held_object
if flatten and isinstance(i, list):
result += listify(i, flatten=True, unholder=unholder)
result += listify(i, flatten=True)
else:
result.append(i)
return result
def extract_as_list(dict_object: T.Dict[_T, _U], *keys: _T, pop: bool = False,
**kwargs: T.Any) -> T.List[T.Union[_U, T.List[_U]]]:
flatten: bool = True) -> T.List[T.Union[_U, T.List[_U]]]:
'''
Extracts all values from given dict_object and listifies them.
'''
@ -1095,10 +1086,10 @@ def extract_as_list(dict_object: T.Dict[_T, _U], *keys: _T, pop: bool = False,
fetch = dict_object.pop
# If there's only one key, we don't return a list with one element
if len(keys) == 1:
return listify(fetch(keys[0], []), **kwargs)
return listify(fetch(keys[0], []), flatten=True)
# Return a list of values corresponding to *keys
for key in keys:
result.append(listify(fetch(key, []), **kwargs))
result.append(listify(fetch(key, []), flatten=True))
return result

@ -316,7 +316,7 @@ class GnomeModule(ExtensionModule):
# require two args in order, such as -framework AVFoundation
external_ldflags_nodedup = []
gi_includes = OrderedSet()
deps = mesonlib.listify(deps, unholder=True)
deps = mesonlib.unholder(mesonlib.listify(deps))
for dep in deps:
if isinstance(dep, InternalDependency):
@ -776,7 +776,7 @@ class GnomeModule(ExtensionModule):
langs_compilers = self._get_girtargets_langs_compilers(girtargets)
cflags, internal_ldflags, external_ldflags = self._get_langs_compilers_flags(state, langs_compilers)
deps = self._get_gir_targets_deps(girtargets)
deps += extract_as_list(kwargs, 'dependencies', pop=True, unholder=True)
deps += mesonlib.unholder(extract_as_list(kwargs, 'dependencies', pop=True))
typelib_includes = self._gather_typelib_includes_and_update_depends(state, deps, depends)
# ldflags will be misinterpreted by gir scanner (showing
# spurious dependencies) but building GStreamer fails if they
@ -1057,7 +1057,7 @@ This will become a hard error in the future.''')
def _get_build_args(self, kwargs, state, depends):
args = []
deps = extract_as_list(kwargs, 'dependencies', unholder=True)
deps = mesonlib.unholder(extract_as_list(kwargs, 'dependencies'))
cflags = []
cflags.extend(mesonlib.stringlistify(kwargs.pop('c_args', [])))
deps_cflags, internal_ldflags, external_ldflags, gi_includes = \

@ -74,7 +74,7 @@ class DependenciesHelper:
def _process_reqs(self, reqs):
'''Returns string names of requirements'''
processed_reqs = []
for obj in mesonlib.listify(reqs, unholder=True):
for obj in mesonlib.unholder(mesonlib.listify(reqs)):
if not isinstance(obj, str):
FeatureNew('pkgconfig.generate requirement from non-string object', '0.46.0').use(self.state.subproject)
if hasattr(obj, 'generated_pc'):
@ -108,7 +108,7 @@ class DependenciesHelper:
self.cflags += mesonlib.stringlistify(cflags)
def _process_libs(self, libs, public):
libs = mesonlib.listify(libs, unholder=True)
libs = mesonlib.unholder(mesonlib.listify(libs))
processed_libs = []
processed_reqs = []
processed_cflags = []

@ -686,12 +686,17 @@ class InternalTests(unittest.TestCase):
self.assertEqual([holder1], listify([holder1]))
self.assertEqual([holder1, 2], listify([holder1, 2]))
self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]]))
self.assertEqual([1], listify(holder1, unholder=True))
self.assertEqual([1], listify([holder1], unholder=True))
self.assertEqual([1, 2], listify([holder1, 2], unholder=True))
self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True))
# Unholding doesn't work recursively when not flattening
self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False))
def test_unholder(self):
unholder = mesonbuild.mesonlib.unholder
holder1 = ObjectHolder(1)
holder3 = ObjectHolder(3)
holders = [holder1, holder3]
self.assertEqual(1, unholder(holder1))
self.assertEqual([1], unholder([holder1]))
self.assertEqual([1, 3], unholder(holders))
def test_extract_as_list(self):
extract = mesonbuild.mesonlib.extract_as_list
@ -704,14 +709,15 @@ class InternalTests(unittest.TestCase):
# Test unholding
holder3 = ObjectHolder(3)
kwargs = {'sources': [1, 2, holder3]}
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True))
self.assertEqual(kwargs, {'sources': [1, 2, holder3]})
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True))
self.assertEqual(kwargs, {})
# Test listification
kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))
# flatten nested lists
kwargs = {'sources': [1, [2, [3]]]}
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', flatten=True))
def test_pkgconfig_module(self):
class Mock:

Loading…
Cancel
Save