Merge github.com:mesonbuild/meson into vala-target-dirs

pull/2413/head
Corentin Noël 7 years ago
commit 1320a98a33
  1. 10
      .appveyor.yml
  2. 15
      docs/markdown/Dependencies.md
  3. 4
      docs/markdown/Gnome-module.md
  4. 8
      docs/markdown/Qt5-module.md
  5. 19
      docs/markdown/Reference-manual.md
  6. 10
      docs/markdown/Release-notes-for-0.43.0/001-boost-platform-improvement.md
  7. 20
      docs/markdown/snippets/prebuilt.md
  8. 24
      mesonbuild/backend/backends.py
  9. 25
      mesonbuild/build.py
  10. 34
      mesonbuild/compilers/c.py
  11. 39
      mesonbuild/compilers/compilers.py
  12. 6
      mesonbuild/dependencies/base.py
  13. 4
      mesonbuild/dependencies/dev.py
  14. 426
      mesonbuild/dependencies/misc.py
  15. 184
      mesonbuild/interpreter.py
  16. 59
      mesonbuild/mesonlib.py
  17. 24
      mesonbuild/modules/gnome.py
  18. 10
      mesonbuild/modules/qt4.py
  19. 10
      mesonbuild/modules/qt5.py
  20. 72
      run_project_tests.py
  21. 139
      run_unittests.py
  22. 5
      test cases/frameworks/1 boost/meson.build
  23. 12
      test cases/frameworks/1 boost/nolinkexe.cc
  24. 10
      test cases/frameworks/4 qt/meson.build
  25. 7
      test cases/frameworks/4 qt/plugin/plugin.cpp
  26. 11
      test cases/frameworks/4 qt/plugin/plugin.h
  27. 3
      test cases/frameworks/4 qt/plugin/plugin.json
  28. 21
      test cases/frameworks/4 qt/pluginInterface/plugin_if.h
  29. 1
      test cases/frameworks/7 gnome/gir/dep1/meson.build
  30. 2
      test cases/frameworks/7 gnome/gir/meson.build
  31. 0
      test cases/unit/14 prebuilt object/main.c
  32. 0
      test cases/unit/14 prebuilt object/meson.build
  33. 0
      test cases/unit/14 prebuilt object/source.c
  34. 0
      test cases/unit/15 prebuilt static/libdir/best.c
  35. 0
      test cases/unit/15 prebuilt static/libdir/best.h
  36. 0
      test cases/unit/15 prebuilt static/libdir/meson.build
  37. 0
      test cases/unit/15 prebuilt static/main.c
  38. 0
      test cases/unit/15 prebuilt static/meson.build
  39. 6
      test cases/unit/16 prebuilt shared/alexandria.c
  40. 20
      test cases/unit/16 prebuilt shared/alexandria.h
  41. 10
      test cases/unit/16 prebuilt shared/another_visitor.c
  42. 14
      test cases/unit/16 prebuilt shared/meson.build
  43. 8
      test cases/unit/16 prebuilt shared/patron.c
  44. 180
      tools/boost_names.py

@ -19,10 +19,12 @@ environment:
- arch: x86
compiler: msvc2015
backend: ninja
BOOST_ROOT: C:\Libraries\Boost_1_59_0
- arch: x86
compiler: msvc2015
backend: vs2015
BOOST_ROOT: C:\Libraries\Boost_1_59_0
- arch: x64
compiler: cygwin
@ -36,11 +38,13 @@ environment:
compiler: msvc2017
backend: ninja
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
BOOST_ROOT: C:\Libraries\Boost_1_64_0
- arch: x64
compiler: msvc2017
backend: vs2017
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
BOOST_ROOT: C:\Libraries\Boost_1_64_0
platform:
- x64
@ -59,8 +63,6 @@ init:
install:
- cmd: set "ORIG_PATH=%PATH%"
# Boost 1.56.0: https://www.appveyor.com/docs/build-environment/#boost
#- cmd: set "BOOST_ROOT=C:\Libraries\boost"
# Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219
- cmd: set "MESON_FIXED_NINJA=1"
- ps: (new-object net.webclient).DownloadFile('http://nirbheek.in/files/binaries/ninja/win32/ninja.exe', 'C:\projects\meson\ninja.exe')
@ -68,6 +70,10 @@ install:
# For all other archs (including, say, arm), use the x64 python.
- cmd: if %arch%==x86 (set MESON_PYTHON_PATH=C:\python34) else (set MESON_PYTHON_PATH=C:\python34-x64)
# Set paths for BOOST dll files
- cmd: if %compiler%==msvc2015 ( if %arch%==x86 ( set "PATH=%PATH%;C:\Libraries\boost_1_59_0\lib32-msvc-14.0" ) else ( set "PATH=%PATH%;C:\Libraries\boost_1_59_0\lib64-msvc-14.0" ) )
- cmd: if %compiler%==msvc2017 ( if %arch%==x86 ( set "PATH=%PATH%;C:\Libraries\boost_1_64_0\lib32-msvc-14.1" ) else ( set "PATH=%PATH%;C:\Libraries\boost_1_64_0\lib64-msvc-14.1" ) )
# Set paths and config for each build type.
- cmd: if %compiler%==msvc2010 ( call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" %arch% )
- cmd: if %compiler%==msvc2015 ( call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %arch% )

@ -50,8 +50,16 @@ pkg-config files. Meson has autodetection support for some of these.
## Boost ##
Boost is not a single dependency but rather a group of different
libraries. To use Boost with Meson, simply list which Boost modules
you would like to use.
libraries. To use Boost headers-only libraries, simply add Boost as a
dependency.
```meson
boost_dep = dependency('boost')
exe = executable('myprog', 'file.cc', dependencies : boost_dep)
```
To link against boost with Meson, simply list which libraries you would like to
use.
```meson
boost_dep = dependency('boost', modules : ['thread', 'utility'])
@ -65,6 +73,9 @@ If your boost headers or libraries are in non-standard locations you
can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR
environment variables.
You can set the argument `threading` to `single` to use boost libraries that
has been compiled for single-threaded use instead.
## GTest and GMock ##
GTest and GMock come as sources that must be compiled as part of your

@ -81,6 +81,10 @@ tool so see its documentation for more information.
* `includes`: list of gir names to be included, can also be a GirTarget
* `header`: *(Added 0.43.0)* name of main c header to include for the library, e.g. `glib.h`
* `dependencies`: deps to use during introspection scanning
* `include_directories`: extra include paths to look for gir files
* `install`: if true, install the generated files

@ -5,17 +5,19 @@ tools and steps required for Qt. The module has one method.
## preprocess
This method takes four keyword arguments, `moc_headers`,
This method takes five keyword arguments, `moc_headers`,
`moc_sources`, `ui_files` and `qresources` which define the files that
require preprocessing with `moc`, `uic` and `rcc`. It returns an
require preprocessing with `moc`, `uic` and `rcc` and 'include_directories' which might be needed by moc. It returns an
opaque object that should be passed to a main build target. A simple
example would look like this:
```meson
qt5 = import('qt5')
qt5_dep = dependency('qt5', modules: ['Core', 'Gui'])
moc_files = qt5.preprocess(moc_headers : 'myclass.h')
inc = include_directories('includes')
moc_files = qt5.preprocess(moc_headers : 'myclass.h', include_directories: inc)
executable('myprog', 'main.cpp', 'myclass.cpp', moc_files,
include_directories: inc,
dependencies : qt5_dep)
```

@ -820,10 +820,19 @@ static with only one option.
The keyword arguments for this are the same as for [`executable`](#executable) with the following additions:
- `name_prefix` the string that will be used as the suffix for the
target by overriding the default (only used for libraries). By
default this is `lib` on all platforms and compilers except with
MSVC where it is omitted.
- `name_prefix` the string that will be used as the prefix for the
target output filename by overriding the default (only used for
libraries). By default this is `lib` on all platforms and compilers
except with MSVC shared libraries where it is omitted to follow
convention.
- `name_suffix` the string that will be used as the suffix for the
target output filename by overriding the default (see also:
[executable()](#executable)). By default, for shared libraries this
is `dylib` on macOS, `dll` on Windows, and `so` everywhere else.
For static libraries, it is `a` everywhere. By convention MSVC
static libraries use the `lib` suffix, but we use `a` to avoid a
potential name clash with shared libraries which also generate
`xxx.lib` import files.
- `rust_crate_type` specifies the crate type for Rust
libraries. Defaults to `dylib` for shared libraries and `rlib` for
static libraries.
@ -1614,7 +1623,7 @@ during tests. It should be passed as the `env` keyword argument to
tests. It has the following methods.
- `append(varname, value)` appends the given value to the old value of
the environment variable, e.g. `env.append'('FOO', 'BAR', separator
the environment variable, e.g. `env.append('FOO', 'BAR', separator
: ';')` produces `BOB;BAR` if `FOO` had the value `BOB` and plain
`BAR` if the value was not defined. If the separator is not
specified explicitly, the default path separator for the host

@ -0,0 +1,10 @@
## Portability improvements to Boost Dependency
The Boost dependency has been improved to better detect the various ways to
install boost on multiple platforms. At the same time the `modules` semantics
for the dependency has been changed. Previously it was allowed to specify
header directories as `modules` but it wasn't required. Now, modules are only
used to specify libraries that require linking.
This is a breaking change and the fix is to remove all modules that aren't
found.

@ -0,0 +1,20 @@
# Better support for shared libraries in non-system paths
Meson has had support for prebuilt object files and static libraries.
This release adds feature parity to shared libraries that are either
in non-standard system paths or shipped as part of your project. On
systems that support rpath, Meson automatically adds rpath entries
to built targets using manually found external libraries.
This means that e.g. supporting prebuilt libraries shipped with your
source or provided by subprojects or wrap definitions by writing a
build file like this:
project('myprebuiltlibrary', 'c')
cc = meson.get_compiler('c')
prebuilt = cc.find_library('mylib', dirs : meson.current_source_dir())
mydep = declare_dependency(include_directories : include_directories('.'),
dependencies : prebuilt)
Then you can use the dependency object in the same way as any other.

@ -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):

@ -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'])

@ -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)

@ -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)

@ -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

@ -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'))

@ -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'
]

@ -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

@ -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.

@ -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)):

@ -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)

@ -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)

@ -124,6 +124,8 @@ print_debug = 'MESON_PRINT_TEST_OUTPUT' in os.environ
do_debug = not {'MESON_PRINT_TEST_OUTPUT', 'TRAVIS', 'APPVEYOR'}.isdisjoint(os.environ)
no_meson_log_msg = 'No meson-log.txt found.'
system_compiler = None
meson_command = os.path.join(os.getcwd(), 'meson')
if not os.path.exists(meson_command):
meson_command += '.py'
@ -141,9 +143,6 @@ def stop_handler(signal, frame):
signal.signal(signal.SIGINT, stop_handler)
signal.signal(signal.SIGTERM, stop_handler)
# Needed when running cross tests because we don't generate prebuilt files
compiler = None
def setup_commands(optbackend):
global do_debug, backend, backend_flags
global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands
@ -451,7 +450,6 @@ def detect_tests_to_run():
('failing-meson', 'failing', False),
('failing-build', 'failing build', False),
('failing-tests', 'failing tests', False),
('prebuilt', 'prebuilt', False),
('platform-osx', 'osx', not mesonlib.is_osx()),
('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()),
@ -485,7 +483,7 @@ def run_tests(all_tests, log_name_base, extra_args):
return _run_tests(all_tests, log_name_base, extra_args)
def _run_tests(all_tests, log_name_base, extra_args):
global stop, executor, futures
global stop, executor, futures, system_compiler
xmlname = log_name_base + '.xml'
junit_root = ET.Element('testsuites')
conf_time = 0
@ -532,7 +530,7 @@ def _run_tests(all_tests, log_name_base, extra_args):
should_fail = False
if name.startswith('failing'):
should_fail = name.split('failing-')[1]
result = executor.submit(run_test, skipped, t, extra_args, compiler, backend, backend_flags, commands, should_fail)
result = executor.submit(run_test, skipped, t, extra_args, system_compiler, backend, backend_flags, commands, should_fail)
futures.append((testname, t, result))
for (testname, t, result) in futures:
sys.stdout.flush()
@ -600,52 +598,6 @@ def check_format():
fullname = os.path.join(root, file)
check_file(fullname)
def pbcompile(compiler, source, objectfile):
if compiler == 'cl':
cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source]
else:
cmd = [compiler, '-c', source, '-o', objectfile]
subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def generate_pb_object(compiler, object_suffix):
source = 'test cases/prebuilt/1 object/source.c'
objectfile = 'test cases/prebuilt/1 object/prebuilt.' + object_suffix
pbcompile(compiler, source, objectfile)
return objectfile
def generate_pb_static(compiler, object_suffix, static_suffix):
source = 'test cases/prebuilt/2 static/libdir/best.c'
objectfile = 'test cases/prebuilt/2 static/libdir/best.' + object_suffix
stlibfile = 'test cases/prebuilt/2 static/libdir/libbest.' + static_suffix
pbcompile(compiler, source, objectfile)
if compiler == 'cl':
linker = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile]
else:
linker = ['ar', 'csr', stlibfile, objectfile]
subprocess.check_call(linker)
os.unlink(objectfile)
return stlibfile
def generate_prebuilt():
global compiler
static_suffix = 'a'
if shutil.which('cl'):
compiler = 'cl'
static_suffix = 'lib'
elif shutil.which('cc'):
compiler = 'cc'
elif shutil.which('gcc'):
compiler = 'gcc'
else:
raise RuntimeError("Could not find C compiler.")
if mesonlib.is_windows():
object_suffix = 'obj'
else:
object_suffix = 'o'
objectfile = generate_pb_object(compiler, object_suffix)
stlibfile = generate_pb_static(compiler, object_suffix, static_suffix)
return objectfile, stlibfile
def check_meson_commands_work():
global backend, meson_command, compile_commands, test_commands, install_commands
testdir = 'test cases/common/1 trivial'
@ -670,6 +622,18 @@ def check_meson_commands_work():
if pc.returncode != 0:
raise RuntimeError('Failed to install {!r}:\n{}\n{}'.format(testdir, e, o))
def detect_system_compiler():
global system_compiler
if shutil.which('cl'):
system_compiler = 'cl'
elif shutil.which('cc'):
system_compiler = 'cc'
elif shutil.which('gcc'):
system_compiler = 'gcc'
else:
raise RuntimeError("Could not find C compiler.")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
parser.add_argument('extra_args', nargs='*',
@ -679,19 +643,17 @@ if __name__ == '__main__':
options = parser.parse_args()
setup_commands(options.backend)
detect_system_compiler()
script_dir = os.path.split(__file__)[0]
if script_dir != '':
os.chdir(script_dir)
check_format()
check_meson_commands_work()
pbfiles = generate_prebuilt()
try:
all_tests = detect_tests_to_run()
(passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.extra_args)
except StopException:
pass
for f in pbfiles:
os.unlink(f)
print('\nTotal passed tests:', green(str(passing_tests)))
print('Total failed tests:', red(str(failing_tests)))
print('Total skipped tests:', yellow(str(skipped_tests)))

@ -31,6 +31,7 @@ import mesonbuild.compilers
import mesonbuild.environment
import mesonbuild.mesonlib
import mesonbuild.coredata
from mesonbuild.interpreter import ObjectHolder
from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree
from mesonbuild.environment import Environment
from mesonbuild.dependencies import DependencyException
@ -62,7 +63,6 @@ def get_soname(fname):
def get_rpath(fname):
return get_dynamic_section_entry(fname, r'(?:rpath|runpath)')
class InternalTests(unittest.TestCase):
def test_version_number(self):
@ -398,6 +398,49 @@ class InternalTests(unittest.TestCase):
self.assertEqual(forced_value, desired_value)
def test_listify(self):
listify = mesonbuild.mesonlib.listify
# Test sanity
self.assertEqual([1], listify(1))
self.assertEqual([], listify([]))
self.assertEqual([1], listify([1]))
# Test flattening
self.assertEqual([1, 2, 3], listify([1, [2, 3]]))
self.assertEqual([1, 2, 3], listify([1, [2, [3]]]))
self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False))
# Test flattening and unholdering
holder1 = ObjectHolder(1)
holder3 = ObjectHolder(3)
self.assertEqual([holder1], listify(holder1))
self.assertEqual([holder1], listify([holder1]))
self.assertEqual([holder1, 2], listify([holder1, 2]))
self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]]))
self.assertEqual([1], listify(holder1, unholder=True))
self.assertEqual([1], listify([holder1], unholder=True))
self.assertEqual([1, 2], listify([holder1, 2], unholder=True))
self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True))
# Unholding doesn't work recursively when not flattening
self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False))
def test_extract_as_list(self):
extract = mesonbuild.mesonlib.extract_as_list
# Test sanity
kwargs = {'sources': [1, 2, 3]}
self.assertEqual([1, 2, 3], extract(kwargs, 'sources'))
self.assertEqual(kwargs, {'sources': [1, 2, 3]})
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True))
self.assertEqual(kwargs, {})
# Test unholding
holder3 = ObjectHolder(3)
kwargs = {'sources': [1, 2, holder3]}
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True))
self.assertEqual(kwargs, {'sources': [1, 2, holder3]})
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True))
self.assertEqual(kwargs, {})
# Test listification
kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))
class BasePlatformTests(unittest.TestCase):
def setUp(self):
@ -1298,6 +1341,100 @@ int main(int argc, char **argv) {
for i in targets:
self.assertPathExists(os.path.join(testdir, i))
def detect_prebuild_env(self):
if mesonbuild.mesonlib.is_windows():
object_suffix = 'obj'
else:
object_suffix = 'o'
static_suffix = 'a'
shared_suffix = 'so'
if shutil.which('cl'):
compiler = 'cl'
static_suffix = 'lib'
shared_suffix = 'dll'
elif shutil.which('cc'):
compiler = 'cc'
elif shutil.which('gcc'):
compiler = 'gcc'
else:
raise RuntimeError("Could not find C compiler.")
return (compiler, object_suffix, static_suffix, shared_suffix)
def pbcompile(self, compiler, source, objectfile, extra_args=[]):
if compiler == 'cl':
cmd = [compiler, '/nologo', '/Fo' + objectfile, '/c', source] + extra_args
else:
cmd = [compiler, '-c', source, '-o', objectfile] + extra_args
subprocess.check_call(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def test_prebuilt_object(self):
(compiler, object_suffix, _, _) = self.detect_prebuild_env()
tdir = os.path.join(self.unit_test_dir, '14 prebuilt object')
source = os.path.join(tdir, 'source.c')
objectfile = os.path.join(tdir, 'prebuilt.' + object_suffix)
self.pbcompile(compiler, source, objectfile)
try:
self.init(tdir)
self.build()
self.run_tests()
finally:
os.unlink(objectfile)
def test_prebuilt_static_lib(self):
(compiler, object_suffix, static_suffix, _) = self.detect_prebuild_env()
tdir = os.path.join(self.unit_test_dir, '15 prebuilt static')
source = os.path.join(tdir, 'libdir/best.c')
objectfile = os.path.join(tdir, 'libdir/best.' + object_suffix)
stlibfile = os.path.join(tdir, 'libdir/libbest.' + static_suffix)
if compiler == 'cl':
link_cmd = ['lib', '/NOLOGO', '/OUT:' + stlibfile, objectfile]
else:
link_cmd = ['ar', 'csr', stlibfile, objectfile]
self.pbcompile(compiler, source, objectfile)
try:
subprocess.check_call(link_cmd)
finally:
os.unlink(objectfile)
try:
self.init(tdir)
self.build()
self.run_tests()
finally:
os.unlink(stlibfile)
def test_prebuilt_shared_lib(self):
(compiler, object_suffix, _, shared_suffix) = self.detect_prebuild_env()
tdir = os.path.join(self.unit_test_dir, '16 prebuilt shared')
source = os.path.join(tdir, 'alexandria.c')
objectfile = os.path.join(tdir, 'alexandria.' + object_suffix)
if compiler == 'cl':
extra_args = []
shlibfile = os.path.join(tdir, 'alexandria.' + shared_suffix)
link_cmd = ['link', '/NOLOGO','/DLL', '/DEBUG', '/IMPLIB:' + os.path.join(tdir, 'alexandria.lib'), '/OUT:' + shlibfile, objectfile]
else:
extra_args = ['-fPIC']
shlibfile = os.path.join(tdir, 'libalexandria.' + shared_suffix)
link_cmd = [compiler, '-shared', '-o', shlibfile, objectfile]
if not mesonbuild.mesonlib.is_osx():
link_cmd += ['-Wl,-soname=libalexandria.so']
self.pbcompile(compiler, source, objectfile, extra_args=extra_args)
try:
subprocess.check_call(link_cmd)
finally:
os.unlink(objectfile)
try:
self.init(tdir)
self.build()
self.run_tests()
finally:
os.unlink(shlibfile)
if mesonbuild.mesonlib.is_windows():
# Clean up all the garbage MSVC writes in the
# source tree.
for fname in glob(os.path.join(tdir, 'alexandria.*')):
if os.path.splitext(fname)[1] not in ['.c', '.h']:
os.unlink(fname)
class FailureTests(BasePlatformTests):
'''

@ -9,21 +9,18 @@ add_project_arguments(['-DBOOST_LOG_DYN_LINK'],
# within one project. The need to be independent of each other.
# Use one without a library dependency and one with it.
nolinkdep = dependency('boost', modules: 'utility')
linkdep = dependency('boost', modules : ['thread', 'system'])
staticdep = dependency('boost', modules : ['thread', 'system'], static : true)
testdep = dependency('boost', modules : 'test')
testdep = dependency('boost', modules : ['unit_test_framework'])
nomoddep = dependency('boost')
extralibdep = dependency('boost', modules : ['thread', 'system', 'log_setup', 'log'])
nolinkexe = executable('nolinkedexe', 'nolinkexe.cc', dependencies : nolinkdep)
linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep)
staticexe = executable('staticlinkedexe', 'linkexe.cc', dependencies : staticdep)
unitexe = executable('utf', 'unit_test.cpp', dependencies: testdep)
nomodexe = executable('nomod', 'nomod.cpp', dependencies : nomoddep)
extralibexe = executable('extralibexe', 'extralib.cpp', dependencies : extralibdep)
test('Boost nolinktest', nolinkexe)
test('Boost linktest', linkexe)
test('Boost statictest', staticexe)
test('Boost UTF test', unitexe)

@ -1,12 +0,0 @@
#include<boost/utility.hpp>
class MyClass : boost::noncopyable {
public:
MyClass() {};
~MyClass() {};
};
int main(int argc, char **argv) {
MyClass obj;
return 0;
}

@ -70,5 +70,15 @@ foreach qt : ['qt4', 'qt5']
dependencies : qtcore)
test(qt + 'maninclude', qtmaninclude)
# building Qt plugins implies to give include path to moc
plugin_includes = include_directories('pluginInterface', 'plugin')
pluginpreprocess = qtmodule.preprocess(
moc_headers : 'plugin/plugin.h',
include_directories : plugin_includes
)
plugin = library('plugin', 'plugin/plugin.cpp', pluginpreprocess,
include_directories : plugin_includes,
dependencies : qtcore)
endif
endforeach

@ -0,0 +1,7 @@
#include "plugin.h"
#include <QFile>
QString plugin1::getResource()
{
return "hello world";
}

@ -0,0 +1,11 @@
#pragma once
#include <plugin_if.h>
class plugin1:public QObject,public PluginInterface
{
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "demo.PluginInterface" FILE "plugin.json")
public:
QString getResource() override;
};

@ -0,0 +1,21 @@
#ifndef PLUGIN_IF_H
#define PLUGIN_IF_H
#include <QString>
#include <QtPlugin>
/**
* @brief Interface for a plugin
*/
class PluginInterface
{
public:
virtual ~PluginInterface() = default;
/// Initializes the plugin
virtual QString getResource() = 0;
};
Q_DECLARE_INTERFACE(PluginInterface, "demo.PluginInterface")
#endif

@ -19,6 +19,7 @@ dep1gir = gnome.generate_gir(
namespace : 'MesonDep1',
symbol_prefix : 'meson',
identifier_prefix : 'Meson',
header: 'dep1.h',
includes : ['GObject-2.0', 'MesonDep2-1.0'],
dependencies : [dep2_dep],
install : true

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

@ -0,0 +1,6 @@
#include"alexandria.h"
#include<stdio.h>
void alexandria_visit() {
printf("You are surrounded by wisdom and knowledge. You feel enlightened.\n");
}

@ -0,0 +1,20 @@
#pragma once
/* Both funcs here for simplicity. */
#if defined _WIN32 || defined __CYGWIN__
#if defined BUILDING_DLL
#define DLL_PUBLIC __declspec(dllexport)
#else
#define DLL_PUBLIC __declspec(dllimport)
#endif
#else
#if defined __GNUC__
#define DLL_PUBLIC __attribute__ ((visibility("default")))
#else
#pragma message ("Compiler does not support symbol visibility.")
#define DLL_PUBLIC
#endif
#endif
void DLL_PUBLIC alexandria_visit();

@ -0,0 +1,10 @@
#include<alexandria.h>
#include<stdio.h>
int main(int argc, char **argv) {
printf("Ahh, another visitor. Stay a while.\n");
printf("You enter the library.\n\n");
alexandria_visit();
printf("\nYou decided not to stay forever.\n");
return 0;
}

@ -0,0 +1,14 @@
project('prebuilt shared library', 'c')
cc = meson.get_compiler('c')
shlib = cc.find_library('alexandria', dirs : meson.current_source_dir())
exe = executable('patron', 'patron.c', dependencies : shlib)
test('visitation', exe)
d = declare_dependency(dependencies : shlib)
exe2 = executable('another_visitor', 'another_visitor.c',
dependencies : d)
test('another', exe2)

@ -0,0 +1,8 @@
#include<alexandria.h>
#include<stdio.h>
int main(int argc, char **argv) {
printf("You are standing outside the Great Library of Alexandria.\n");
printf("You decide to go inside.\n\n");
alexandria_visit();
}

@ -0,0 +1,180 @@
#!/usr/bin/env python3
# Copyright 2017 Niklas Claesson
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This is two implementations for how to get module names from the boost
sources. One relies on json metadata files in the sources, the other relies on
the folder names.
Run the tool in the boost directory and append the stdout to the misc.py:
boost/$ path/to/meson/tools/boost_names.py >> path/to/meson/dependencies/misc.py
"""
import sys
import os
import collections
import pprint
import json
import re
Module = collections.namedtuple('Module', ['dirname', 'name', 'libnames'])
Module.__repr__ = lambda self: str((self.dirname, self.name, self.libnames))
LIBS = 'libs'
manual_map = {
'callable_traits': 'Call Traits',
'crc': 'CRC',
'dll': 'DLL',
'gil': 'GIL',
'graph_parallel': 'GraphParallel',
'icl': 'ICL',
'io': 'IO State Savers',
'msm': 'Meta State Machine',
'mpi': 'MPI',
'mpl': 'MPL',
'multi_array': 'Multi-Array',
'multi_index': 'Multi-Index',
'numeric': 'Numeric Conversion',
'ptr_container': 'Pointer Container',
'poly_collection': 'PolyCollection',
'qvm': 'QVM',
'throw_exception': 'ThrowException',
'tti': 'TTI',
'vmd': 'VMD',
}
extra = [
Module('utility', 'Compressed Pair', []),
Module('core', 'Enable If', []),
Module('functional', 'Functional/Factory', []),
Module('functional', 'Functional/Forward', []),
Module('functional', 'Functional/Hash', []),
Module('functional', 'Functional/Overloaded Function', []),
Module('utility', 'Identity Type', []),
Module('utility', 'In Place Factory, Typed In Place Factory', []),
Module('numeric', 'Interval', []),
Module('math', 'Math Common Factor', []),
Module('math', 'Math Octonion', []),
Module('math', 'Math Quaternion', []),
Module('math', 'Math/Special Functions', []),
Module('math', 'Math/Statistical Distributions', []),
Module('bind', 'Member Function', []),
Module('algorithm', 'Min-Max', []),
Module('numeric', 'Odeint', []),
Module('utility', 'Operators', []),
Module('core', 'Ref', []),
Module('utility', 'Result Of', []),
Module('algorithm', 'String Algo', []),
Module('core', 'Swap', []),
Module('', 'Tribool', []),
Module('numeric', 'uBLAS', []),
Module('utility', 'Value Initialized', []),
]
# Cannot find the following modules in the documentation of boost
not_modules = ['beast', 'logic', 'mp11', 'winapi']
def eprint(message):
print(message, file=sys.stderr)
def get_library_names(jamfile):
libs = []
with open(jamfile) as jamfh:
jam = jamfh.read()
res = re.finditer(r'^lib[\s]+([A-Za-z0-9_]+)([^;]*);', jam, re.MULTILINE | re.DOTALL)
for matches in res:
if ':' in matches.group(2):
libs.append(matches.group(1))
return libs
def exists(modules, module):
return len([x for x in modules if x.dirname == module.dirname]) != 0
def get_modules(init=extra):
modules = init
for directory in os.listdir(LIBS):
if not os.path.isdir(os.path.join(LIBS, directory)):
continue
if directory in not_modules:
continue
jamfile = os.path.join(LIBS, directory, 'build', 'Jamfile.v2')
if os.path.isfile(jamfile):
libs = get_library_names(jamfile)
else:
libs = []
if directory in manual_map.keys():
modname = manual_map[directory]
else:
modname = directory.replace('_', ' ').title()
modules.append(Module(directory, modname, libs))
return modules
def get_modules_2():
modules = []
for (root, dirs, files) in os.walk(LIBS):
for f in files:
if f == "libraries.json":
projectdir = os.path.dirname(root)
jamfile = os.path.join(projectdir, 'build', 'Jamfile.v2')
if os.path.isfile(jamfile):
libs = get_library_names(jamfile)
else:
libs = []
# Get metadata for module
jsonfile = os.path.join(root, f)
with open(jsonfile) as jsonfh:
boost_modules = json.loads(jsonfh.read())
if(isinstance(boost_modules, dict)):
boost_modules = [boost_modules]
for boost_module in boost_modules:
modules.append(Module(boost_module['key'], boost_module['name'], libs))
# Some subprojects do not have meta directory with json file. Find those
jsonless_modules = [x for x in get_modules([]) if not exists(modules, x)]
for module in jsonless_modules:
eprint("WARNING: {} does not have meta/libraries.json. Will guess pretty name '{}'".format(module.dirname, module.name))
modules.extend(jsonless_modules)
return modules
def main(args):
if not os.path.isdir(LIBS):
eprint("ERROR: script must be run in boost source directory")
# It will pick jsonless algorithm if 1 is given as argument
impl = 0
if len(args) > 1:
if args[1] == '1':
impl = 1
if impl == 1:
modules = get_modules()
else:
modules = get_modules_2()
sorted_modules = sorted(modules, key=lambda module: module.name.lower())
sorted_modules = [x[2] for x in sorted_modules if x[2]]
sorted_modules = sum(sorted_modules, [])
sorted_modules = [x for x in sorted_modules if x.startswith('boost')]
pp = pprint.PrettyPrinter()
pp.pprint(sorted_modules)
if __name__ == '__main__':
main(sys.argv)
Loading…
Cancel
Save