aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorCorentin Noël <corentin@elementary.io>2017-10-03 20:26:16 +0200
committerCorentin Noël <corentin@elementary.io>2017-10-03 20:26:16 +0200
commit1320a98a33e4e9f188e5daa143316b24d0dce819 (patch)
tree82ea281b163115277e1c9524283b0d371b6c21ac /mesonbuild
parentf13887b64a9d535682668960493158ae15bfbb2d (diff)
parent0c3d58baba4a61558ed9b4905f26155a3e95cf6c (diff)
downloadmeson-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.py24
-rw-r--r--mesonbuild/build.py25
-rw-r--r--mesonbuild/compilers/c.py34
-rw-r--r--mesonbuild/compilers/compilers.py39
-rw-r--r--mesonbuild/dependencies/base.py6
-rw-r--r--mesonbuild/dependencies/dev.py4
-rw-r--r--mesonbuild/dependencies/misc.py426
-rw-r--r--mesonbuild/interpreter.py184
-rw-r--r--mesonbuild/mesonlib.py59
-rw-r--r--mesonbuild/modules/gnome.py24
-rw-r--r--mesonbuild/modules/qt4.py10
-rw-r--r--mesonbuild/modules/qt5.py10
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)