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 - arch: x86
compiler: msvc2015 compiler: msvc2015
backend: ninja backend: ninja
BOOST_ROOT: C:\Libraries\Boost_1_59_0
- arch: x86 - arch: x86
compiler: msvc2015 compiler: msvc2015
backend: vs2015 backend: vs2015
BOOST_ROOT: C:\Libraries\Boost_1_59_0
- arch: x64 - arch: x64
compiler: cygwin compiler: cygwin
@ -36,11 +38,13 @@ environment:
compiler: msvc2017 compiler: msvc2017
backend: ninja backend: ninja
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
BOOST_ROOT: C:\Libraries\Boost_1_64_0
- arch: x64 - arch: x64
compiler: msvc2017 compiler: msvc2017
backend: vs2017 backend: vs2017
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
BOOST_ROOT: C:\Libraries\Boost_1_64_0
platform: platform:
- x64 - x64
@ -59,8 +63,6 @@ init:
install: install:
- cmd: set "ORIG_PATH=%PATH%" - 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 # Use a Ninja with QuLogic's patch: https://github.com/ninja-build/ninja/issues/1219
- cmd: set "MESON_FIXED_NINJA=1" - 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') - 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. # 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) - 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. # 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%==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% ) - 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 ##
Boost is not a single dependency but rather a group of different Boost is not a single dependency but rather a group of different
libraries. To use Boost with Meson, simply list which Boost modules libraries. To use Boost headers-only libraries, simply add Boost as a
you would like to use. 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 ```meson
boost_dep = dependency('boost', modules : ['thread', 'utility']) 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 can set the BOOST_ROOT, BOOST_INCLUDEDIR, and/or BOOST_LIBRARYDIR
environment variables. 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 ##
GTest and GMock come as sources that must be compiled as part of your 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 * `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 * `include_directories`: extra include paths to look for gir files
* `install`: if true, install the generated files * `install`: if true, install the generated files

@ -5,17 +5,19 @@ tools and steps required for Qt. The module has one method.
## preprocess ## 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 `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 opaque object that should be passed to a main build target. A simple
example would look like this: example would look like this:
```meson ```meson
qt5 = import('qt5') qt5 = import('qt5')
qt5_dep = dependency('qt5', modules: ['Core', 'Gui']) 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, executable('myprog', 'main.cpp', 'myclass.cpp', moc_files,
include_directories: inc,
dependencies : qt5_dep) 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: 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 - `name_prefix` the string that will be used as the prefix for the
target by overriding the default (only used for libraries). By target output filename by overriding the default (only used for
default this is `lib` on all platforms and compilers except with libraries). By default this is `lib` on all platforms and compilers
MSVC where it is omitted. 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 - `rust_crate_type` specifies the crate type for Rust
libraries. Defaults to `dylib` for shared libraries and `rlib` for libraries. Defaults to `dylib` for shared libraries and `rlib` for
static libraries. static libraries.
@ -1614,7 +1623,7 @@ during tests. It should be passed as the `env` keyword argument to
tests. It has the following methods. tests. It has the following methods.
- `append(varname, value)` appends the given value to the old value of - `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 : ';')` produces `BOB;BAR` if `FOO` had the value `BOB` and plain
`BAR` if the value was not defined. If the separator is not `BAR` if the value was not defined. If the separator is not
specified explicitly, the default path separator for the host 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)) raise MesonException(m.format(target.name))
return l 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): def determine_rpath_dirs(self, target):
link_deps = target.get_all_link_deps() link_deps = target.get_all_link_deps()
result = [] result = []
@ -314,6 +333,9 @@ class Backend:
prospective = self.get_target_dir(ld) prospective = self.get_target_dir(ld)
if prospective not in result: if prospective not in result:
result.append(prospective) result.append(prospective)
for rp in self.rpaths_for_bundled_shared_libraries(target):
if rp not in result:
result += [rp]
return result return result
def object_filename_from_source(self, target, source, is_unity): 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)) dirseg = os.path.join(self.environment.get_build_dir(), self.get_target_dir(ld))
if dirseg not in result: if dirseg not in result:
result.append(dirseg) 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 return result
def write_benchmark_file(self, datafile): def write_benchmark_file(self, datafile):

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

@ -172,6 +172,9 @@ class CCompiler(Compiler):
def get_linker_search_args(self, dirname): def get_linker_search_args(self, dirname):
return ['-L' + dirname] return ['-L' + dirname]
def get_default_include_dirs(self):
return []
def gen_import_library_args(self, implibname): def gen_import_library_args(self, implibname):
""" """
The name of the outputted import library The name of the outputted import library
@ -1056,3 +1059,34 @@ class VisualStudioCCompiler(CCompiler):
# and the can not be called. # and the can not be called.
return None return None
return vs32_instruction_set_args.get(instruction_set, 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. # limitations under the License.
import contextlib, os.path, re, tempfile import contextlib, os.path, re, tempfile
import subprocess
from ..linkers import StaticLinker from ..linkers import StaticLinker
from .. import coredata from .. import coredata
@ -917,6 +918,35 @@ def get_largefile_args(compiler):
# those features explicitly. # those features explicitly.
return [] 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: class GnuCompiler:
# Functionality that is common to all GNU family compilers. # Functionality that is common to all GNU family compilers.
@ -998,6 +1028,9 @@ class GnuCompiler:
def get_instruction_set_args(self, instruction_set): def get_instruction_set_args(self, instruction_set):
return gnulike_instruction_set_args.get(instruction_set, None) 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: class ClangCompiler:
def __init__(self, clang_type): def __init__(self, clang_type):
@ -1082,6 +1115,9 @@ class ClangCompiler:
def get_instruction_set_args(self, instruction_set): def get_instruction_set_args(self, instruction_set):
return gnulike_instruction_set_args.get(instruction_set, None) 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 # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1
class IntelCompiler: class IntelCompiler:
@ -1132,3 +1168,6 @@ class IntelCompiler:
# if self.icc_type == ICC_OSX: # if self.icc_type == ICC_OSX:
# return ['-bundle'] # return ['-bundle']
return ['-shared'] 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 mlog
from .. import mesonlib from .. import mesonlib
from ..mesonlib import MesonException, Popen_safe, flatten, version_compare_many, listify from ..mesonlib import MesonException, Popen_safe, version_compare_many, listify
# These must be defined in this file to avoid cyclical references. # These must be defined in this file to avoid cyclical references.
@ -586,7 +586,7 @@ class ExtraFrameworkDependency(ExternalDependency):
def get_dep_identifier(name, kwargs, want_cross): def get_dep_identifier(name, kwargs, want_cross):
# Need immutable objects since the identifier will be used as a dict key # Need immutable objects since the identifier will be used as a dict key
version_reqs = flatten(kwargs.get('version', [])) version_reqs = listify(kwargs.get('version', []))
if isinstance(version_reqs, list): if isinstance(version_reqs, list):
version_reqs = frozenset(version_reqs) version_reqs = frozenset(version_reqs)
identifier = (name, version_reqs, want_cross) identifier = (name, version_reqs, want_cross)
@ -599,7 +599,7 @@ def get_dep_identifier(name, kwargs, want_cross):
continue continue
# All keyword arguments are strings, ints, or lists (or lists of lists) # All keyword arguments are strings, ints, or lists (or lists of lists)
if isinstance(value, list): if isinstance(value, list):
value = frozenset(flatten(value)) value = frozenset(listify(value))
identifier += (key, value) identifier += (key, value)
return identifier return identifier

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

@ -18,7 +18,6 @@ import glob
import os import os
import re import re
import shlex import shlex
import stat
import shutil import shutil
import sysconfig import sysconfig
@ -30,77 +29,153 @@ from ..environment import detect_cpu_family
from .base import DependencyException, DependencyMethods from .base import DependencyException, DependencyMethods
from .base import ExternalDependency, ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency 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): 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): def __init__(self, environment, kwargs):
super().__init__('boost', environment, 'cpp', 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 self.libdir = None
try:
if 'BOOST_ROOT' in os.environ:
self.boost_root = os.environ['BOOST_ROOT'] self.boost_root = os.environ['BOOST_ROOT']
self.boost_roots = [self.boost_root]
if not os.path.isabs(self.boost_root): if not os.path.isabs(self.boost_root):
raise DependencyException('BOOST_ROOT must be an absolute path.') raise DependencyException('BOOST_ROOT must be an absolute path.')
except KeyError: if 'BOOST_INCLUDEDIR' in os.environ:
self.boost_root = None 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.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(): if mesonlib.is_windows():
self.boost_root = self.detect_win_root() self.boost_roots = self.detect_win_roots()
self.incdir = self.boost_root
else: else:
if 'BOOST_INCLUDEDIR' in os.environ: self.boost_roots = self.detect_nix_roots()
self.incdir = os.environ['BOOST_INCLUDEDIR']
else: if self.boost_root is None and not self.boost_roots:
self.incdir = '/usr/include' 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 = {}
self.lib_modules_mt = {}
self.detect_version() self.detect_version()
self.requested_modules = self.get_requested(kwargs)
module_str = ', '.join(self.requested_modules)
if self.is_found: if self.is_found:
self.detect_src_modules()
self.detect_lib_modules() self.detect_lib_modules()
mlog.debug('Boost library directory is', mlog.bold(self.libdir))
self.validate_requested() self.validate_requested()
if self.boost_root is not None: self.log_success()
info = self.version + ', ' + self.boost_root else:
else: self.log_fail()
info = self.version
mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info) 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: 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): def detect_win_roots(self):
globtext = 'c:\\local\\boost_*' res = []
# Where boost documentation says it should be
globtext = 'C:\\Program Files\\boost\\boost_*'
files = glob.glob(globtext) files = glob.glob(globtext)
if len(files) > 0: res.extend(files)
return files[0]
return 'C:\\' # 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): def get_compile_args(self):
args = [] args = []
if self.boost_root is not None: include_dir = self.incdir
if mesonlib.is_windows():
include_dir = self.boost_root
else:
include_dir = os.path.join(self.boost_root, 'include')
else:
include_dir = self.incdir
# Use "-isystem" when including boost headers instead of "-I" # Use "-isystem" when including boost headers instead of "-I"
# to avoid compiler warnings/failures when "-Werror" is used # 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 # and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors
# for more details # for more details
# TODO: The correct solution would probably be to ask the if include_dir and include_dir not in self.compiler.get_default_include_dirs():
# 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')):
args.append("".join(self.compiler.get_include_args(include_dir, True))) args.append("".join(self.compiler.get_include_args(include_dir, True)))
return args return args
@ -136,19 +200,23 @@ class BoostDependency(ExternalDependency):
for c in candidates: for c in candidates:
if not isinstance(c, str): if not isinstance(c, str):
raise DependencyException('Boost module argument is not a string.') 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 return candidates
def validate_requested(self): def validate_requested(self):
for m in self.requested_modules: 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: if 'boost_' + m not in self.lib_modules:
msg = 'Requested Boost module {!r} not found' msg = 'Requested Boost library {!r} not found'
raise DependencyException(msg.format(m)) raise DependencyException(msg.format(m))
def detect_version(self): def detect_version(self):
try: try:
ifile = open(os.path.join(self.boost_inc_subdir, 'version.hpp')) ifile = open(os.path.join(self.incdir, 'boost', 'version.hpp'))
except FileNotFoundError: except FileNotFoundError:
return return
except TypeError:
return
with ifile: with ifile:
for line in ifile: for line in ifile:
if line.startswith("#define") and 'BOOST_LIB_VERSION' in line: if line.startswith("#define") and 'BOOST_LIB_VERSION' in line:
@ -158,12 +226,6 @@ class BoostDependency(ExternalDependency):
self.is_found = True self.is_found = True
return 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): def detect_lib_modules(self):
if mesonlib.is_windows(): if mesonlib.is_windows():
return self.detect_lib_modules_win() return self.detect_lib_modules_win()
@ -171,32 +233,79 @@ class BoostDependency(ExternalDependency):
def detect_lib_modules_win(self): def detect_lib_modules_win(self):
arch = detect_cpu_family(self.env.coredata.compilers) arch = detect_cpu_family(self.env.coredata.compilers)
# Guess the libdir compiler_ts = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version().split('.')
if arch == 'x86': compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1])
gl = 'lib32*' if not self.libdir:
elif arch == 'x86_64': # The libdirs in the distributed binaries
gl = 'lib64*' if arch == 'x86':
else: gl = 'lib32*'
# Does anyone do Boost cross-compiling to other archs on Windows? elif arch == 'x86_64':
gl = None gl = 'lib64*'
# See if the libdir is valid else:
if gl: # Does anyone do Boost cross-compiling to other archs on Windows?
libdir = glob.glob(os.path.join(self.boost_root, gl)) gl = None
else: if self.boost_root:
libdir = [] roots = [self.boost_root]
# Can't find libdir, bail else:
if not libdir: 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 return
libdir = libdir[0]
# Don't override what was set in the environment for name in self.need_static_link:
if self.libdir: libname = "lib{}".format(name) + '-' + compiler
self.libdir = libdir if self.is_multithreading:
globber = 'libboost_*-gd-*.lib' if self.static else 'boost_*-gd-*.lib' # FIXME libname = libname + '-mt'
for entry in glob.glob(os.path.join(libdir, globber)): 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) (_, fname) = os.path.split(entry)
base = fname.split('_', 1)[1] modname = fname.split('-', 1)
modname = base.split('-', 1)[0] if len(modname) > 1:
self.lib_modules_mt[modname] = fname 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): def detect_lib_modules_nix(self):
if self.static: if self.static:
@ -214,25 +323,32 @@ class BoostDependency(ExternalDependency):
else: else:
libdirs = [os.path.join(self.boost_root, 'lib')] libdirs = [os.path.join(self.boost_root, 'lib')]
for libdir in libdirs: 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)): for entry in glob.glob(os.path.join(libdir, globber)):
lib = os.path.basename(entry) 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 # I'm not 100% sure what to do here. Some distros
# have modules such as thread only as -mt versions. # have modules such as thread only as -mt versions.
if entry.endswith('-mt.{}'.format(libsuffix)): # On debian all packages are built threading=multi
self.lib_modules_mt[name] = True # but not suffixed with -mt.
else: # FIXME: implement detect_lib_modules_{debian, redhat, ...}
self.lib_modules[name] = True 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): def get_win_link_args(self):
args = [] args = []
# TODO: should this check self.libdir? # TODO: should this check self.libdir?
if self.boost_root: if self.libdir:
args.append('-L' + self.libdir) args.append('-L' + self.libdir)
for module in self.requested_modules: for lib in self.requested_modules:
module = BoostDependency.name2lib.get(module, module) args.append(self.lib_modules['boost_' + lib])
if module in self.lib_modules_mt:
args.append(self.lib_modules_mt[module])
return args return args
def get_link_args(self): def get_link_args(self):
@ -243,33 +359,14 @@ class BoostDependency(ExternalDependency):
args.append('-L' + os.path.join(self.boost_root, 'lib')) args.append('-L' + os.path.join(self.boost_root, 'lib'))
elif self.libdir: elif self.libdir:
args.append('-L' + self.libdir) args.append('-L' + self.libdir)
for module in self.requested_modules: for lib in self.requested_modules:
module = BoostDependency.name2lib.get(module, module)
libname = 'boost_' + module
# The compiler's library detector is the most reliable so use that first. # 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 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 args += default_detect
if emon_args is not None: elif lib in self.lib_modules:
args += emon_args linkcmd = '-l' + lib
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'
args.append(linkcmd) args.append(linkcmd)
if module == 'unit_testing_framework':
args.append('-lboost_test_exec_monitor-mt')
return args return args
def get_sources(self): def get_sources(self):
@ -664,3 +761,78 @@ class CupsDependency(ExternalDependency):
return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG, DependencyMethods.EXTRAFRAMEWORK] return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG, DependencyMethods.EXTRAFRAMEWORK]
else: else:
return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG] 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.') raise InvalidArguments('Function accepts only strings, integers, lists and lists thereof.')
class ObjectHolder:
def __init__(self, obj):
self.held_object = obj
def __repr__(self):
return '<Holder: {!r}>'.format(self.held_object)
class TryRunResultHolder(InterpreterObject): class TryRunResultHolder(InterpreterObject):
def __init__(self, res): def __init__(self, res):
super().__init__() super().__init__()
@ -117,17 +125,18 @@ class RunProcess(InterpreterObject):
def stderr_method(self, args, kwargs): def stderr_method(self, args, kwargs):
return self.stderr return self.stderr
class ConfigureFileHolder(InterpreterObject): class ConfigureFileHolder(InterpreterObject, ObjectHolder):
def __init__(self, subdir, sourcename, targetname, configuration_data): def __init__(self, subdir, sourcename, targetname, configuration_data):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = build.ConfigureFile(subdir, sourcename, targetname, configuration_data) ObjectHolder.__init__(self, build.ConfigureFile(subdir, sourcename,
targetname, configuration_data))
class EnvironmentVariablesHolder(MutableInterpreterObject): class EnvironmentVariablesHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self): def __init__(self):
super().__init__() MutableInterpreterObject.__init__(self)
self.held_object = build.EnvironmentVariables() ObjectHolder.__init__(self, build.EnvironmentVariables())
self.methods.update({'set': self.set_method, self.methods.update({'set': self.set_method,
'append': self.append_method, 'append': self.append_method,
'prepend': self.prepend_method, 'prepend': self.prepend_method,
@ -158,11 +167,11 @@ class EnvironmentVariablesHolder(MutableInterpreterObject):
self.add_var(self.held_object.prepend, args, kwargs) self.add_var(self.held_object.prepend, args, kwargs)
class ConfigurationDataHolder(MutableInterpreterObject): class ConfigurationDataHolder(MutableInterpreterObject, ObjectHolder):
def __init__(self): def __init__(self):
super().__init__() MutableInterpreterObject.__init__(self)
self.used = False # These objects become immutable after use in configure_file. self.used = False # These objects become immutable after use in configure_file.
self.held_object = build.ConfigurationData() ObjectHolder.__init__(self, build.ConfigurationData())
self.methods.update({'set': self.set_method, self.methods.update({'set': self.set_method,
'set10': self.set10_method, 'set10': self.set10_method,
'set_quoted': self.set_quoted_method, 'set_quoted': self.set_quoted_method,
@ -242,10 +251,10 @@ class ConfigurationDataHolder(MutableInterpreterObject):
# Interpreter objects can not be pickled so we must have # Interpreter objects can not be pickled so we must have
# these wrappers. # these wrappers.
class DependencyHolder(InterpreterObject): class DependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep): def __init__(self, dep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = dep ObjectHolder.__init__(self, dep)
self.methods.update({'found': self.found_method, self.methods.update({'found': self.found_method,
'type_name': self.type_name_method, 'type_name': self.type_name_method,
'version': self.version_method, 'version': self.version_method,
@ -272,10 +281,10 @@ class DependencyHolder(InterpreterObject):
raise InterpreterException('Variable name must be a string.') raise InterpreterException('Variable name must be a string.')
return self.held_object.get_pkgconfig_variable(varname) return self.held_object.get_pkgconfig_variable(varname)
class InternalDependencyHolder(InterpreterObject): class InternalDependencyHolder(InterpreterObject, ObjectHolder):
def __init__(self, dep): def __init__(self, dep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = dep ObjectHolder.__init__(self, dep)
self.methods.update({'found': self.found_method, self.methods.update({'found': self.found_method,
'version': self.version_method, 'version': self.version_method,
}) })
@ -286,10 +295,10 @@ class InternalDependencyHolder(InterpreterObject):
def version_method(self, args, kwargs): def version_method(self, args, kwargs):
return self.held_object.get_version() return self.held_object.get_version()
class ExternalProgramHolder(InterpreterObject): class ExternalProgramHolder(InterpreterObject, ObjectHolder):
def __init__(self, ep): def __init__(self, ep):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = ep ObjectHolder.__init__(self, ep)
self.methods.update({'found': self.found_method, self.methods.update({'found': self.found_method,
'path': self.path_method}) 'path': self.path_method})
@ -308,10 +317,10 @@ class ExternalProgramHolder(InterpreterObject):
def get_name(self): def get_name(self):
return self.held_object.get_name() return self.held_object.get_name()
class ExternalLibraryHolder(InterpreterObject): class ExternalLibraryHolder(InterpreterObject, ObjectHolder):
def __init__(self, el): def __init__(self, el):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = el ObjectHolder.__init__(self, el)
self.methods.update({'found': self.found_method}) self.methods.update({'found': self.found_method})
def found(self): def found(self):
@ -332,11 +341,11 @@ class ExternalLibraryHolder(InterpreterObject):
def get_exe_args(self): def get_exe_args(self):
return self.held_object.get_exe_args() return self.held_object.get_exe_args()
class GeneratorHolder(InterpreterObject): class GeneratorHolder(InterpreterObject, ObjectHolder):
def __init__(self, interpreter, args, kwargs): def __init__(self, interpreter, args, kwargs):
super().__init__() InterpreterObject.__init__(self)
self.interpreter = interpreter self.interpreter = interpreter
self.held_object = build.Generator(args, kwargs) ObjectHolder.__init__(self, build.Generator(args, kwargs))
self.methods.update({'process': self.process_method}) self.methods.update({'process': self.process_method})
def process_method(self, args, kwargs): def process_method(self, args, kwargs):
@ -345,13 +354,13 @@ class GeneratorHolder(InterpreterObject):
return GeneratedListHolder(gl) return GeneratedListHolder(gl)
class GeneratedListHolder(InterpreterObject): class GeneratedListHolder(InterpreterObject, ObjectHolder):
def __init__(self, arg1, extra_args=[]): def __init__(self, arg1, extra_args=[]):
super().__init__() InterpreterObject.__init__(self)
if isinstance(arg1, GeneratorHolder): if isinstance(arg1, GeneratorHolder):
self.held_object = build.GeneratedList(arg1.held_object, extra_args) ObjectHolder.__init__(self, build.GeneratedList(arg1.held_object, extra_args))
else: else:
self.held_object = arg1 ObjectHolder.__init__(self, arg1)
def __repr__(self): def __repr__(self):
r = '<{}: {!r}>' r = '<{}: {!r}>'
@ -360,14 +369,15 @@ class GeneratedListHolder(InterpreterObject):
def add_file(self, a): def add_file(self, a):
self.held_object.add_file(a) self.held_object.add_file(a)
class BuildMachine(InterpreterObject): class BuildMachine(InterpreterObject, ObjectHolder):
def __init__(self, compilers): def __init__(self, compilers):
self.compilers = compilers self.compilers = compilers
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
self.held_object = environment.MachineInfo(environment.detect_system(), held_object = environment.MachineInfo(environment.detect_system(),
environment.detect_cpu_family(self.compilers), environment.detect_cpu_family(self.compilers),
environment.detect_cpu(self.compilers), environment.detect_cpu(self.compilers),
sys.byteorder) sys.byteorder)
ObjectHolder.__init__(self, held_object)
self.methods.update({'system': self.system_method, self.methods.update({'system': self.system_method,
'cpu_family': self.cpu_family_method, 'cpu_family': self.cpu_family_method,
'cpu': self.cpu_method, 'cpu': self.cpu_method,
@ -388,7 +398,7 @@ class BuildMachine(InterpreterObject):
# This class will provide both host_machine and # This class will provide both host_machine and
# target_machine # target_machine
class CrossMachineInfo(InterpreterObject): class CrossMachineInfo(InterpreterObject, ObjectHolder):
def __init__(self, cross_info): def __init__(self, cross_info):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'} minimum_cross_info = {'cpu', 'cpu_family', 'endian', 'system'}
@ -397,10 +407,11 @@ class CrossMachineInfo(InterpreterObject):
'Machine info is currently {}\n'.format(cross_info) + 'Machine info is currently {}\n'.format(cross_info) +
'but is missing {}.'.format(minimum_cross_info - set(cross_info))) 'but is missing {}.'.format(minimum_cross_info - set(cross_info)))
self.info = cross_info self.info = cross_info
self.held_object = environment.MachineInfo(cross_info['system'], minfo = environment.MachineInfo(cross_info['system'],
cross_info['cpu_family'], cross_info['cpu_family'],
cross_info['cpu'], cross_info['cpu'],
cross_info['endian']) cross_info['endian'])
ObjectHolder.__init__(self, minfo)
self.methods.update({'system': self.system_method, self.methods.update({'system': self.system_method,
'cpu': self.cpu_method, 'cpu': self.cpu_method,
'cpu_family': self.cpu_family_method, 'cpu_family': self.cpu_family_method,
@ -419,10 +430,10 @@ class CrossMachineInfo(InterpreterObject):
def endian_method(self, args, kwargs): def endian_method(self, args, kwargs):
return self.held_object.endian return self.held_object.endian
class IncludeDirsHolder(InterpreterObject): class IncludeDirsHolder(InterpreterObject, ObjectHolder):
def __init__(self, idobj): def __init__(self, idobj):
super().__init__() InterpreterObject.__init__(self)
self.held_object = idobj ObjectHolder.__init__(self, idobj)
class Headers(InterpreterObject): class Headers(InterpreterObject):
@ -447,10 +458,10 @@ class Headers(InterpreterObject):
def get_custom_install_dir(self): def get_custom_install_dir(self):
return self.custom_install_dir return self.custom_install_dir
class DataHolder(InterpreterObject): class DataHolder(InterpreterObject, ObjectHolder):
def __init__(self, data): def __init__(self, data):
super().__init__() InterpreterObject.__init__(self)
self.held_object = data ObjectHolder.__init__(self, data)
def get_source_subdir(self): def get_source_subdir(self):
return self.held_object.source_subdir return self.held_object.source_subdir
@ -495,20 +506,20 @@ class Man(InterpreterObject):
def get_sources(self): def get_sources(self):
return self.sources return self.sources
class GeneratedObjectsHolder(InterpreterObject): class GeneratedObjectsHolder(InterpreterObject, ObjectHolder):
def __init__(self, held_object): def __init__(self, held_object):
super().__init__() InterpreterObject.__init__(self)
self.held_object = held_object ObjectHolder.__init__(self, held_object)
class TargetHolder(InterpreterObject): class TargetHolder(InterpreterObject, ObjectHolder):
def __init__(self): def __init__(self, target, interp):
super().__init__() InterpreterObject.__init__(self)
ObjectHolder.__init__(self, target)
self.interpreter = interp
class BuildTargetHolder(TargetHolder): class BuildTargetHolder(TargetHolder):
def __init__(self, target, interp): def __init__(self, target, interp):
super().__init__() super().__init__(target, interp)
self.held_object = target
self.interpreter = interp
self.methods.update({'extract_objects': self.extract_objects_method, self.methods.update({'extract_objects': self.extract_objects_method,
'extract_all_objects': self.extract_all_objects_method, 'extract_all_objects': self.extract_all_objects_method,
'get_id': self.get_id_method, 'get_id': self.get_id_method,
@ -566,16 +577,14 @@ class JarHolder(BuildTargetHolder):
def __init__(self, target, interp): def __init__(self, target, interp):
super().__init__(target, interp) super().__init__(target, interp)
class CustomTargetIndexHolder(InterpreterObject): class CustomTargetIndexHolder(InterpreterObject, ObjectHolder):
def __init__(self, object_to_hold): def __init__(self, object_to_hold):
super().__init__() InterpreterObject.__init__(self)
self.held_object = object_to_hold ObjectHolder.__init__(self, object_to_hold)
class CustomTargetHolder(TargetHolder): class CustomTargetHolder(TargetHolder):
def __init__(self, object_to_hold, interp): def __init__(self, target, interp):
super().__init__() super().__init__(target, interp)
self.held_object = object_to_hold
self.interpreter = interp
self.methods.update({'full_path': self.full_path_method, self.methods.update({'full_path': self.full_path_method,
}) })
@ -596,10 +605,10 @@ class CustomTargetHolder(TargetHolder):
def __delitem__(self, index): def __delitem__(self, index):
raise InterpreterException('Cannot delete a member of a CustomTarget') raise InterpreterException('Cannot delete a member of a CustomTarget')
class RunTargetHolder(InterpreterObject): class RunTargetHolder(InterpreterObject, ObjectHolder):
def __init__(self, name, command, args, dependencies, subdir): def __init__(self, name, command, args, dependencies, subdir):
super().__init__() InterpreterObject.__init__(self)
self.held_object = build.RunTarget(name, command, args, dependencies, subdir) ObjectHolder.__init__(self, build.RunTarget(name, command, args, dependencies, subdir))
def __repr__(self): def __repr__(self):
r = '<{} {}: {}>' r = '<{} {}: {}>'
@ -625,11 +634,11 @@ class Test(InterpreterObject):
def get_name(self): def get_name(self):
return self.name return self.name
class SubprojectHolder(InterpreterObject): class SubprojectHolder(InterpreterObject, ObjectHolder):
def __init__(self, subinterpreter): def __init__(self, subinterpreter):
super().__init__() InterpreterObject.__init__(self)
self.held_object = subinterpreter ObjectHolder.__init__(self, subinterpreter)
self.methods.update({'get_variable': self.get_variable_method, self.methods.update({'get_variable': self.get_variable_method,
}) })
@ -1056,11 +1065,11 @@ ModuleState = namedtuple('ModuleState', [
'man', 'global_args', 'project_args', 'build_machine', 'host_machine', 'man', 'global_args', 'project_args', 'build_machine', 'host_machine',
'target_machine']) 'target_machine'])
class ModuleHolder(InterpreterObject): class ModuleHolder(InterpreterObject, ObjectHolder):
def __init__(self, modname, module, interpreter): def __init__(self, modname, module, interpreter):
InterpreterObject.__init__(self) InterpreterObject.__init__(self)
ObjectHolder.__init__(self, module)
self.modname = modname self.modname = modname
self.held_object = module
self.interpreter = interpreter self.interpreter = interpreter
def method_call(self, method_name, args, kwargs): def method_call(self, method_name, args, kwargs):
@ -1551,12 +1560,11 @@ class Interpreter(InterpreterBase):
version = kwargs.get('version', self.project_version) version = kwargs.get('version', self.project_version)
if not isinstance(version, str): if not isinstance(version, str):
raise InterpreterException('Version must be a string.') raise InterpreterException('Version must be a string.')
incs = extract_as_list(kwargs, 'include_directories') incs = extract_as_list(kwargs, 'include_directories', unholder=True)
libs = extract_as_list(kwargs, 'link_with') libs = extract_as_list(kwargs, 'link_with', unholder=True)
sources = extract_as_list(kwargs, 'sources') sources = extract_as_list(kwargs, 'sources')
sources = self.source_strings_to_files(self.flatten(sources)) sources = listify(self.source_strings_to_files(sources), unholder=True)
deps = self.flatten(kwargs.get('dependencies', [])) deps = extract_as_list(kwargs, 'dependencies', unholder=True)
deps = listify(deps)
compile_args = mesonlib.stringlistify(kwargs.get('compile_args', [])) compile_args = mesonlib.stringlistify(kwargs.get('compile_args', []))
link_args = mesonlib.stringlistify(kwargs.get('link_args', [])) link_args = mesonlib.stringlistify(kwargs.get('link_args', []))
final_deps = [] final_deps = []
@ -1568,13 +1576,8 @@ class Interpreter(InterpreterBase):
if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)): if not isinstance(d, (dependencies.Dependency, dependencies.ExternalLibrary, dependencies.InternalDependency)):
raise InterpreterException('Dependencies must be external deps') raise InterpreterException('Dependencies must be external deps')
final_deps.append(d) final_deps.append(d)
dep = dependencies.InternalDependency(version, dep = dependencies.InternalDependency(version, incs, compile_args,
mesonlib.unholder_array(incs), link_args, libs, sources, final_deps)
compile_args,
link_args,
mesonlib.unholder_array(libs),
mesonlib.unholder_array(sources),
final_deps)
return DependencyHolder(dep) return DependencyHolder(dep)
@noKwargs @noKwargs
@ -1629,7 +1632,7 @@ class Interpreter(InterpreterBase):
'or not executable'.format(cmd)) 'or not executable'.format(cmd))
cmd = prog cmd = prog
expanded_args = [] expanded_args = []
for a in mesonlib.flatten(cargs): for a in listify(cargs):
if isinstance(a, str): if isinstance(a, str):
expanded_args.append(a) expanded_args.append(a)
elif isinstance(a, mesonlib.File): elif isinstance(a, mesonlib.File):
@ -2299,11 +2302,7 @@ to directly access options of other subprojects.''')
raise InterpreterException('Run_target needs at least one positional argument.') raise InterpreterException('Run_target needs at least one positional argument.')
cleaned_args = [] cleaned_args = []
for i in mesonlib.flatten(all_args): for i in listify(all_args, unholder=True):
try:
i = i.held_object
except AttributeError:
pass
if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)): if not isinstance(i, (str, build.BuildTarget, build.CustomTarget, dependencies.ExternalProgram, mesonlib.File)):
mlog.debug('Wrong type:', str(i)) mlog.debug('Wrong type:', str(i))
raise InterpreterException('Invalid argument to run_target.') raise InterpreterException('Invalid argument to run_target.')
@ -2374,11 +2373,10 @@ to directly access options of other subprojects.''')
par = kwargs.get('is_parallel', True) par = kwargs.get('is_parallel', True)
if not isinstance(par, bool): if not isinstance(par, bool):
raise InterpreterException('Keyword argument is_parallel must be a boolean.') raise InterpreterException('Keyword argument is_parallel must be a boolean.')
cmd_args = extract_as_list(kwargs, 'args') cmd_args = extract_as_list(kwargs, 'args', unholder=True)
for i in cmd_args: for i in cmd_args:
if not isinstance(i, (str, mesonlib.File, TargetHolder)): if not isinstance(i, (str, mesonlib.File, build.Target)):
raise InterpreterException('Command line arguments must be strings, files or targets.') raise InterpreterException('Command line arguments must be strings, files or targets.')
cmd_args = mesonlib.unholder_array(cmd_args)
env = self.unpack_env_kwarg(kwargs) env = self.unpack_env_kwarg(kwargs)
should_fail = kwargs.get('should_fail', False) should_fail = kwargs.get('should_fail', False)
if not isinstance(should_fail, bool): if not isinstance(should_fail, bool):
@ -2796,7 +2794,8 @@ different subdirectory.
elif isinstance(s, str): elif isinstance(s, str):
s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s) s = mesonlib.File.from_source_file(self.environment.source_dir, self.subdir, s)
else: else:
raise InterpreterException("Source item is not string or File-type object.") raise InterpreterException('Source item is {!r} instead of '
'string or File-type object'.format(s))
results.append(s) results.append(s)
return results return results
@ -2822,7 +2821,7 @@ different subdirectory.
if not args: if not args:
raise InterpreterException('Target does not have a name.') raise InterpreterException('Target does not have a name.')
name = args[0] name = args[0]
sources = args[1:] sources = listify(args[1:])
if self.environment.is_cross_build(): if self.environment.is_cross_build():
if kwargs.get('native', False): if kwargs.get('native', False):
is_cross = False is_cross = False
@ -2830,19 +2829,14 @@ different subdirectory.
is_cross = True is_cross = True
else: else:
is_cross = False is_cross = False
try: if 'sources' in kwargs:
kw_src = self.flatten(kwargs['sources']) sources += listify(kwargs['sources'])
kw_src = listify(kw_src)
except KeyError:
kw_src = []
sources += kw_src
sources = self.source_strings_to_files(sources) sources = self.source_strings_to_files(sources)
objs = self.flatten(kwargs.get('objects', [])) objs = extract_as_list(kwargs, 'objects')
kwargs['dependencies'] = self.flatten(kwargs.get('dependencies', [])) kwargs['dependencies'] = extract_as_list(kwargs, 'dependencies')
if 'extra_files' in kwargs: if 'extra_files' in kwargs:
ef = extract_as_list(kwargs, 'extra_files') ef = extract_as_list(kwargs, 'extra_files')
kwargs['extra_files'] = self.source_strings_to_files(ef) kwargs['extra_files'] = self.source_strings_to_files(ef)
objs = listify(objs)
self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources) self.check_sources_exist(os.path.join(self.source_root, self.subdir), sources)
if targetholder is ExecutableHolder: if targetholder is ExecutableHolder:
targetclass = build.Executable targetclass = build.Executable

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

@ -20,7 +20,7 @@ import os
import copy import copy
import subprocess import subprocess
from . import ModuleReturnValue from . import ModuleReturnValue
from ..mesonlib import MesonException, OrderedSet, Popen_safe from ..mesonlib import MesonException, OrderedSet, Popen_safe, extract_as_list
from ..dependencies import Dependency, PkgConfigDependency, InternalDependency from ..dependencies import Dependency, PkgConfigDependency, InternalDependency
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
@ -323,11 +323,9 @@ class GnomeModule(ExtensionModule):
cflags = OrderedSet() cflags = OrderedSet()
ldflags = OrderedSet() ldflags = OrderedSet()
gi_includes = OrderedSet() gi_includes = OrderedSet()
deps = mesonlib.listify(deps) deps = mesonlib.listify(deps, unholder=True)
for dep in deps: for dep in deps:
if hasattr(dep, 'held_object'):
dep = dep.held_object
if isinstance(dep, InternalDependency): if isinstance(dep, InternalDependency):
cflags.update(get_include_args(dep.include_directories)) cflags.update(get_include_args(dep.include_directories))
for lib in dep.libraries: for lib in dep.libraries:
@ -378,7 +376,7 @@ class GnomeModule(ExtensionModule):
elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)): elif isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
cflags.update(get_include_args(dep.get_include_dirs())) cflags.update(get_include_args(dep.get_include_dirs()))
else: else:
mlog.log('dependency %s not handled to build gir files' % dep) mlog.log('dependency {!r} not handled to build gir files'.format(dep))
continue continue
if gir_has_extra_lib_arg() and use_gir_args: if gir_has_extra_lib_arg() and use_gir_args:
@ -394,7 +392,7 @@ class GnomeModule(ExtensionModule):
@permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix', @permittedKwargs({'sources', 'nsversion', 'namespace', 'symbol_prefix', 'identifier_prefix',
'export_packages', 'includes', 'dependencies', 'link_with', 'include_directories', 'export_packages', 'includes', 'dependencies', 'link_with', 'include_directories',
'install', 'install_dir_gir', 'install_dir_typelib', 'extra_args', '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): def generate_gir(self, state, args, kwargs):
if len(args) != 1: if len(args) != 1:
raise MesonException('Gir takes one argument') 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.') raise MesonException('gobject-introspection dependency was not found, gir cannot be generated.')
ns = kwargs.pop('namespace') ns = kwargs.pop('namespace')
nsversion = kwargs.pop('nsversion') nsversion = kwargs.pop('nsversion')
libsources = mesonlib.flatten(kwargs.pop('sources')) libsources = mesonlib.extract_as_list(kwargs, 'sources', pop=True)
girfile = '%s-%s.gir' % (ns, nsversion) girfile = '%s-%s.gir' % (ns, nsversion)
srcdir = os.path.join(state.environment.get_source_dir(), state.subdir) srcdir = os.path.join(state.environment.get_source_dir(), state.subdir)
builddir = os.path.join(state.environment.get_build_dir(), state.subdir) builddir = os.path.join(state.environment.get_build_dir(), state.subdir)
@ -429,6 +427,12 @@ class GnomeModule(ExtensionModule):
scan_command += ['--no-libtool', '--namespace=' + ns, '--nsversion=' + nsversion, '--warn-all', scan_command += ['--no-libtool', '--namespace=' + ns, '--nsversion=' + nsversion, '--warn-all',
'--output', '@OUTPUT@'] '--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', [])) extra_args = mesonlib.stringlistify(kwargs.pop('extra_args', []))
scan_command += extra_args scan_command += extra_args
scan_command += ['-I' + srcdir, scan_command += ['-I' + srcdir,
@ -525,9 +529,8 @@ class GnomeModule(ExtensionModule):
else: else:
raise MesonException('Gir export packages must be str or list') raise MesonException('Gir export packages must be str or list')
deps = mesonlib.extract_as_list(kwargs, 'dependencies', pop = True)
deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() + deps = (girtarget.get_all_link_deps() + girtarget.get_external_deps() +
deps) extract_as_list(kwargs, 'dependencies', pop=True, unholder=True))
# Need to recursively add deps on GirTarget sources from our # Need to recursively add deps on GirTarget sources from our
# dependencies and also find the include directories needed for the # dependencies and also find the include directories needed for the
# typelib generation custom target below. # typelib generation custom target below.
@ -794,7 +797,8 @@ This will become a hard error in the future.''')
def _get_build_args(self, kwargs, state): def _get_build_args(self, kwargs, state):
args = [] args = []
cflags, ldflags, gi_includes = self._get_dependencies_flags(kwargs.get('dependencies', []), state, include_rpath=True) deps = extract_as_list(kwargs, 'dependencies', unholder=True)
cflags, ldflags, gi_includes = self._get_dependencies_flags(deps, state, include_rpath=True)
inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories') inc_dirs = mesonlib.extract_as_list(kwargs, 'include_directories')
for incd in inc_dirs: for incd in inc_dirs:
if not isinstance(incd.held_object, (str, build.IncludeDirs)): if not isinstance(incd.held_object, (str, build.IncludeDirs)):

@ -21,6 +21,7 @@ from . import ExtensionModule
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from . import ModuleReturnValue from . import ModuleReturnValue
from ..interpreterbase import permittedKwargs from ..interpreterbase import permittedKwargs
from . import get_include_args
class Qt4Module(ExtensionModule): class Qt4Module(ExtensionModule):
tools_detected = False tools_detected = False
@ -97,10 +98,10 @@ class Qt4Module(ExtensionModule):
except Exception: except Exception:
return [] 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): def preprocess(self, state, args, kwargs):
rcc_files, ui_files, moc_headers, moc_sources, sources \ rcc_files, ui_files, moc_headers, moc_sources, sources, include_directories \
= extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', pop = True) = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', 'include_directories', pop = True)
sources += args[1:] sources += args[1:]
method = kwargs.get('method', 'auto') method = kwargs.get('method', 'auto')
self._detect_tools(state.environment, method) self._detect_tools(state.environment, method)
@ -133,9 +134,10 @@ class Qt4Module(ExtensionModule):
ui_gen = build.Generator([self.uic], ui_kwargs) ui_gen = build.Generator([self.uic], ui_kwargs)
ui_output = ui_gen.process_files('Qt4 ui', ui_files, state) ui_output = ui_gen.process_files('Qt4 ui', ui_files, state)
sources.append(ui_output) sources.append(ui_output)
inc = get_include_args(include_dirs=include_directories)
if len(moc_headers) > 0: if len(moc_headers) > 0:
moc_kwargs = {'output': 'moc_@BASENAME@.cpp', moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
'arguments': ['@INPUT@', '-o', '@OUTPUT@']} 'arguments': inc + ['@INPUT@', '-o', '@OUTPUT@']}
moc_gen = build.Generator([self.moc], moc_kwargs) moc_gen = build.Generator([self.moc], moc_kwargs)
moc_output = moc_gen.process_files('Qt4 moc header', moc_headers, state) moc_output = moc_gen.process_files('Qt4 moc header', moc_headers, state)
sources.append(moc_output) sources.append(moc_output)

@ -21,6 +21,7 @@ from . import ExtensionModule
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from . import ModuleReturnValue from . import ModuleReturnValue
from ..interpreterbase import permittedKwargs from ..interpreterbase import permittedKwargs
from . import get_include_args
class Qt5Module(ExtensionModule): class Qt5Module(ExtensionModule):
tools_detected = False tools_detected = False
@ -103,10 +104,10 @@ class Qt5Module(ExtensionModule):
except Exception: except Exception:
return [] 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): def preprocess(self, state, args, kwargs):
rcc_files, ui_files, moc_headers, moc_sources, sources \ rcc_files, ui_files, moc_headers, moc_sources, sources, include_directories \
= extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', pop = True) = extract_as_list(kwargs, 'qresources', 'ui_files', 'moc_headers', 'moc_sources', 'sources', 'include_directories', pop = True)
sources += args[1:] sources += args[1:]
method = kwargs.get('method', 'auto') method = kwargs.get('method', 'auto')
self._detect_tools(state.environment, method) self._detect_tools(state.environment, method)
@ -139,9 +140,10 @@ class Qt5Module(ExtensionModule):
ui_gen = build.Generator([self.uic], ui_kwargs) ui_gen = build.Generator([self.uic], ui_kwargs)
ui_output = ui_gen.process_files('Qt5 ui', ui_files, state) ui_output = ui_gen.process_files('Qt5 ui', ui_files, state)
sources.append(ui_output) sources.append(ui_output)
inc = get_include_args(include_dirs=include_directories)
if len(moc_headers) > 0: if len(moc_headers) > 0:
moc_kwargs = {'output': 'moc_@BASENAME@.cpp', moc_kwargs = {'output': 'moc_@BASENAME@.cpp',
'arguments': ['@INPUT@', '-o', '@OUTPUT@']} 'arguments': inc + ['@INPUT@', '-o', '@OUTPUT@']}
moc_gen = build.Generator([self.moc], moc_kwargs) moc_gen = build.Generator([self.moc], moc_kwargs)
moc_output = moc_gen.process_files('Qt5 moc header', moc_headers, state) moc_output = moc_gen.process_files('Qt5 moc header', moc_headers, state)
sources.append(moc_output) 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) do_debug = not {'MESON_PRINT_TEST_OUTPUT', 'TRAVIS', 'APPVEYOR'}.isdisjoint(os.environ)
no_meson_log_msg = 'No meson-log.txt found.' no_meson_log_msg = 'No meson-log.txt found.'
system_compiler = None
meson_command = os.path.join(os.getcwd(), 'meson') meson_command = os.path.join(os.getcwd(), 'meson')
if not os.path.exists(meson_command): if not os.path.exists(meson_command):
meson_command += '.py' meson_command += '.py'
@ -141,9 +143,6 @@ def stop_handler(signal, frame):
signal.signal(signal.SIGINT, stop_handler) signal.signal(signal.SIGINT, stop_handler)
signal.signal(signal.SIGTERM, 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): def setup_commands(optbackend):
global do_debug, backend, backend_flags global do_debug, backend, backend_flags
global compile_commands, clean_commands, test_commands, install_commands, uninstall_commands 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-meson', 'failing', False),
('failing-build', 'failing build', False), ('failing-build', 'failing build', False),
('failing-tests', 'failing tests', False), ('failing-tests', 'failing tests', False),
('prebuilt', 'prebuilt', False),
('platform-osx', 'osx', not mesonlib.is_osx()), ('platform-osx', 'osx', not mesonlib.is_osx()),
('platform-windows', 'windows', not mesonlib.is_windows() and not mesonlib.is_cygwin()), ('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) return _run_tests(all_tests, log_name_base, extra_args)
def _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' xmlname = log_name_base + '.xml'
junit_root = ET.Element('testsuites') junit_root = ET.Element('testsuites')
conf_time = 0 conf_time = 0
@ -532,7 +530,7 @@ def _run_tests(all_tests, log_name_base, extra_args):
should_fail = False should_fail = False
if name.startswith('failing'): if name.startswith('failing'):
should_fail = name.split('failing-')[1] 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)) futures.append((testname, t, result))
for (testname, t, result) in futures: for (testname, t, result) in futures:
sys.stdout.flush() sys.stdout.flush()
@ -600,52 +598,6 @@ def check_format():
fullname = os.path.join(root, file) fullname = os.path.join(root, file)
check_file(fullname) 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(): def check_meson_commands_work():
global backend, meson_command, compile_commands, test_commands, install_commands global backend, meson_command, compile_commands, test_commands, install_commands
testdir = 'test cases/common/1 trivial' testdir = 'test cases/common/1 trivial'
@ -670,6 +622,18 @@ def check_meson_commands_work():
if pc.returncode != 0: if pc.returncode != 0:
raise RuntimeError('Failed to install {!r}:\n{}\n{}'.format(testdir, e, o)) 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__': if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Run the test suite of Meson.") parser = argparse.ArgumentParser(description="Run the test suite of Meson.")
parser.add_argument('extra_args', nargs='*', parser.add_argument('extra_args', nargs='*',
@ -679,19 +643,17 @@ if __name__ == '__main__':
options = parser.parse_args() options = parser.parse_args()
setup_commands(options.backend) setup_commands(options.backend)
detect_system_compiler()
script_dir = os.path.split(__file__)[0] script_dir = os.path.split(__file__)[0]
if script_dir != '': if script_dir != '':
os.chdir(script_dir) os.chdir(script_dir)
check_format() check_format()
check_meson_commands_work() check_meson_commands_work()
pbfiles = generate_prebuilt()
try: try:
all_tests = detect_tests_to_run() all_tests = detect_tests_to_run()
(passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.extra_args) (passing_tests, failing_tests, skipped_tests) = run_tests(all_tests, 'meson-test-run', options.extra_args)
except StopException: except StopException:
pass pass
for f in pbfiles:
os.unlink(f)
print('\nTotal passed tests:', green(str(passing_tests))) print('\nTotal passed tests:', green(str(passing_tests)))
print('Total failed tests:', red(str(failing_tests))) print('Total failed tests:', red(str(failing_tests)))
print('Total skipped tests:', yellow(str(skipped_tests))) print('Total skipped tests:', yellow(str(skipped_tests)))

@ -31,6 +31,7 @@ import mesonbuild.compilers
import mesonbuild.environment import mesonbuild.environment
import mesonbuild.mesonlib import mesonbuild.mesonlib
import mesonbuild.coredata import mesonbuild.coredata
from mesonbuild.interpreter import ObjectHolder
from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree from mesonbuild.mesonlib import is_linux, is_windows, is_osx, is_cygwin, windows_proof_rmtree
from mesonbuild.environment import Environment from mesonbuild.environment import Environment
from mesonbuild.dependencies import DependencyException from mesonbuild.dependencies import DependencyException
@ -62,7 +63,6 @@ def get_soname(fname):
def get_rpath(fname): def get_rpath(fname):
return get_dynamic_section_entry(fname, r'(?:rpath|runpath)') return get_dynamic_section_entry(fname, r'(?:rpath|runpath)')
class InternalTests(unittest.TestCase): class InternalTests(unittest.TestCase):
def test_version_number(self): def test_version_number(self):
@ -398,6 +398,49 @@ class InternalTests(unittest.TestCase):
self.assertEqual(forced_value, desired_value) self.assertEqual(forced_value, desired_value)
def test_listify(self):
listify = mesonbuild.mesonlib.listify
# Test sanity
self.assertEqual([1], listify(1))
self.assertEqual([], listify([]))
self.assertEqual([1], listify([1]))
# Test flattening
self.assertEqual([1, 2, 3], listify([1, [2, 3]]))
self.assertEqual([1, 2, 3], listify([1, [2, [3]]]))
self.assertEqual([1, [2, [3]]], listify([1, [2, [3]]], flatten=False))
# Test flattening and unholdering
holder1 = ObjectHolder(1)
holder3 = ObjectHolder(3)
self.assertEqual([holder1], listify(holder1))
self.assertEqual([holder1], listify([holder1]))
self.assertEqual([holder1, 2], listify([holder1, 2]))
self.assertEqual([holder1, 2, 3], listify([holder1, 2, [3]]))
self.assertEqual([1], listify(holder1, unholder=True))
self.assertEqual([1], listify([holder1], unholder=True))
self.assertEqual([1, 2], listify([holder1, 2], unholder=True))
self.assertEqual([1, 2, 3], listify([holder1, 2, [holder3]], unholder=True))
# Unholding doesn't work recursively when not flattening
self.assertEqual([1, [2], [holder3]], listify([holder1, [2], [holder3]], unholder=True, flatten=False))
def test_extract_as_list(self):
extract = mesonbuild.mesonlib.extract_as_list
# Test sanity
kwargs = {'sources': [1, 2, 3]}
self.assertEqual([1, 2, 3], extract(kwargs, 'sources'))
self.assertEqual(kwargs, {'sources': [1, 2, 3]})
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', pop=True))
self.assertEqual(kwargs, {})
# Test unholding
holder3 = ObjectHolder(3)
kwargs = {'sources': [1, 2, holder3]}
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True))
self.assertEqual(kwargs, {'sources': [1, 2, holder3]})
self.assertEqual([1, 2, 3], extract(kwargs, 'sources', unholder=True, pop=True))
self.assertEqual(kwargs, {})
# Test listification
kwargs = {'sources': [1, 2, 3], 'pch_sources': [4, 5, 6]}
self.assertEqual([[1, 2, 3], [4, 5, 6]], extract(kwargs, 'sources', 'pch_sources'))
class BasePlatformTests(unittest.TestCase): class BasePlatformTests(unittest.TestCase):
def setUp(self): def setUp(self):
@ -1298,6 +1341,100 @@ int main(int argc, char **argv) {
for i in targets: for i in targets:
self.assertPathExists(os.path.join(testdir, i)) 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): 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. # within one project. The need to be independent of each other.
# Use one without a library dependency and one with it. # Use one without a library dependency and one with it.
nolinkdep = dependency('boost', modules: 'utility')
linkdep = dependency('boost', modules : ['thread', 'system']) linkdep = dependency('boost', modules : ['thread', 'system'])
staticdep = dependency('boost', modules : ['thread', 'system'], static : true) staticdep = dependency('boost', modules : ['thread', 'system'], static : true)
testdep = dependency('boost', modules : 'test') testdep = dependency('boost', modules : ['unit_test_framework'])
nomoddep = dependency('boost') nomoddep = dependency('boost')
extralibdep = dependency('boost', modules : ['thread', 'system', 'log_setup', 'log']) extralibdep = dependency('boost', modules : ['thread', 'system', 'log_setup', 'log'])
nolinkexe = executable('nolinkedexe', 'nolinkexe.cc', dependencies : nolinkdep)
linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep) linkexe = executable('linkedexe', 'linkexe.cc', dependencies : linkdep)
staticexe = executable('staticlinkedexe', 'linkexe.cc', dependencies : staticdep) staticexe = executable('staticlinkedexe', 'linkexe.cc', dependencies : staticdep)
unitexe = executable('utf', 'unit_test.cpp', dependencies: testdep) unitexe = executable('utf', 'unit_test.cpp', dependencies: testdep)
nomodexe = executable('nomod', 'nomod.cpp', dependencies : nomoddep) nomodexe = executable('nomod', 'nomod.cpp', dependencies : nomoddep)
extralibexe = executable('extralibexe', 'extralib.cpp', dependencies : extralibdep) extralibexe = executable('extralibexe', 'extralib.cpp', dependencies : extralibdep)
test('Boost nolinktest', nolinkexe)
test('Boost linktest', linkexe) test('Boost linktest', linkexe)
test('Boost statictest', staticexe) test('Boost statictest', staticexe)
test('Boost UTF test', unitexe) 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) dependencies : qtcore)
test(qt + 'maninclude', qtmaninclude) 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 endif
endforeach 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', namespace : 'MesonDep1',
symbol_prefix : 'meson', symbol_prefix : 'meson',
identifier_prefix : 'Meson', identifier_prefix : 'Meson',
header: 'dep1.h',
includes : ['GObject-2.0', 'MesonDep2-1.0'], includes : ['GObject-2.0', 'MesonDep2-1.0'],
dependencies : [dep2_dep], dependencies : [dep2_dep],
install : true install : true

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

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