diff options
author | Corentin Noël <corentin@elementary.io> | 2017-10-03 20:26:16 +0200 |
---|---|---|
committer | Corentin Noël <corentin@elementary.io> | 2017-10-03 20:26:16 +0200 |
commit | 1320a98a33e4e9f188e5daa143316b24d0dce819 (patch) | |
tree | 82ea281b163115277e1c9524283b0d371b6c21ac /mesonbuild | |
parent | f13887b64a9d535682668960493158ae15bfbb2d (diff) | |
parent | 0c3d58baba4a61558ed9b4905f26155a3e95cf6c (diff) | |
download | meson-1320a98a33e4e9f188e5daa143316b24d0dce819.zip meson-1320a98a33e4e9f188e5daa143316b24d0dce819.tar.gz meson-1320a98a33e4e9f188e5daa143316b24d0dce819.tar.bz2 |
Merge github.com:mesonbuild/meson into vala-target-dirs
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/backend/backends.py | 24 | ||||
-rw-r--r-- | mesonbuild/build.py | 25 | ||||
-rw-r--r-- | mesonbuild/compilers/c.py | 34 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 39 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 6 | ||||
-rw-r--r-- | mesonbuild/dependencies/dev.py | 4 | ||||
-rw-r--r-- | mesonbuild/dependencies/misc.py | 426 | ||||
-rw-r--r-- | mesonbuild/interpreter.py | 184 | ||||
-rw-r--r-- | mesonbuild/mesonlib.py | 59 | ||||
-rw-r--r-- | mesonbuild/modules/gnome.py | 24 | ||||
-rw-r--r-- | mesonbuild/modules/qt4.py | 10 | ||||
-rw-r--r-- | mesonbuild/modules/qt5.py | 10 |
12 files changed, 553 insertions, 292 deletions
diff --git a/mesonbuild/backend/backends.py b/mesonbuild/backend/backends.py index 61c5e90..61f7535 100644 --- a/mesonbuild/backend/backends.py +++ b/mesonbuild/backend/backends.py @@ -307,6 +307,25 @@ class Backend: raise MesonException(m.format(target.name)) return l + def rpaths_for_bundled_shared_libraries(self, target): + paths = [] + for dep in target.external_deps: + if isinstance(dep, dependencies.ExternalLibrary): + la = dep.link_args + if len(la) == 1 and os.path.isabs(la[0]): + # The only link argument is an absolute path to a library file. + libpath = la[0] + if libpath.startswith(('/usr/lib', '/lib')): + # No point in adding system paths. + continue + if os.path.splitext(libpath)[1] not in ['.dll', '.lib', '.so']: + continue + absdir = os.path.split(libpath)[0] + rel_to_src = absdir[len(self.environment.get_source_dir()) + 1:] + assert(not os.path.isabs(rel_to_src)) + paths.append(os.path.join(self.build_to_src, rel_to_src)) + return paths + def determine_rpath_dirs(self, target): link_deps = target.get_all_link_deps() result = [] @@ -314,6 +333,9 @@ class Backend: prospective = self.get_target_dir(ld) if prospective not in result: result.append(prospective) + for rp in self.rpaths_for_bundled_shared_libraries(target): + if rp not in result: + result += [rp] return result def object_filename_from_source(self, target, source, is_unity): @@ -522,6 +544,8 @@ class Backend: dirseg = os.path.join(self.environment.get_build_dir(), self.get_target_dir(ld)) if dirseg not in result: result.append(dirseg) + for deppath in self.rpaths_for_bundled_shared_libraries(target): + result.append(os.path.normpath(os.path.join(self.environment.get_build_dir(), deppath))) return result def write_benchmark_file(self, datafile): diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 5f5dd6b..9837d5a 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -20,7 +20,7 @@ from . import environment from . import dependencies from . import mlog 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 .environment import for_windows, for_darwin, for_cygwin from .compilers import is_object, clike_langs, sort_clike, lang_suffixes @@ -682,7 +682,7 @@ class BuildTarget(Target): if 'd' in self.compilers: 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: if not isinstance(i, str): 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 def link(self, target): - for t in flatten(target): - if hasattr(t, 'held_object'): - t = t.held_object + for t in listify(target, unholder=True): if not t.is_linkable_target(): raise InvalidArguments('Link target {!r} is not linkable.'.format(t)) 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) def link_whole(self, target): - for t in flatten(target): - if hasattr(t, 'held_object'): - t = t.held_object + for t in listify(target, unholder=True): if not isinstance(t, StaticLibrary): raise InvalidArguments('{!r} is not a static library.'.format(t)) 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 def add_compiler_args(self, language, args): - args = flatten(args) + args = listify(args) for a in args: if not isinstance(a, (str, File)): raise InvalidArguments('A non-string passed to compiler args.') @@ -1546,11 +1542,9 @@ class CustomTarget(Target): return deps def flatten_command(self, cmd): - cmd = listify(cmd) + cmd = listify(cmd, unholder=True) final_cmd = [] for c in cmd: - if hasattr(c, 'held_object'): - c = c.held_object if isinstance(c, str): final_cmd.append(c) elif isinstance(c, File): @@ -1573,12 +1567,7 @@ class CustomTarget(Target): def process_kwargs(self, kwargs): super().process_kwargs(kwargs) - sources = flatten(kwargs.get('input', [])) - self.sources = [] - for s in sources: - if hasattr(s, 'held_object'): - s = s.held_object - self.sources.append(s) + self.sources = extract_as_list(kwargs, 'input', unholder=True) if 'output' not in kwargs: raise InvalidArguments('Missing keyword argument "output".') self.outputs = listify(kwargs['output']) diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 82b1ef0..3f9ba5c 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -172,6 +172,9 @@ class CCompiler(Compiler): def get_linker_search_args(self, dirname): return ['-L' + dirname] + def get_default_include_dirs(self): + return [] + def gen_import_library_args(self, implibname): """ The name of the outputted import library @@ -1056,3 +1059,34 @@ class VisualStudioCCompiler(CCompiler): # and the can not be called. return None return vs32_instruction_set_args.get(instruction_set, None) + + def get_toolset_version(self): + # See boost/config/compiler/visualc.cpp for up to date mapping + try: + version = int(''.join(self.version.split('.')[0:2])) + except: + return None + if version < 1310: + return '7.0' + elif version < 1400: + return '7.1' # (Visual Studio 2003) + elif version < 1500: + return '8.0' # (Visual Studio 2005) + elif version < 1600: + return '9.0' # (Visual Studio 2008) + elif version < 1700: + return '10.0' # (Visual Studio 2010) + elif version < 1800: + return '11.0' # (Visual Studio 2012) + elif version < 1900: + return '12.0' # (Visual Studio 2013) + elif version < 1910: + return '14.0' # (Visual Studio 2015) + elif version < 1920: + return '14.1' # (Visual Studio 2017) + return None + + def get_default_include_dirs(self): + if 'INCLUDE' not in os.environ: + return [] + return os.environ['INCLUDE'].split(os.pathsep) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 89208e0..3f088b0 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -13,6 +13,7 @@ # limitations under the License. import contextlib, os.path, re, tempfile +import subprocess from ..linkers import StaticLinker from .. import coredata @@ -917,6 +918,35 @@ def get_largefile_args(compiler): # those features explicitly. return [] +# TODO: The result from calling compiler should be cached. So that calling this +# function multiple times don't add latency. +def gnulike_default_include_dirs(compiler, lang): + if lang == 'cpp': + lang = 'c++' + p = subprocess.Popen( + compiler + ['-x{}'.format(lang), '-E', '-v', '-'], + stdin=subprocess.DEVNULL, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE + ) + stderr = p.stderr.read().decode('utf-8') + parse_state = 0 + paths = [] + for line in stderr.split('\n'): + if parse_state == 0: + if line == '#include "..." search starts here:': + parse_state = 1 + elif parse_state == 1: + if line == '#include <...> search starts here:': + parse_state = 2 + else: + paths.append(line[1:]) + elif parse_state == 2: + if line == 'End of search list.': + break + else: + paths.append(line[1:]) + return paths class GnuCompiler: # Functionality that is common to all GNU family compilers. @@ -998,6 +1028,9 @@ class GnuCompiler: def get_instruction_set_args(self, instruction_set): return gnulike_instruction_set_args.get(instruction_set, None) + def get_default_include_dirs(self): + return gnulike_default_include_dirs(self.exelist, self.language) + class ClangCompiler: def __init__(self, clang_type): @@ -1082,6 +1115,9 @@ class ClangCompiler: def get_instruction_set_args(self, instruction_set): return gnulike_instruction_set_args.get(instruction_set, None) + def get_default_include_dirs(self): + return gnulike_default_include_dirs(self.exelist, self.language) + # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1 class IntelCompiler: @@ -1132,3 +1168,6 @@ class IntelCompiler: # if self.icc_type == ICC_OSX: # return ['-bundle'] return ['-shared'] + + def get_default_include_dirs(self): + return gnulike_default_include_dirs(self.exelist, self.language) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 7c7f986..0d9742d 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -23,7 +23,7 @@ from enum import Enum from .. import mlog 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. @@ -586,7 +586,7 @@ class ExtraFrameworkDependency(ExternalDependency): def get_dep_identifier(name, kwargs, want_cross): # 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): version_reqs = frozenset(version_reqs) identifier = (name, version_reqs, want_cross) @@ -599,7 +599,7 @@ def get_dep_identifier(name, kwargs, want_cross): continue # All keyword arguments are strings, ints, or lists (or lists of lists) if isinstance(value, list): - value = frozenset(flatten(value)) + value = frozenset(listify(value)) identifier += (key, value) return identifier diff --git a/mesonbuild/dependencies/dev.py b/mesonbuild/dependencies/dev.py index d2dd107..387300a 100644 --- a/mesonbuild/dependencies/dev.py +++ b/mesonbuild/dependencies/dev.py @@ -21,7 +21,7 @@ import shutil from .. import mlog 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 class GTestDependency(ExternalDependency): @@ -185,7 +185,7 @@ class LLVMDependency(ExternalDependency): raise DependencyException('Could not generate modules for LLVM.') 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)): if mod not in self.modules: mlog.log('LLVM module', mod, 'found:', mlog.red('NO')) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index c2b6dbd..a0d5e47 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -18,7 +18,6 @@ import glob import os import re import shlex -import stat import shutil import sysconfig @@ -30,77 +29,153 @@ from ..environment import detect_cpu_family from .base import DependencyException, DependencyMethods from .base import ExternalDependency, ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency +# On windows 3 directory layouts are supported: +# * The default layout (versioned) installed: +# - $BOOST_ROOT/include/boost-x_x/boost/*.hpp +# - $BOOST_ROOT/lib/*.lib +# * The non-default layout (system) installed: +# - $BOOST_ROOT/include/boost/*.hpp +# - $BOOST_ROOT/lib/*.lib +# * The pre-built binaries from sf.net: +# - $BOOST_ROOT/boost/*.hpp +# - $BOOST_ROOT/lib<arch>-<compiler>/*.lib where arch=32/64 and compiler=msvc-14.1 +# +# Library names supported: +# - libboost_<module>-<compiler>-mt-gd-x_x.lib (static) +# - boost_<module>-<compiler>-mt-gd-x_x.lib|.dll (shared) +# - libboost_<module>.lib (static) +# - boost_<module>.lib|.dll (shared) +# where compiler is vc141 for example. +# +# NOTE: -gb means runtime and build time debugging is on +# -mt means threading=multi +# +# The `modules` argument accept library names. This is because every module that +# has libraries to link against also has multiple options regarding how to +# link. See for example: +# * http://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/boost_test/usage_variants.html +# * http://www.boost.org/doc/libs/1_65_1/doc/html/stacktrace/configuration_and_build.html +# * http://www.boost.org/doc/libs/1_65_1/libs/math/doc/html/math_toolkit/main_tr1.html class BoostDependency(ExternalDependency): - # Some boost libraries have different names for - # their sources and libraries. This dict maps - # between the two. - name2lib = {'test': 'unit_test_framework'} - def __init__(self, environment, kwargs): super().__init__('boost', environment, 'cpp', kwargs) + self.need_static_link = ['boost_exception', 'boost_test_exec_monitor'] + self.is_debug = environment.cmd_line_options.buildtype.startswith('debug') + threading = kwargs.get("threading", "multi") + self.is_multithreading = threading == "multi" + + self.requested_modules = self.get_requested(kwargs) + + self.boost_root = None + self.boost_roots = [] + self.incdir = None self.libdir = None - try: + + if 'BOOST_ROOT' in os.environ: self.boost_root = os.environ['BOOST_ROOT'] + self.boost_roots = [self.boost_root] if not os.path.isabs(self.boost_root): raise DependencyException('BOOST_ROOT must be an absolute path.') - except KeyError: - self.boost_root = None + if 'BOOST_INCLUDEDIR' in os.environ: + self.incdir = os.environ['BOOST_INCLUDEDIR'] + if 'BOOST_LIBRARYDIR' in os.environ: + self.libdir = os.environ['BOOST_LIBRARYDIR'] + + if self.want_cross and self.boost_root is None and self.incdir is None: + raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling') + if self.boost_root is None: - if self.want_cross: - if 'BOOST_INCLUDEDIR' in os.environ: - self.incdir = os.environ['BOOST_INCLUDEDIR'] - else: - raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling') if mesonlib.is_windows(): - self.boost_root = self.detect_win_root() - self.incdir = self.boost_root + self.boost_roots = self.detect_win_roots() else: - if 'BOOST_INCLUDEDIR' in os.environ: - self.incdir = os.environ['BOOST_INCLUDEDIR'] - else: - self.incdir = '/usr/include' + self.boost_roots = self.detect_nix_roots() + + if self.boost_root is None and not self.boost_roots: + self.log_fail() + return + + if self.incdir is None: + if mesonlib.is_windows(): + self.incdir = self.detect_win_incdir() + else: + self.incdir = self.detect_nix_incdir() + + if self.incdir is None: + self.log_fail() + return + + mlog.debug('Boost library root dir is', mlog.bold(self.boost_root)) + mlog.debug('Boost include directory is', mlog.bold(self.incdir)) - if 'BOOST_LIBRARYDIR' in os.environ: - self.libdir = os.environ['BOOST_LIBRARYDIR'] - else: - self.incdir = os.path.join(self.boost_root, 'include') - self.boost_inc_subdir = os.path.join(self.incdir, 'boost') - mlog.debug('Boost library root dir is', self.boost_root) - self.src_modules = {} self.lib_modules = {} - self.lib_modules_mt = {} self.detect_version() - self.requested_modules = self.get_requested(kwargs) - module_str = ', '.join(self.requested_modules) if self.is_found: - self.detect_src_modules() self.detect_lib_modules() + mlog.debug('Boost library directory is', mlog.bold(self.libdir)) self.validate_requested() - if self.boost_root is not None: - info = self.version + ', ' + self.boost_root - else: - info = self.version - mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info) + self.log_success() + else: + self.log_fail() + + def log_fail(self): + module_str = ', '.join(self.requested_modules) + mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) + + def log_success(self): + module_str = ', '.join(self.requested_modules) + if self.boost_root: + info = self.version + ', ' + self.boost_root else: - mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO')) + info = self.version + mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info) + + def detect_nix_roots(self): + return ['/usr/local', '/usr'] - def detect_win_root(self): - globtext = 'c:\\local\\boost_*' + def detect_win_roots(self): + res = [] + # Where boost documentation says it should be + globtext = 'C:\\Program Files\\boost\\boost_*' files = glob.glob(globtext) - if len(files) > 0: - return files[0] - return 'C:\\' + res.extend(files) + + # Where boost built from source actually installs it + if os.path.isdir('C:\\Boost'): + res.append('C:\\Boost') + + # Where boost prebuilt binaries are + globtext = 'C:\\local\\boost_*' + files = glob.glob(globtext) + res.extend(files) + return res + + def detect_nix_incdir(self): + for root in self.boost_roots: + incdir = os.path.join(root, 'include', 'boost') + if os.path.isdir(incdir): + return os.path.join(root, 'include') + return None + + # FIXME: Should pick a version that matches the requested version + # Returns the folder that contains the boost folder. + def detect_win_incdir(self): + for root in self.boost_roots: + globtext = os.path.join(root, 'include', 'boost-*') + incdirs = glob.glob(globtext) + if len(incdirs) > 0: + return incdirs[0] + incboostdir = os.path.join(root, 'include', 'boost') + if os.path.isdir(incboostdir): + return os.path.join(root, 'include') + incboostdir = os.path.join(root, 'boost') + if os.path.isdir(incboostdir): + return root + return None def get_compile_args(self): args = [] - if self.boost_root is not None: - if mesonlib.is_windows(): - include_dir = self.boost_root - else: - include_dir = os.path.join(self.boost_root, 'include') - else: - include_dir = self.incdir + include_dir = self.incdir # Use "-isystem" when including boost headers instead of "-I" # to avoid compiler warnings/failures when "-Werror" is used @@ -116,18 +191,7 @@ class BoostDependency(ExternalDependency): # and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors # for more details - # TODO: The correct solution would probably be to ask the - # compiler for it's default include paths (ie: "gcc -xc++ -E - # -v -") and avoid including those with -isystem - - # For now, use -isystem for all includes except for some - # typical defaults (which don't need to be included at all - # since they are in the default include paths). These typical - # defaults include the usual directories at the root of the - # filesystem, but also any path that ends with those directory - # names in order to handle cases like cross-compiling where we - # might have a different sysroot. - if not include_dir.endswith(('/usr/include', '/usr/local/include')): + if include_dir and include_dir not in self.compiler.get_default_include_dirs(): args.append("".join(self.compiler.get_include_args(include_dir, True))) return args @@ -136,19 +200,23 @@ class BoostDependency(ExternalDependency): for c in candidates: if not isinstance(c, str): raise DependencyException('Boost module argument is not a string.') + if 'boost_' + c not in BOOST_LIBS: + raise DependencyException('Dependency {} not found. It is not a valid boost library.'.format(c)) return candidates def validate_requested(self): for m in self.requested_modules: - if m not in self.src_modules and m not in self.lib_modules and m + '-mt' not in self.lib_modules_mt: - msg = 'Requested Boost module {!r} not found' + if 'boost_' + m not in self.lib_modules: + msg = 'Requested Boost library {!r} not found' raise DependencyException(msg.format(m)) def detect_version(self): try: - ifile = open(os.path.join(self.boost_inc_subdir, 'version.hpp')) + ifile = open(os.path.join(self.incdir, 'boost', 'version.hpp')) except FileNotFoundError: return + except TypeError: + return with ifile: for line in ifile: if line.startswith("#define") and 'BOOST_LIB_VERSION' in line: @@ -158,12 +226,6 @@ class BoostDependency(ExternalDependency): self.is_found = True return - def detect_src_modules(self): - for entry in os.listdir(self.boost_inc_subdir): - entry = os.path.join(self.boost_inc_subdir, entry) - if stat.S_ISDIR(os.stat(entry).st_mode): - self.src_modules[os.path.split(entry)[-1]] = True - def detect_lib_modules(self): if mesonlib.is_windows(): return self.detect_lib_modules_win() @@ -171,32 +233,79 @@ class BoostDependency(ExternalDependency): def detect_lib_modules_win(self): arch = detect_cpu_family(self.env.coredata.compilers) - # Guess the libdir - if arch == 'x86': - gl = 'lib32*' - elif arch == 'x86_64': - gl = 'lib64*' - else: - # Does anyone do Boost cross-compiling to other archs on Windows? - gl = None - # See if the libdir is valid - if gl: - libdir = glob.glob(os.path.join(self.boost_root, gl)) - else: - libdir = [] - # Can't find libdir, bail - if not libdir: + compiler_ts = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version().split('.') + compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1]) + if not self.libdir: + # The libdirs in the distributed binaries + if arch == 'x86': + gl = 'lib32*' + elif arch == 'x86_64': + gl = 'lib64*' + else: + # Does anyone do Boost cross-compiling to other archs on Windows? + gl = None + if self.boost_root: + roots = [self.boost_root] + else: + roots = self.boost_roots + for root in roots: + # The default libdir when building + libdir = os.path.join(root, 'lib') + if os.path.isdir(libdir): + self.libdir = libdir + break + if gl: + tmp = glob.glob(os.path.join(root, gl)) + if len(tmp) > 0: + # FIXME: Should pick the correct version + self.libdir = tmp[0] + break + + if not self.libdir: return - libdir = libdir[0] - # Don't override what was set in the environment - if self.libdir: - self.libdir = libdir - globber = 'libboost_*-gd-*.lib' if self.static else 'boost_*-gd-*.lib' # FIXME - for entry in glob.glob(os.path.join(libdir, globber)): + + for name in self.need_static_link: + libname = "lib{}".format(name) + '-' + compiler + if self.is_multithreading: + libname = libname + '-mt' + if self.is_debug: + libname = libname + '-gd' + libname = libname + "-{}.lib".format(self.version.replace('.', '_')) + if os.path.isfile(os.path.join(self.libdir, libname)): + modname = libname.split('-', 1)[0][3:] + self.lib_modules[modname] = libname + else: + libname = "lib{}.lib".format(name) + if os.path.isfile(os.path.join(self.libdir, libname)): + self.lib_modules[name[3:]] = libname + + # globber1 applies to a layout=system installation + # globber2 applies to a layout=versioned installation + globber1 = 'libboost_*' if self.static else 'boost_*' + globber2 = globber1 + '-' + compiler + if self.is_multithreading: + globber2 = globber2 + '-mt' + if self.is_debug: + globber2 = globber2 + '-gd' + globber2 = globber2 + '-{}'.format(self.version.replace('.', '_')) + globber2_matches = glob.glob(os.path.join(self.libdir, globber2 + '.lib')) + for entry in globber2_matches: (_, fname) = os.path.split(entry) - base = fname.split('_', 1)[1] - modname = base.split('-', 1)[0] - self.lib_modules_mt[modname] = fname + modname = fname.split('-', 1) + if len(modname) > 1: + modname = modname[0] + else: + modname = modname.split('.', 1)[0] + if self.static: + modname = modname[3:] + self.lib_modules[modname] = fname + if len(globber2_matches) == 0: + for entry in glob.glob(os.path.join(self.libdir, globber1 + '.lib')): + (_, fname) = os.path.split(entry) + modname = fname.split('.', 1)[0] + if self.static: + modname = modname[3:] + self.lib_modules[modname] = fname def detect_lib_modules_nix(self): if self.static: @@ -214,25 +323,32 @@ class BoostDependency(ExternalDependency): else: libdirs = [os.path.join(self.boost_root, 'lib')] for libdir in libdirs: + for name in self.need_static_link: + libname = 'lib{}.a'.format(name) + if os.path.isfile(os.path.join(libdir, libname)): + self.lib_modules[name] = libname for entry in glob.glob(os.path.join(libdir, globber)): lib = os.path.basename(entry) - name = lib.split('.')[0].split('_', 1)[-1] + name = lib.split('.')[0][3:] # I'm not 100% sure what to do here. Some distros # have modules such as thread only as -mt versions. - if entry.endswith('-mt.{}'.format(libsuffix)): - self.lib_modules_mt[name] = True - else: - self.lib_modules[name] = True + # On debian all packages are built threading=multi + # but not suffixed with -mt. + # FIXME: implement detect_lib_modules_{debian, redhat, ...} + if self.is_multithreading and mesonlib.is_debianlike(): + self.lib_modules[name] = lib + elif self.is_multithreading and entry.endswith('-mt.{}'.format(libsuffix)): + self.lib_modules[name] = lib + elif not entry.endswith('-mt.{}'.format(libsuffix)): + self.lib_modules[name] = lib def get_win_link_args(self): args = [] # TODO: should this check self.libdir? - if self.boost_root: + if self.libdir: args.append('-L' + self.libdir) - for module in self.requested_modules: - module = BoostDependency.name2lib.get(module, module) - if module in self.lib_modules_mt: - args.append(self.lib_modules_mt[module]) + for lib in self.requested_modules: + args.append(self.lib_modules['boost_' + lib]) return args def get_link_args(self): @@ -243,33 +359,14 @@ class BoostDependency(ExternalDependency): args.append('-L' + os.path.join(self.boost_root, 'lib')) elif self.libdir: args.append('-L' + self.libdir) - for module in self.requested_modules: - module = BoostDependency.name2lib.get(module, module) - libname = 'boost_' + module + for lib in self.requested_modules: # The compiler's library detector is the most reliable so use that first. - default_detect = self.compiler.find_library(libname, self.env, []) + default_detect = self.compiler.find_library('boost_' + lib, self.env, []) if default_detect is not None: - if module == 'unit_testing_framework': - emon_args = self.compiler.find_library('boost_test_exec_monitor') - else: - emon_args = None args += default_detect - if emon_args is not None: - args += emon_args - elif module in self.lib_modules or module in self.lib_modules_mt: - linkcmd = '-l' + libname - args.append(linkcmd) - # FIXME a hack, but Boost's testing framework has a lot of - # different options and it's hard to determine what to do - # without feedback from actual users. Update this - # as we get more bug reports. - if module == 'unit_testing_framework': - args.append('-lboost_test_exec_monitor') - elif module + '-mt' in self.lib_modules_mt: - linkcmd = '-lboost_' + module + '-mt' + elif lib in self.lib_modules: + linkcmd = '-l' + lib args.append(linkcmd) - if module == 'unit_testing_framework': - args.append('-lboost_test_exec_monitor-mt') return args def get_sources(self): @@ -664,3 +761,78 @@ class CupsDependency(ExternalDependency): return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG, DependencyMethods.EXTRAFRAMEWORK] else: return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG] + +# Generated with boost_names.py +BOOST_LIBS = [ + 'boost_atomic', + 'boost_chrono', + 'boost_chrono', + 'boost_container', + 'boost_context', + 'boost_coroutine', + 'boost_date_time', + 'boost_exception', + 'boost_fiber', + 'boost_filesystem', + 'boost_graph', + 'boost_iostreams', + 'boost_locale', + 'boost_log', + 'boost_log_setup', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_math_tr1', + 'boost_math_tr1f', + 'boost_math_tr1l', + 'boost_math_c99', + 'boost_math_c99f', + 'boost_math_c99l', + 'boost_mpi', + 'boost_random', + 'boost_regex', + 'boost_serialization', + 'boost_wserialization', + 'boost_signals', + 'boost_stacktrace_noop', + 'boost_stacktrace_backtrace', + 'boost_stacktrace_addr2line', + 'boost_stacktrace_basic', + 'boost_stacktrace_windbg', + 'boost_stacktrace_windbg_cached', + 'boost_system', + 'boost_prg_exec_monitor', + 'boost_test_exec_monitor', + 'boost_unit_test_framework', + 'boost_thread', + 'boost_timer', + 'boost_type_erasure', + 'boost_wave' +] diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py index 7641514..b938080 100644 --- a/mesonbuild/interpreter.py +++ b/mesonbuild/interpreter.py @@ -48,6 +48,14 @@ def stringifyUserArguments(args): 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): def __init__(self, res): super().__init__() @@ -117,17 +125,18 @@ class RunProcess(InterpreterObject): def stderr_method(self, args, kwargs): return self.stderr -class ConfigureFileHolder(InterpreterObject): +class ConfigureFileHolder(InterpreterObject, ObjectHolder): def __init__(self, subdir, sourcename, targetname, configuration_data): 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): - super().__init__() - self.held_object = build.EnvironmentVariables() + MutableInterpreterObject.__init__(self) + ObjectHolder.__init__(self, build.EnvironmentVariables()) self.methods.update({'set': self.set_method, 'append': self.append_method, 'prepend': self.prepend_method, @@ -158,11 +167,11 @@ class EnvironmentVariablesHolder(MutableInterpreterObject): self.add_var(self.held_object.prepend, args, kwargs) -class ConfigurationDataHolder(MutableInterpreterObject): +class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder): def __init__(self): - super().__init__() + MutableInterpreterObject.__init__(self) 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, 'set10': self.set10_method, 'set_quoted': self.set_quoted_method, @@ -242,10 +251,10 @@ class ConfigurationDataHolder(MutableInterpreterObject): # Interpreter objects can not be pickled so we must have # these wrappers. -class DependencyHolder(InterpreterObject): +class DependencyHolder(InterpreterObject, ObjectHolder): def __init__(self, dep): InterpreterObject.__init__(self) - self.held_object = dep + ObjectHolder.__init__(self, dep) self.methods.update({'found': self.found_method, 'type_name': self.type_name_method, 'version': self.version_method, @@ -272,10 +281,10 @@ class DependencyHolder(InterpreterObject): raise InterpreterException('Variable name must be a string.') return self.held_object.get_pkgconfig_variable(varname) -class InternalDependencyHolder(InterpreterObject): +class InternalDependencyHolder(InterpreterObject, ObjectHolder): def __init__(self, dep): InterpreterObject.__init__(self) - self.held_object = dep + ObjectHolder.__init__(self, dep) self.methods.update({'found': self.found_method, 'version': self.version_method, }) @@ -286,10 +295,10 @@ class InternalDependencyHolder(InterpreterObject): def version_method(self, args, kwargs): return self.held_object.get_version() -class ExternalProgramHolder(InterpreterObject): +class ExternalProgramHolder(InterpreterObject, ObjectHolder): def __init__(self, ep): InterpreterObject.__init__(self) - self.held_object = ep + ObjectHolder.__init__(self, ep) self.methods.update({'found': self.found_method, 'path': self.path_method}) @@ -308,10 +317,10 @@ class ExternalProgramHolder(InterpreterObject): def get_name(self): return self.held_object.get_name() -class ExternalLibraryHolder(InterpreterObject): +class ExternalLibraryHolder(InterpreterObject, ObjectHolder): def __init__(self, el): InterpreterObject.__init__(self) - self.held_object = el + ObjectHolder.__init__(self, el) self.methods.update({'found': self.found_method}) def found(self): @@ -332,11 +341,11 @@ class ExternalLibraryHolder(InterpreterObject): def get_exe_args(self): return self.held_object.get_exe_args() -class GeneratorHolder(InterpreterObject): +class GeneratorHolder(InterpreterObject, ObjectHolder): def __init__(self, interpreter, args, kwargs): - super().__init__() + InterpreterObject.__init__(self) self.interpreter = interpreter - self.held_object = build.Generator(args, kwargs) + ObjectHolder.__init__(self, build.Generator(args, kwargs)) self.methods.update({'process': self.process_method}) def process_method(self, args, kwargs): @@ -345,13 +354,13 @@ class GeneratorHolder(InterpreterObject): return GeneratedListHolder(gl) -class GeneratedListHolder(InterpreterObject): +class GeneratedListHolder(InterpreterObject, ObjectHolder): def __init__(self, arg1, extra_args=[]): - super().__init__() + InterpreterObject.__init__(self) 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: - self.held_object = arg1 + ObjectHolder.__init__(self, arg1) def __repr__(self): r = '<{}: {!r}>' @@ -360,14 +369,15 @@ class GeneratedListHolder(InterpreterObject): def add_file(self, a): self.held_object.add_file(a) -class BuildMachine(InterpreterObject): +class BuildMachine(InterpreterObject, ObjectHolder): def __init__(self, compilers): self.compilers = compilers InterpreterObject.__init__(self) - self.held_object = environment.MachineInfo(environment.detect_system(), - environment.detect_cpu_family(self.compilers), - environment.detect_cpu(self.compilers), - sys.byteorder) + held_object = environment.MachineInfo(environment.detect_system(), + environment.detect_cpu_family(self.compilers), + environment.detect_cpu(self.compilers), + sys.byteorder) + ObjectHolder.__init__(self, held_object) self.methods.update({'system': self.system_method, 'cpu_family': self.cpu_family_method, 'cpu': self.cpu_method, @@ -388,7 +398,7 @@ class BuildMachine(InterpreterObject): # This class will provide both host_machine and # target_machine -class CrossMachineInfo(InterpreterObject): +class CrossMachineInfo(InterpreterObject, ObjectHolder): def __init__(self, cross_info): InterpreterObject.__init__(self) minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'} @@ -397,10 +407,11 @@ class CrossMachineInfo(InterpreterObject): 'Machine info is currently {}\n'.format(cross_info) + 'but is missing {}.'.format(minimum_cross_info - set(cross_info))) self.info = cross_info - self.held_object = environment.MachineInfo(cross_info['system'], - cross_info['cpu_family'], - cross_info['cpu'], - cross_info['endian']) + minfo = environment.MachineInfo(cross_info['system'], + cross_info['cpu_family'], + cross_info['cpu'], + cross_info['endian']) + ObjectHolder.__init__(self, minfo) self.methods.update({'system': self.system_method, 'cpu': self.cpu_method, 'cpu_family': self.cpu_family_method, @@ -419,10 +430,10 @@ class CrossMachineInfo(InterpreterObject): def endian_method(self, args, kwargs): return self.held_object.endian -class IncludeDirsHolder(InterpreterObject): +class IncludeDirsHolder(InterpreterObject, ObjectHolder): def __init__(self, idobj): - super().__init__() - self.held_object = idobj + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, idobj) class Headers(InterpreterObject): @@ -447,10 +458,10 @@ class Headers(InterpreterObject): def get_custom_install_dir(self): return self.custom_install_dir -class DataHolder(InterpreterObject): +class DataHolder(InterpreterObject, ObjectHolder): def __init__(self, data): - super().__init__() - self.held_object = data + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, data) def get_source_subdir(self): return self.held_object.source_subdir @@ -495,20 +506,20 @@ class Man(InterpreterObject): def get_sources(self): return self.sources -class GeneratedObjectsHolder(InterpreterObject): +class GeneratedObjectsHolder(InterpreterObject, ObjectHolder): def __init__(self, held_object): - super().__init__() - self.held_object = held_object + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, held_object) -class TargetHolder(InterpreterObject): - def __init__(self): - super().__init__() +class TargetHolder(InterpreterObject, ObjectHolder): + def __init__(self, target, interp): + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, target) + self.interpreter = interp class BuildTargetHolder(TargetHolder): def __init__(self, target, interp): - super().__init__() - self.held_object = target - self.interpreter = interp + super().__init__(target, interp) self.methods.update({'extract_objects': self.extract_objects_method, 'extract_all_objects': self.extract_all_objects_method, 'get_id': self.get_id_method, @@ -566,16 +577,14 @@ class JarHolder(BuildTargetHolder): def __init__(self, target, interp): super().__init__(target, interp) -class CustomTargetIndexHolder(InterpreterObject): +class CustomTargetIndexHolder(InterpreterObject, ObjectHolder): def __init__(self, object_to_hold): - super().__init__() - self.held_object = object_to_hold + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, object_to_hold) class CustomTargetHolder(TargetHolder): - def __init__(self, object_to_hold, interp): - super().__init__() - self.held_object = object_to_hold - self.interpreter = interp + def __init__(self, target, interp): + super().__init__(target, interp) self.methods.update({'full_path': self.full_path_method, }) @@ -596,10 +605,10 @@ class CustomTargetHolder(TargetHolder): def __delitem__(self, index): raise InterpreterException('Cannot delete a member of a CustomTarget') -class RunTargetHolder(InterpreterObject): +class RunTargetHolder(InterpreterObject, ObjectHolder): def __init__(self, name, command, args, dependencies, subdir): - super().__init__() - self.held_object = build.RunTarget(name, command, args, dependencies, subdir) + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, build.RunTarget(name, command, args, dependencies, subdir)) def __repr__(self): r = '<{} {}: {}>' @@ -625,11 +634,11 @@ class Test(InterpreterObject): def get_name(self): return self.name -class SubprojectHolder(InterpreterObject): +class SubprojectHolder(InterpreterObject, ObjectHolder): def __init__(self, subinterpreter): - super().__init__() - self.held_object = subinterpreter + InterpreterObject.__init__(self) + ObjectHolder.__init__(self, subinterpreter) 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', 'target_machine']) -class ModuleHolder(InterpreterObject): +class ModuleHolder(InterpreterObject, ObjectHolder): def __init__(self, modname, module, interpreter): InterpreterObject.__init__(self) + ObjectHolder.__init__(self, module) self.modname = modname - self.held_object = module self.interpreter = interpreter def method_call(self, method_name, args, kwargs): @@ -1551,12 +1560,11 @@ class Interpreter(InterpreterBase): version = kwargs.get('version', self.project_version) if not isinstance(version, str): raise InterpreterException('Version must be a string.') - incs = extract_as_list(kwargs, 'include_directories') - libs = extract_as_list(kwargs, 'link_with') + incs = extract_as_list(kwargs, 'include_directories', unholder=True) + libs = extract_as_list(kwargs, 'link_with', unholder=True) sources = extract_as_list(kwargs, 'sources') - sources = self.source_strings_to_files(self.flatten(sources)) - deps = self.flatten(kwargs.get('dependencies', [])) - deps = listify(deps) + sources = listify(self.source_strings_to_files(sources), unholder=True) + deps = extract_as_list(kwargs, 'dependencies', unholder=True) compile_args = mesonlib.stringlistify(kwargs.get('compile_args', [])) link_args = mesonlib.stringlistify(kwargs.get('link_args', [])) final_deps = [] @@ -1568,13 +1576,8 @@ class Interpreter(InterpreterBase): if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)): raise InterpreterException('Dependencies must be external deps') final_deps.append(d) - dep = dependencies.InternalDependency(version, - mesonlib.unholder_array(incs), - compile_args, - link_args, - mesonlib.unholder_array(libs), - mesonlib.unholder_array(sources), - final_deps) + dep = dependencies.InternalDependency(version, incs, compile_args, + link_args, libs, sources, final_deps) return DependencyHolder(dep) @noKwargs @@ -1629,7 +1632,7 @@ class Interpreter(InterpreterBase): 'or not executable'.format(cmd)) cmd = prog expanded_args = [] - for a in mesonlib.flatten(cargs): + for a in listify(cargs): if isinstance(a, str): expanded_args.append(a) 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.') cleaned_args = [] - for i in mesonlib.flatten(all_args): - try: - i = i.held_object - except AttributeError: - pass + for i in listify(all_args, unholder=True): 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.') @@ -2374,11 +2373,10 @@ to directly access options of other subprojects.''') 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') + cmd_args = extract_as_list(kwargs, 'args', unholder=True) 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.') - cmd_args = mesonlib.unholder_array(cmd_args) env = self.unpack_env_kwarg(kwargs) should_fail = kwargs.get('should_fail', False) if not isinstance(should_fail, bool): @@ -2796,7 +2794,8 @@ different subdirectory. elif isinstance(s, str): s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s) 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) return results @@ -2822,7 +2821,7 @@ different subdirectory. if not args: raise InterpreterException('Target does not have a name.') name = args[0] - sources = args[1:] + sources = listify(args[1:]) if self.environment.is_cross_build(): if kwargs.get('native', False): is_cross = False @@ -2830,19 +2829,14 @@ different subdirectory. is_cross = True else: is_cross = False - try: - kw_src = self.flatten(kwargs['sources']) - kw_src = listify(kw_src) - except KeyError: - kw_src = [] - sources += kw_src + if 'sources' in kwargs: + sources += listify(kwargs['sources']) sources = self.source_strings_to_files(sources) - objs = self.flatten(kwargs.get('objects', [])) - kwargs['dependencies'] = self.flatten(kwargs.get('dependencies', [])) + objs = extract_as_list(kwargs, 'objects') + kwargs['dependencies'] = extract_as_list(kwargs, 'dependencies') if 'extra_files' in kwargs: ef = extract_as_list(kwargs, 'extra_files') 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) if targetholder is ExecutableHolder: targetclass = build.Executable diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 71134a8..5c4c374 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -199,17 +199,6 @@ def classify_unity_sources(compilers, sources): compsrclist[comp].append(src) 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(): return platform.system().lower() == 'darwin' @@ -474,24 +463,45 @@ def replace_if_different(dst, dst_tmp): else: os.unlink(dst_tmp) - -def listify(*args): +def listify(item, flatten=True, unholder=False): ''' - 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. + @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 - return args[0] if type(args[0]) is list else [args[0]] - return [item if type(item) is list else [item] for item in args] + if not isinstance(item, list): + if unholder and hasattr(item, 'held_object'): + 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. ''' + result = [] + fetch = dict_object.get if pop: - return listify(*[dict_object.pop(key, []) for key in keys]) - return listify(*[dict_object.get(key, []) for key in keys]) + 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 a list of values corresponding to *keys + for key in keys: + result.append(listify(fetch(key, []), **kwargs)) + return result def typeslistify(item, types): @@ -750,15 +760,6 @@ def windows_proof_rmtree(f): # Try one last time and throw if it fails. 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): """A set that preserves the order in which items are added, by first insertion. diff --git a/mesonbuild/modules/gnome.py b/mesonbuild/modules/gnome.py index d1d7013..1f813da 100644 --- a/mesonbuild/modules/gnome.py +++ b/mesonbuild/modules/gnome.py @@ -20,7 +20,7 @@ import os import copy import subprocess 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 .. import mlog from .. import mesonlib @@ -323,11 +323,9 @@ class GnomeModule(ExtensionModule): cflags = OrderedSet() ldflags = OrderedSet() gi_includes = OrderedSet() - deps = mesonlib.listify(deps) + deps = mesonlib.listify(deps, unholder=True) for dep in deps: - if hasattr(dep, 'held_object'): - dep = dep.held_object if isinstance(dep, InternalDependency): cflags.update(get_include_args(dep.include_directories)) for lib in dep.libraries: @@ -378,7 +376,7 @@ class GnomeModule(ExtensionModule): elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): cflags.update(get_include_args(dep.get_include_dirs())) 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 if gir_has_extra_lib_arg() and use_gir_args: @@ -394,7 +392,7 @@ class GnomeModule(ExtensionModule): @permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', 'export_packages', 'includes', 'dependencies', 'link_with', 'include_directories', 'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args', - 'packages', 'build_by_default'}) + 'packages', 'header', 'build_by_default'}) def generate_gir(self, state, args, kwargs): if len(args) != 1: raise MesonException('Gir takes one argument') @@ -417,7 +415,7 @@ class GnomeModule(ExtensionModule): raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.') ns = kwargs.pop('namespace') 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) srcdir = os.path.join(state.environment.get_source_dir(), state.subdir) builddir = os.path.join(state.environment.get_build_dir(), state.subdir) @@ -429,6 +427,12 @@ class GnomeModule(ExtensionModule): scan_command += ['--no-libtool', '--namespace=' + ns, '--nsversion=' + nsversion, '--warn-all', '--output', '@OUTPUT@'] + header = kwargs.pop('header', None) + if header: + if not isinstance(header, str): + raise MesonException('header must be a string') + scan_command += ['--c-include=' + header] + extra_args = mesonlib.stringlistify(kwargs.pop('extra_args', [])) scan_command += extra_args scan_command += ['-I' + srcdir, @@ -525,9 +529,8 @@ class GnomeModule(ExtensionModule): else: 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) + extract_as_list(kwargs, 'dependencies', pop=True, unholder=True)) # Need to recursively add deps on GirTarget sources from our # dependencies and also find the include directories needed for the # typelib generation custom target below. @@ -794,7 +797,8 @@ This will become a hard error in the future.''') def _get_build_args(self, kwargs, state): 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') for incd in inc_dirs: if not isinstance(incd.held_object, (str, build.IncludeDirs)): diff --git a/mesonbuild/modules/qt4.py b/mesonbuild/modules/qt4.py index a63aff8..4ab07b9 100644 --- a/mesonbuild/modules/qt4.py +++ b/mesonbuild/modules/qt4.py @@ -21,6 +21,7 @@ from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue from ..interpreterbase import permittedKwargs +from . import get_include_args class Qt4Module(ExtensionModule): tools_detected = False @@ -97,10 +98,10 @@ class Qt4Module(ExtensionModule): except Exception: return [] - @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'}) + @permittedKwargs({'moc_headers', 'moc_sources', 'include_directories', 'ui_files', 'qresources', 'method'}) def preprocess(self, state, args, kwargs): - rcc_files, ui_files, moc_headers, moc_sources, sources \ - = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', pop = True) + rcc_files, ui_files, moc_headers, moc_sources, sources, include_directories \ + = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', 'include_directories', pop = True) sources += args[1:] method = kwargs.get('method', 'auto') self._detect_tools(state.environment, method) @@ -133,9 +134,10 @@ class Qt4Module(ExtensionModule): ui_gen = build.Generator([self.uic], ui_kwargs) ui_output = ui_gen.process_files('Qt4 ui', ui_files, state) sources.append(ui_output) + inc = get_include_args(include_dirs=include_directories) if len(moc_headers) > 0: moc_kwargs = {'output': 'moc_@BASENAME@.cpp', - 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} + 'arguments': inc + ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt4 moc header', moc_headers, state) sources.append(moc_output) diff --git a/mesonbuild/modules/qt5.py b/mesonbuild/modules/qt5.py index 08ce662..001caa7 100644 --- a/mesonbuild/modules/qt5.py +++ b/mesonbuild/modules/qt5.py @@ -21,6 +21,7 @@ from . import ExtensionModule import xml.etree.ElementTree as ET from . import ModuleReturnValue from ..interpreterbase import permittedKwargs +from . import get_include_args class Qt5Module(ExtensionModule): tools_detected = False @@ -103,10 +104,10 @@ class Qt5Module(ExtensionModule): except Exception: return [] - @permittedKwargs({'moc_headers', 'moc_sources', 'ui_files', 'qresources', 'method'}) + @permittedKwargs({'moc_headers', 'moc_sources', 'include_directories', 'ui_files', 'qresources', 'method'}) def preprocess(self, state, args, kwargs): - rcc_files, ui_files, moc_headers, moc_sources, sources \ - = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', pop = True) + rcc_files, ui_files, moc_headers, moc_sources, sources, include_directories \ + = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', 'include_directories', pop = True) sources += args[1:] method = kwargs.get('method', 'auto') self._detect_tools(state.environment, method) @@ -139,9 +140,10 @@ class Qt5Module(ExtensionModule): ui_gen = build.Generator([self.uic], ui_kwargs) ui_output = ui_gen.process_files('Qt5 ui', ui_files, state) sources.append(ui_output) + inc = get_include_args(include_dirs=include_directories) if len(moc_headers) > 0: moc_kwargs = {'output': 'moc_@BASENAME@.cpp', - 'arguments': ['@INPUT@', '-o', '@OUTPUT@']} + 'arguments': inc + ['@INPUT@', '-o', '@OUTPUT@']} moc_gen = build.Generator([self.moc], moc_kwargs) moc_output = moc_gen.process_files('Qt5 moc header', moc_headers, state) sources.append(moc_output) |