Merge pull request #2375 from centricular/gnome-gir-fixes

Fix GNOME gir generation with lists of dependency lists
pull/2414/head
Jussi Pakkanen 7 years ago committed by GitHub
commit 357b34f915
  1. 25
      mesonbuild/build.py
  2. 6
      mesonbuild/dependencies/base.py
  3. 4
      mesonbuild/dependencies/dev.py
  4. 172
      mesonbuild/interpreter.py
  5. 59
      mesonbuild/mesonlib.py
  6. 16
      mesonbuild/modules/gnome.py
  7. 45
      run_unittests.py
  8. 2
      test cases/frameworks/7 gnome/gir/meson.build

@ -20,7 +20,7 @@ from . import environment
from . import dependencies from . import dependencies
from . import mlog from . import mlog
from .mesonlib import File, MesonException, listify, extract_as_list from .mesonlib import File, MesonException, listify, extract_as_list
from .mesonlib import flatten, typeslistify, stringlistify, classify_unity_sources from .mesonlib import typeslistify, stringlistify, classify_unity_sources
from .mesonlib import get_filenames_templates_dict, substitute_values from .mesonlib import get_filenames_templates_dict, substitute_values
from .environment import for_windows, for_darwin, for_cygwin from .environment import for_windows, for_darwin, for_cygwin
from .compilers import is_object, clike_langs, sort_clike, lang_suffixes from .compilers import is_object, clike_langs, sort_clike, lang_suffixes
@ -682,7 +682,7 @@ class BuildTarget(Target):
if 'd' in self.compilers: if 'd' in self.compilers:
self.add_compiler_args('d', self.compilers['d'].get_feature_args(dfeatures)) self.add_compiler_args('d', self.compilers['d'].get_feature_args(dfeatures))
self.link_args = flatten(kwargs.get('link_args', [])) self.link_args = extract_as_list(kwargs, 'link_args')
for i in self.link_args: for i in self.link_args:
if not isinstance(i, str): if not isinstance(i, str):
raise InvalidArguments('Link_args arguments must be strings.') raise InvalidArguments('Link_args arguments must be strings.')
@ -856,9 +856,7 @@ You probably should put it in link_with instead.''')
return self.external_deps return self.external_deps
def link(self, target): def link(self, target):
for t in flatten(target): for t in listify(target, unholder=True):
if hasattr(t, 'held_object'):
t = t.held_object
if not t.is_linkable_target(): if not t.is_linkable_target():
raise InvalidArguments('Link target {!r} is not linkable.'.format(t)) raise InvalidArguments('Link target {!r} is not linkable.'.format(t))
if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic: if isinstance(self, SharedLibrary) and isinstance(t, StaticLibrary) and not t.pic:
@ -870,9 +868,7 @@ You probably should put it in link_with instead.''')
self.link_targets.append(t) self.link_targets.append(t)
def link_whole(self, target): def link_whole(self, target):
for t in flatten(target): for t in listify(target, unholder=True):
if hasattr(t, 'held_object'):
t = t.held_object
if not isinstance(t, StaticLibrary): if not isinstance(t, StaticLibrary):
raise InvalidArguments('{!r} is not a static library.'.format(t)) raise InvalidArguments('{!r} is not a static library.'.format(t))
if isinstance(self, SharedLibrary) and not t.pic: if isinstance(self, SharedLibrary) and not t.pic:
@ -915,7 +911,7 @@ You probably should put it in link_with instead.''')
self.include_dirs += ids self.include_dirs += ids
def add_compiler_args(self, language, args): def add_compiler_args(self, language, args):
args = flatten(args) args = listify(args)
for a in args: for a in args:
if not isinstance(a, (str, File)): if not isinstance(a, (str, File)):
raise InvalidArguments('A non-string passed to compiler args.') raise InvalidArguments('A non-string passed to compiler args.')
@ -1546,11 +1542,9 @@ class CustomTarget(Target):
return deps return deps
def flatten_command(self, cmd): def flatten_command(self, cmd):
cmd = listify(cmd) cmd = listify(cmd, unholder=True)
final_cmd = [] final_cmd = []
for c in cmd: for c in cmd:
if hasattr(c, 'held_object'):
c = c.held_object
if isinstance(c, str): if isinstance(c, str):
final_cmd.append(c) final_cmd.append(c)
elif isinstance(c, File): elif isinstance(c, File):
@ -1573,12 +1567,7 @@ class CustomTarget(Target):
def process_kwargs(self, kwargs): def process_kwargs(self, kwargs):
super().process_kwargs(kwargs) super().process_kwargs(kwargs)
sources = flatten(kwargs.get('input', [])) self.sources = extract_as_list(kwargs, 'input', unholder=True)
self.sources = []
for s in sources:
if hasattr(s, 'held_object'):
s = s.held_object
self.sources.append(s)
if 'output' not in kwargs: if 'output' not in kwargs:
raise InvalidArguments('Missing keyword argument "output".') raise InvalidArguments('Missing keyword argument "output".')
self.outputs = listify(kwargs['output']) self.outputs = listify(kwargs['output'])

@ -23,7 +23,7 @@ from enum import Enum
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
from ..mesonlib import MesonException, Popen_safe, flatten, version_compare_many, listify from ..mesonlib import MesonException, Popen_safe, version_compare_many, listify
# These must be defined in this file to avoid cyclical references. # These must be defined in this file to avoid cyclical references.
@ -586,7 +586,7 @@ class ExtraFrameworkDependency(ExternalDependency):
def get_dep_identifier(name, kwargs, want_cross): def get_dep_identifier(name, kwargs, want_cross):
# Need immutable objects since the identifier will be used as a dict key # Need immutable objects since the identifier will be used as a dict key
version_reqs = flatten(kwargs.get('version', [])) version_reqs = listify(kwargs.get('version', []))
if isinstance(version_reqs, list): if isinstance(version_reqs, list):
version_reqs = frozenset(version_reqs) version_reqs = frozenset(version_reqs)
identifier = (name, version_reqs, want_cross) identifier = (name, version_reqs, want_cross)
@ -599,7 +599,7 @@ def get_dep_identifier(name, kwargs, want_cross):
continue continue
# All keyword arguments are strings, ints, or lists (or lists of lists) # All keyword arguments are strings, ints, or lists (or lists of lists)
if isinstance(value, list): if isinstance(value, list):
value = frozenset(flatten(value)) value = frozenset(listify(value))
identifier += (key, value) identifier += (key, value)
return identifier return identifier

@ -21,7 +21,7 @@ import shutil
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
from ..mesonlib import version_compare, Popen_safe from ..mesonlib import version_compare, Popen_safe, stringlistify, extract_as_list
from .base import DependencyException, ExternalDependency, PkgConfigDependency from .base import DependencyException, ExternalDependency, PkgConfigDependency
class GTestDependency(ExternalDependency): class GTestDependency(ExternalDependency):
@ -185,7 +185,7 @@ class LLVMDependency(ExternalDependency):
raise DependencyException('Could not generate modules for LLVM.') raise DependencyException('Could not generate modules for LLVM.')
self.modules = shlex.split(out) self.modules = shlex.split(out)
modules = mesonlib.stringlistify(mesonlib.flatten(kwargs.get('modules', []))) modules = stringlistify(extract_as_list(kwargs, 'modules'))
for mod in sorted(set(modules)): for mod in sorted(set(modules)):
if mod not in self.modules: if mod not in self.modules:
mlog.log('LLVM module', mod, 'found:', mlog.red('NO')) mlog.log('LLVM module', mod, 'found:', mlog.red('NO'))

@ -48,6 +48,14 @@ def stringifyUserArguments(args):
raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.') raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
class ObjectHolder:
def __init__(self, obj):
self.held_object = obj
def __repr__(self):
return '<Holder: {!r}>'.format(self.held_object)
class TryRunResultHolder(InterpreterObject): class TryRunResultHolder(InterpreterObject):
def __init__(self, res): def __init__(self, res):
super().__init__() super().__init__()
@ -117,17 +125,18 @@ class RunProcess(InterpreterObject):
def stderr_method(self, args, kwargs): def stderr_method(self, args, kwargs):
return self.stderr return self.stderr
class ConfigureFileHolder(InterpreterObject): class ConfigureFileHolder(InterpreterObject, ObjectHolder):
def __init__(self, subdir, sourcename, targetname, configuration_data): def __init__(self, subdir, sourcename, targetname, configuration_data):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data) ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
targetname, configuration_data))
class EnvironmentVariablesHolder(MutableInterpreterObject): class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self): def __init__(self):
super().__init__() MutableInterpreterObject.__init__(self)
self.held_object = build.EnvironmentVariables() ObjectHolder.__init__(self, build.EnvironmentVariables())
self.methods.update({'set': self.set_method, self.methods.update({'set': self.set_method,
'append': self.append_method, 'append': self.append_method,
'prepend': self.prepend_method, 'prepend': self.prepend_method,
@ -158,11 +167,11 @@ class EnvironmentVariablesHolder(MutableInterpreterObject):
self.add_var(self.held_object.prepend, args, kwargs) self.add_var(self.held_object.prepend, args, kwargs)
class ConfigurationDataHolder(MutableInterpreterObject): class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self): def __init__(self):
super().__init__() MutableInterpreterObject.__init__(self)
self.used = False # These objects become immutable after use in configure_file. self.used = False # These objects become immutable after use in configure_file.
self.held_object = build.ConfigurationData() ObjectHolder.__init__(self, build.ConfigurationData())
self.methods.update({'set': self.set_method, self.methods.update({'set': self.set_method,
'set10': self.set10_method, 'set10': self.set10_method,
'set_quoted': self.set_quoted_method, 'set_quoted': self.set_quoted_method,
@ -242,10 +251,10 @@ class ConfigurationDataHolder(MutableInterpreterObject):
# Interpreter objects can not be pickled so we must have # Interpreter objects can not be pickled so we must have
# these wrappers. # these wrappers.
class DependencyHolder(InterpreterObject): class DependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep): def __init__(self, dep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = dep ObjectHolder.__init__(self, dep)
self.methods.update({'found': self.found_method, self.methods.update({'found': self.found_method,
'type_name': self.type_name_method, 'type_name': self.type_name_method,
'version': self.version_method, 'version': self.version_method,
@ -272,10 +281,10 @@ class DependencyHolder(InterpreterObject):
raise InterpreterException('Variable name must be a string.') raise InterpreterException('Variable name must be a string.')
return self.held_object.get_pkgconfig_variable(varname) return self.held_object.get_pkgconfig_variable(varname)
class InternalDependencyHolder(InterpreterObject): class InternalDependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep): def __init__(self, dep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = dep ObjectHolder.__init__(self, dep)
self.methods.update({'found': self.found_method, self.methods.update({'found': self.found_method,
'version': self.version_method, 'version': self.version_method,
}) })
@ -286,10 +295,10 @@ class InternalDependencyHolder(InterpreterObject):
def version_method(self, args, kwargs): def version_method(self, args, kwargs):
return self.held_object.get_version() return self.held_object.get_version()
class ExternalProgramHolder(InterpreterObject): class ExternalProgramHolder(InterpreterObject, ObjectHolder):
def __init__(self, ep): def __init__(self, ep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = ep ObjectHolder.__init__(self, ep)
self.methods.update({'found': self.found_method, self.methods.update({'found': self.found_method,
'path': self.path_method}) 'path': self.path_method})
@ -308,10 +317,10 @@ class ExternalProgramHolder(InterpreterObject):
def get_name(self): def get_name(self):
return self.held_object.get_name() return self.held_object.get_name()
class ExternalLibraryHolder(InterpreterObject): class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
def __init__(self, el): def __init__(self, el):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = el ObjectHolder.__init__(self, el)
self.methods.update({'found': self.found_method}) self.methods.update({'found': self.found_method})
def found(self): def found(self):
@ -332,11 +341,11 @@ class ExternalLibraryHolder(InterpreterObject):
def get_exe_args(self): def get_exe_args(self):
return self.held_object.get_exe_args() return self.held_object.get_exe_args()
class GeneratorHolder(InterpreterObject): class GeneratorHolder(InterpreterObject, ObjectHolder):
def __init__(self, interpreter, args, kwargs): def __init__(self, interpreter, args, kwargs):
super().__init__() InterpreterObject.__init__(self)
self.interpreter = interpreter self.interpreter = interpreter
self.held_object = build.Generator(args, kwargs) ObjectHolder.__init__(self, build.Generator(args, kwargs))
self.methods.update({'process': self.process_method}) self.methods.update({'process': self.process_method})
def process_method(self, args, kwargs): def process_method(self, args, kwargs):
@ -345,13 +354,13 @@ class GeneratorHolder(InterpreterObject):
return GeneratedListHolder(gl) return GeneratedListHolder(gl)
class GeneratedListHolder(InterpreterObject): class GeneratedListHolder(InterpreterObject, ObjectHolder):
def __init__(self, arg1, extra_args=[]): def __init__(self, arg1, extra_args=[]):
super().__init__() InterpreterObject.__init__(self)
if isinstance(arg1, GeneratorHolder): if isinstance(arg1, GeneratorHolder):
self.held_object = build.GeneratedList(arg1.held_object, extra_args) ObjectHolder.__init__(self, build.GeneratedList(arg1.held_object, extra_args))
else: else:
self.held_object = arg1 ObjectHolder.__init__(self, arg1)
def __repr__(self): def __repr__(self):
r = '<{}: {!r}>' r = '<{}: {!r}>'
@ -360,14 +369,15 @@ class GeneratedListHolder(InterpreterObject):
def add_file(self, a): def add_file(self, a):
self.held_object.add_file(a) self.held_object.add_file(a)
class BuildMachine(InterpreterObject): class BuildMachine(InterpreterObject, ObjectHolder):
def __init__(self, compilers): def __init__(self, compilers):
self.compilers = compilers self.compilers = compilers
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = environment.MachineInfo(environment.detect_system(), held_object = environment.MachineInfo(environment.detect_system(),
environment.detect_cpu_family(self.compilers), environment.detect_cpu_family(self.compilers),
environment.detect_cpu(self.compilers), environment.detect_cpu(self.compilers),
sys.byteorder) sys.byteorder)
ObjectHolder.__init__(self, held_object)
self.methods.update({'system': self.system_method, self.methods.update({'system': self.system_method,
'cpu_family': self.cpu_family_method, 'cpu_family': self.cpu_family_method,
'cpu': self.cpu_method, 'cpu': self.cpu_method,
@ -388,7 +398,7 @@ class BuildMachine(InterpreterObject):
# This class will provide both host_machine and # This class will provide both host_machine and
# target_machine # target_machine
class CrossMachineInfo(InterpreterObject): class CrossMachineInfo(InterpreterObject, ObjectHolder):
def __init__(self, cross_info): def __init__(self, cross_info):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'} minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'}
@ -397,10 +407,11 @@ class CrossMachineInfo(InterpreterObject):
'Machine info is currently {}\n'.format(cross_info) + 'Machine info is currently {}\n'.format(cross_info) +
'but is missing {}.'.format(minimum_cross_info - set(cross_info))) 'but is missing {}.'.format(minimum_cross_info - set(cross_info)))
self.info = cross_info self.info = cross_info
self.held_object = environment.MachineInfo(cross_info['system'], minfo = environment.MachineInfo(cross_info['system'],
cross_info['cpu_family'], cross_info['cpu_family'],
cross_info['cpu'], cross_info['cpu'],
cross_info['endian']) cross_info['endian'])
ObjectHolder.__init__(self, minfo)
self.methods.update({'system': self.system_method, self.methods.update({'system': self.system_method,
'cpu': self.cpu_method, 'cpu': self.cpu_method,
'cpu_family': self.cpu_family_method, 'cpu_family': self.cpu_family_method,
@ -419,10 +430,10 @@ class CrossMachineInfo(InterpreterObject):
def endian_method(self, args, kwargs): def endian_method(self, args, kwargs):
return self.held_object.endian return self.held_object.endian
class IncludeDirsHolder(InterpreterObject): class IncludeDirsHolder(InterpreterObject, ObjectHolder):
def __init__(self, idobj): def __init__(self, idobj):
super().__init__() InterpreterObject.__init__(self)
self.held_object = idobj ObjectHolder.__init__(self, idobj)
class Headers(InterpreterObject): class Headers(InterpreterObject):
@ -447,10 +458,10 @@ class Headers(InterpreterObject):
def get_custom_install_dir(self): def get_custom_install_dir(self):
return self.custom_install_dir return self.custom_install_dir
class DataHolder(InterpreterObject): class DataHolder(InterpreterObject, ObjectHolder):
def __init__(self, data): def __init__(self, data):
super().__init__() InterpreterObject.__init__(self)
self.held_object = data ObjectHolder.__init__(self, data)
def get_source_subdir(self): def get_source_subdir(self):
return self.held_object.source_subdir return self.held_object.source_subdir
@ -495,20 +506,20 @@ class Man(InterpreterObject):
def get_sources(self): def get_sources(self):
return self.sources return self.sources
class GeneratedObjectsHolder(InterpreterObject): class GeneratedObjectsHolder(InterpreterObject, ObjectHolder):
def __init__(self, held_object): def __init__(self, held_object):
super().__init__() InterpreterObject.__init__(self)
self.held_object = held_object ObjectHolder.__init__(self, held_object)
class TargetHolder(InterpreterObject): class TargetHolder(InterpreterObject, ObjectHolder):
def __init__(self): def __init__(self, target, interp):
super().__init__() InterpreterObject.__init__(self)
ObjectHolder.__init__(self, target)
self.interpreter = interp
class BuildTargetHolder(TargetHolder): class BuildTargetHolder(TargetHolder):
def __init__(self, target, interp): def __init__(self, target, interp):
super().__init__() super().__init__(target, interp)
self.held_object = target
self.interpreter = interp
self.methods.update({'extract_objects': self.extract_objects_method, self.methods.update({'extract_objects': self.extract_objects_method,
'extract_all_objects': self.extract_all_objects_method, 'extract_all_objects': self.extract_all_objects_method,
'get_id': self.get_id_method, 'get_id': self.get_id_method,
@ -566,16 +577,14 @@ class JarHolder(BuildTargetHolder):
def __init__(self, target, interp): def __init__(self, target, interp):
super().__init__(target, interp) super().__init__(target, interp)
class CustomTargetIndexHolder(InterpreterObject): class CustomTargetIndexHolder(InterpreterObject, ObjectHolder):
def __init__(self, object_to_hold): def __init__(self, object_to_hold):
super().__init__() InterpreterObject.__init__(self)
self.held_object = object_to_hold ObjectHolder.__init__(self, object_to_hold)
class CustomTargetHolder(TargetHolder): class CustomTargetHolder(TargetHolder):
def __init__(self, object_to_hold, interp): def __init__(self, target, interp):
super().__init__() super().__init__(target, interp)
self.held_object = object_to_hold
self.interpreter = interp
self.methods.update({'full_path': self.full_path_method, self.methods.update({'full_path': self.full_path_method,
}) })
@ -596,10 +605,10 @@ class CustomTargetHolder(TargetHolder):
def __delitem__(self, index): def __delitem__(self, index):
raise InterpreterException('Cannot delete a member of a CustomTarget') raise InterpreterException('Cannot delete a member of a CustomTarget')
class RunTargetHolder(InterpreterObject): class RunTargetHolder(InterpreterObject, ObjectHolder):
def __init__(self, name, command, args, dependencies, subdir): def __init__(self, name, command, args, dependencies, subdir):
super().__init__() InterpreterObject.__init__(self)
self.held_object = build.RunTarget(name, command, args, dependencies, subdir) ObjectHolder.__init__(self, build.RunTarget(name, command, args, dependencies, subdir))
def __repr__(self): def __repr__(self):
r = '<{} {}: {}>' r = '<{} {}: {}>'
@ -625,11 +634,11 @@ class Test(InterpreterObject):
def get_name(self): def get_name(self):
return self.name return self.name
class SubprojectHolder(InterpreterObject): class SubprojectHolder(InterpreterObject, ObjectHolder):
def __init__(self, subinterpreter): def __init__(self, subinterpreter):
super().__init__() InterpreterObject.__init__(self)
self.held_object = subinterpreter ObjectHolder.__init__(self, subinterpreter)
self.methods.update({'get_variable': self.get_variable_method, self.methods.update({'get_variable': self.get_variable_method,
}) })
@ -1056,11 +1065,11 @@ ModuleState = namedtuple('ModuleState', [
'man', 'global_args', 'project_args', 'build_machine', 'host_machine', 'man', 'global_args', 'project_args', 'build_machine', 'host_machine',
'target_machine']) 'target_machine'])
class ModuleHolder(InterpreterObject): class ModuleHolder(InterpreterObject, ObjectHolder):
def __init__(self, modname, module, interpreter): def __init__(self, modname, module, interpreter):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
ObjectHolder.__init__(self, module)
self.modname = modname self.modname = modname
self.held_object = module
self.interpreter = interpreter self.interpreter = interpreter
def method_call(self, method_name, args, kwargs): def method_call(self, method_name, args, kwargs):
@ -1551,12 +1560,11 @@ class Interpreter(InterpreterBase):
version = kwargs.get('version', self.project_version) version = kwargs.get('version', self.project_version)
if not isinstance(version, str): if not isinstance(version, str):
raise InterpreterException('Version must be a string.') raise InterpreterException('Version must be a string.')
incs = extract_as_list(kwargs, 'include_directories') incs = extract_as_list(kwargs, 'include_directories', unholder=True)
libs = extract_as_list(kwargs, 'link_with') libs = extract_as_list(kwargs, 'link_with', unholder=True)
sources = extract_as_list(kwargs, 'sources') sources = extract_as_list(kwargs, 'sources')
sources = self.source_strings_to_files(self.flatten(sources)) sources = listify(self.source_strings_to_files(sources), unholder=True)
deps = self.flatten(kwargs.get('dependencies', [])) deps = extract_as_list(kwargs, 'dependencies', unholder=True)
deps = listify(deps)
compile_args = mesonlib.stringlistify(kwargs.get('compile_args', [])) compile_args = mesonlib.stringlistify(kwargs.get('compile_args', []))
link_args = mesonlib.stringlistify(kwargs.get('link_args', [])) link_args = mesonlib.stringlistify(kwargs.get('link_args', []))
final_deps = [] final_deps = []
@ -1568,13 +1576,8 @@ class Interpreter(InterpreterBase):
if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)): if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)):
raise InterpreterException('Dependencies must be external deps') raise InterpreterException('Dependencies must be external deps')
final_deps.append(d) final_deps.append(d)
dep = dependencies.InternalDependency(version, dep = dependencies.InternalDependency(version, incs, compile_args,
mesonlib.unholder_array(incs), link_args, libs, sources, final_deps)
compile_args,
link_args,
mesonlib.unholder_array(libs),
mesonlib.unholder_array(sources),
final_deps)
return DependencyHolder(dep) return DependencyHolder(dep)
@noKwargs @noKwargs
@ -1629,7 +1632,7 @@ class Interpreter(InterpreterBase):
'or not executable'.format(cmd)) 'or not executable'.format(cmd))
cmd = prog cmd = prog
expanded_args = [] expanded_args = []
for a in mesonlib.flatten(cargs): for a in listify(cargs):
if isinstance(a, str): if isinstance(a, str):
expanded_args.append(a) expanded_args.append(a)
elif isinstance(a, mesonlib.File): elif isinstance(a, mesonlib.File):
@ -2299,11 +2302,7 @@ to directly access options of other subprojects.''')
raise InterpreterException('Run_target needs at least one positional argument.') raise InterpreterException('Run_target needs at least one positional argument.')
cleaned_args = [] cleaned_args = []
for i in mesonlib.flatten(all_args): for i in listify(all_args, unholder=True):
try:
i = i.held_object
except AttributeError:
pass
if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)): if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)):
mlog.debug('Wrong type:', str(i)) mlog.debug('Wrong type:', str(i))
raise InterpreterException('Invalid argument to run_target.') raise InterpreterException('Invalid argument to run_target.')
@ -2374,11 +2373,10 @@ to directly access options of other subprojects.''')
par = kwargs.get('is_parallel', True) par = kwargs.get('is_parallel', True)
if not isinstance(par, bool): if not isinstance(par, bool):
raise InterpreterException('Keyword argument is_parallel must be a boolean.') raise InterpreterException('Keyword argument is_parallel must be a boolean.')
cmd_args = extract_as_list(kwargs, 'args') cmd_args = extract_as_list(kwargs, 'args', unholder=True)
for i in cmd_args: for i in cmd_args:
if not isinstance(i, (str, mesonlib.File, TargetHolder)): if not isinstance(i, (str, mesonlib.File, build.Target)):
raise InterpreterException('Command line arguments must be strings, files or targets.') raise InterpreterException('Command line arguments must be strings, files or targets.')
cmd_args = mesonlib.unholder_array(cmd_args)
env = self.unpack_env_kwarg(kwargs) env = self.unpack_env_kwarg(kwargs)
should_fail = kwargs.get('should_fail', False) should_fail = kwargs.get('should_fail', False)
if not isinstance(should_fail, bool): if not isinstance(should_fail, bool):
@ -2796,7 +2794,8 @@ different subdirectory.
elif isinstance(s, str): elif isinstance(s, str):
s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s) s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s)
else: else:
raise InterpreterException("Source item is not string or File-type object.") raise InterpreterException('Source item is {!r} instead of '
'string or File-type object'.format(s))
results.append(s) results.append(s)
return results return results
@ -2822,7 +2821,7 @@ different subdirectory.
if not args: if not args:
raise InterpreterException('Target does not have a name.') raise InterpreterException('Target does not have a name.')
name = args[0] name = args[0]
sources = args[1:] sources = listify(args[1:])
if self.environment.is_cross_build(): if self.environment.is_cross_build():
if kwargs.get('native', False): if kwargs.get('native', False):
is_cross = False is_cross = False
@ -2830,19 +2829,14 @@ different subdirectory.
is_cross = True is_cross = True
else: else:
is_cross = False is_cross = False
try: if 'sources' in kwargs:
kw_src = self.flatten(kwargs['sources']) sources += listify(kwargs['sources'])
kw_src = listify(kw_src)
except KeyError:
kw_src = []
sources += kw_src
sources = self.source_strings_to_files(sources) sources = self.source_strings_to_files(sources)
objs = self.flatten(kwargs.get('objects', [])) objs = extract_as_list(kwargs, 'objects')
kwargs['dependencies'] = self.flatten(kwargs.get('dependencies', [])) kwargs['dependencies'] = extract_as_list(kwargs, 'dependencies')
if 'extra_files' in kwargs: if 'extra_files' in kwargs:
ef = extract_as_list(kwargs, 'extra_files') ef = extract_as_list(kwargs, 'extra_files')
kwargs['extra_files'] = self.source_strings_to_files(ef) kwargs['extra_files'] = self.source_strings_to_files(ef)
objs = listify(objs)
self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources) self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources)
if targetholder is ExecutableHolder: if targetholder is ExecutableHolder:
targetclass = build.Executable targetclass = build.Executable

@ -199,17 +199,6 @@ def classify_unity_sources(compilers, sources):
compsrclist[comp].append(src) compsrclist[comp].append(src)
return compsrclist return compsrclist
def flatten(item):
if not isinstance(item, list):
return [item]
result = []
for i in item:
if isinstance(i, list):
result += flatten(i)
else:
result.append(i)
return result
def is_osx(): def is_osx():
return platform.system().lower() == 'darwin' return platform.system().lower() == 'darwin'
@ -474,24 +463,45 @@ def replace_if_different(dst, dst_tmp):
else: else:
os.unlink(dst_tmp) os.unlink(dst_tmp)
def listify(item, flatten=True, unholder=False):
def listify(*args):
''' '''
Returns a list with all args embedded in a list if they are not of type list. Returns a list with all args embedded in a list if they are not a list.
This function preserves order. 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 len(args) == 1: # Special case with one single arg if not isinstance(item, list):
return args[0] if type(args[0]) is list else [args[0]] if unholder and hasattr(item, 'held_object'):
return [item if type(item) is list else [item] for item in args] item = item.held_object
return [item]
result = []
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)
else:
result.append(i)
return result
def extract_as_list(dict_object, *keys, pop = False): def extract_as_list(dict_object, *keys, pop=False, **kwargs):
''' '''
Extracts all values from given dict_object and listifies them. Extracts all values from given dict_object and listifies them.
''' '''
result = []
fetch = dict_object.get
if pop: if pop:
return listify(*[dict_object.pop(key, []) for key in keys]) fetch = dict_object.pop
return listify(*[dict_object.get(key, []) for key in keys]) # 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 a list of values corresponding to *keys
for key in keys:
result.append(listify(fetch(key, []), **kwargs))
return result
def typeslistify(item, types): def typeslistify(item, types):
@ -750,15 +760,6 @@ def windows_proof_rmtree(f):
# Try one last time and throw if it fails. # Try one last time and throw if it fails.
shutil.rmtree(f) shutil.rmtree(f)
def unholder_array(entries):
result = []
entries = flatten(entries)
for e in entries:
if hasattr(e, 'held_object'):
e = e.held_object
result.append(e)
return result
class OrderedSet(collections.MutableSet): class OrderedSet(collections.MutableSet):
"""A set that preserves the order in which items are added, by first """A set that preserves the order in which items are added, by first
insertion. insertion.

@ -20,7 +20,7 @@ import os
import copy import copy
import subprocess import subprocess
from . import ModuleReturnValue from . import ModuleReturnValue
from ..mesonlib import MesonException, OrderedSet, Popen_safe from ..mesonlib import MesonException, OrderedSet, Popen_safe, extract_as_list
from ..dependencies import Dependency, PkgConfigDependency, InternalDependency from ..dependencies import Dependency, PkgConfigDependency, InternalDependency
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
@ -323,11 +323,9 @@ class GnomeModule(ExtensionModule):
cflags = OrderedSet() cflags = OrderedSet()
ldflags = OrderedSet() ldflags = OrderedSet()
gi_includes = OrderedSet() gi_includes = OrderedSet()
deps = mesonlib.listify(deps) deps = mesonlib.listify(deps, unholder=True)
for dep in deps: for dep in deps:
if hasattr(dep, 'held_object'):
dep = dep.held_object
if isinstance(dep, InternalDependency): if isinstance(dep, InternalDependency):
cflags.update(get_include_args(dep.include_directories)) cflags.update(get_include_args(dep.include_directories))
for lib in dep.libraries: for lib in dep.libraries:
@ -378,7 +376,7 @@ class GnomeModule(ExtensionModule):
elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
cflags.update(get_include_args(dep.get_include_dirs())) cflags.update(get_include_args(dep.get_include_dirs()))
else: else:
mlog.log('dependency %s not handled to build gir files' % dep) mlog.log('dependency {!r} not handled to build gir files'.format(dep))
continue continue
if gir_has_extra_lib_arg() and use_gir_args: if gir_has_extra_lib_arg() and use_gir_args:
@ -417,7 +415,7 @@ class GnomeModule(ExtensionModule):
raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.') raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.')
ns = kwargs.pop('namespace') ns = kwargs.pop('namespace')
nsversion = kwargs.pop('nsversion') nsversion = kwargs.pop('nsversion')
libsources = mesonlib.flatten(kwargs.pop('sources')) libsources = mesonlib.extract_as_list(kwargs, 'sources', pop=True)
girfile = '%s-%s.gir' % (ns, nsversion) girfile = '%s-%s.gir' % (ns, nsversion)
srcdir = os.path.join(state.environment.get_source_dir(), state.subdir) srcdir = os.path.join(state.environment.get_source_dir(), state.subdir)
builddir = os.path.join(state.environment.get_build_dir(), state.subdir) builddir = os.path.join(state.environment.get_build_dir(), state.subdir)
@ -531,9 +529,8 @@ class GnomeModule(ExtensionModule):
else: else:
raise MesonException('Gir export packages must be str or list') raise MesonException('Gir export packages must be str or list')
deps = mesonlib.extract_as_list(kwargs, 'dependencies', pop = True)
deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() + deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() +
deps) extract_as_list(kwargs, 'dependencies', pop=True, unholder=True))
# Need to recursively add deps on GirTarget sources from our # Need to recursively add deps on GirTarget sources from our
# dependencies and also find the include directories needed for the # dependencies and also find the include directories needed for the
# typelib generation custom target below. # typelib generation custom target below.
@ -800,7 +797,8 @@ This will become a hard error in the future.''')
def _get_build_args(self, kwargs, state): def _get_build_args(self, kwargs, state):
args = [] args = []
cflags, ldflags, gi_includes = self._get_dependencies_flags(kwargs.get('dependencies', []), state, include_rpath=True) deps = extract_as_list(kwargs, 'dependencies', unholder=True)
cflags, ldflags, gi_includes = self._get_dependencies_flags(deps, state, include_rpath=True)
inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories') inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories')
for incd in inc_dirs: for incd in inc_dirs:
if not isinstance(incd.held_object, (str, build.IncludeDirs)): if not isinstance(incd.held_object, (str, build.IncludeDirs)):

@ -31,6 +31,7 @@ import mesonbuild.compilers
import mesonbuild.environment import mesonbuild.environment
import mesonbuild.mesonlib import mesonbuild.mesonlib
import mesonbuild.coredata import mesonbuild.coredata
from mesonbuild.interpreter import ObjectHolder
from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree
from mesonbuild.environment import Environment from mesonbuild.environment import Environment
from mesonbuild.dependencies import DependencyException from mesonbuild.dependencies import DependencyException
@ -62,7 +63,6 @@ def get_soname(fname):
def get_rpath(fname): def get_rpath(fname):
return get_dynamic_section_entry(fname, r'(?:rpath|runpath)') return get_dynamic_section_entry(fname, r'(?:rpath|runpath)')
class InternalTests(unittest.TestCase): class InternalTests(unittest.TestCase):
def test_version_number(self): def test_version_number(self):
@ -398,6 +398,49 @@ class InternalTests(unittest.TestCase):
self.assertEqual(forced_value, desired_value) self.assertEqual(forced_value, desired_value)
def test_listify(self):
listify = mesonbuild.mesonlib.listify
# Test sanity
self.assertEqual([1], listify(1))
self.assertEqual([], listify([]))
self.assertEqual([1], listify([1]))
# Test flattening
self.assertEqual([1, 2, 3], listify([1, [2, 3]]))
self.assertEqual([1, 2, 3], listify([1, [2, [3]]]))
self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False))
# Test flattening and unholdering
holder1 = ObjectHolder(1)
holder3 = ObjectHolder(3)
self.assertEqual([holder1], listify(holder1))
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_extract_as_list(self):
extract = mesonbuild.mesonlib.extract_as_list
# Test sanity
kwargs = {'sources': [1, 2, 3]}
self.assertEqual([1, 2, 3], extract(kwargs, 'sources'))
self.assertEqual(kwargs, {'sources': [1, 2, 3]})
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True))
self.assertEqual(kwargs, {})
# 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'))
class BasePlatformTests(unittest.TestCase): class BasePlatformTests(unittest.TestCase):
def setUp(self): def setUp(self):

@ -27,7 +27,7 @@ gnome.generate_gir(
identifier_prefix : 'Meson', identifier_prefix : 'Meson',
includes : ['GObject-2.0', 'MesonDep1-1.0'], includes : ['GObject-2.0', 'MesonDep1-1.0'],
# dep1_dep pulls in dep2_dep for us # dep1_dep pulls in dep2_dep for us
dependencies : [fake_dep, dep1_dep], dependencies : [[fake_dep, dep1_dep]],
install : true, install : true,
build_by_default : true, build_by_default : true,
# Test that unknown kwargs do not crash the parser. # Test that unknown kwargs do not crash the parser.

Loading…
Cancel
Save