Merge pull request #2282 from NickeZ/improve-boost

Improve boost
pull/2414/head
Jussi Pakkanen 7 years ago committed by GitHub
commit cb3d980a1f
  1. 10
      .appveyor.yml
  2. 15
      docs/markdown/Dependencies.md
  3. 10
      docs/markdown/Release-notes-for-0.43.0/001-boost-platform-improvement.md
  4. 34
      mesonbuild/compilers/c.py
  5. 39
      mesonbuild/compilers/compilers.py
  6. 426
      mesonbuild/dependencies/misc.py
  7. 5
      test cases/frameworks/1 boost/meson.build
  8. 12
      test cases/frameworks/1 boost/nolinkexe.cc
  9. 180
      tools/boost_names.py

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

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

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

@ -172,6 +172,9 @@ class CCompiler(Compiler):
def get_linker_search_args(self, dirname):
return ['-L' + dirname]
def get_default_include_dirs(self):
return []
def gen_import_library_args(self, implibname):
"""
The name of the outputted import library
@ -1056,3 +1059,34 @@ class VisualStudioCCompiler(CCompiler):
# and the can not be called.
return None
return vs32_instruction_set_args.get(instruction_set, None)
def get_toolset_version(self):
# See boost/config/compiler/visualc.cpp for up to date mapping
try:
version = int(''.join(self.version.split('.')[0:2]))
except:
return None
if version < 1310:
return '7.0'
elif version < 1400:
return '7.1' # (Visual Studio 2003)
elif version < 1500:
return '8.0' # (Visual Studio 2005)
elif version < 1600:
return '9.0' # (Visual Studio 2008)
elif version < 1700:
return '10.0' # (Visual Studio 2010)
elif version < 1800:
return '11.0' # (Visual Studio 2012)
elif version < 1900:
return '12.0' # (Visual Studio 2013)
elif version < 1910:
return '14.0' # (Visual Studio 2015)
elif version < 1920:
return '14.1' # (Visual Studio 2017)
return None
def get_default_include_dirs(self):
if 'INCLUDE' not in os.environ:
return []
return os.environ['INCLUDE'].split(os.pathsep)

@ -13,6 +13,7 @@
# limitations under the License.
import contextlib, os.path, re, tempfile
import subprocess
from ..linkers import StaticLinker
from .. import coredata
@ -917,6 +918,35 @@ def get_largefile_args(compiler):
# those features explicitly.
return []
# TODO: The result from calling compiler should be cached. So that calling this
# function multiple times don't add latency.
def gnulike_default_include_dirs(compiler, lang):
if lang == 'cpp':
lang = 'c++'
p = subprocess.Popen(
compiler + ['-x{}'.format(lang), '-E', '-v', '-'],
stdin=subprocess.DEVNULL,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE
)
stderr = p.stderr.read().decode('utf-8')
parse_state = 0
paths = []
for line in stderr.split('\n'):
if parse_state == 0:
if line == '#include "..." search starts here:':
parse_state = 1
elif parse_state == 1:
if line == '#include <...> search starts here:':
parse_state = 2
else:
paths.append(line[1:])
elif parse_state == 2:
if line == 'End of search list.':
break
else:
paths.append(line[1:])
return paths
class GnuCompiler:
# Functionality that is common to all GNU family compilers.
@ -998,6 +1028,9 @@ class GnuCompiler:
def get_instruction_set_args(self, instruction_set):
return gnulike_instruction_set_args.get(instruction_set, None)
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
class ClangCompiler:
def __init__(self, clang_type):
@ -1082,6 +1115,9 @@ class ClangCompiler:
def get_instruction_set_args(self, instruction_set):
return gnulike_instruction_set_args.get(instruction_set, None)
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)
# Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1
class IntelCompiler:
@ -1132,3 +1168,6 @@ class IntelCompiler:
# if self.icc_type == ICC_OSX:
# return ['-bundle']
return ['-shared']
def get_default_include_dirs(self):
return gnulike_default_include_dirs(self.exelist, self.language)

@ -18,7 +18,6 @@ import glob
import os
import re
import shlex
import stat
import shutil
import sysconfig
@ -30,77 +29,153 @@ from ..environment import detect_cpu_family
from .base import DependencyException, DependencyMethods
from .base import ExternalDependency, ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency
# On windows 3 directory layouts are supported:
# * The default layout (versioned) installed:
# - $BOOST_ROOT/include/boost-x_x/boost/*.hpp
# - $BOOST_ROOT/lib/*.lib
# * The non-default layout (system) installed:
# - $BOOST_ROOT/include/boost/*.hpp
# - $BOOST_ROOT/lib/*.lib
# * The pre-built binaries from sf.net:
# - $BOOST_ROOT/boost/*.hpp
# - $BOOST_ROOT/lib<arch>-<compiler>/*.lib where arch=32/64 and compiler=msvc-14.1
#
# Library names supported:
# - libboost_<module>-<compiler>-mt-gd-x_x.lib (static)
# - boost_<module>-<compiler>-mt-gd-x_x.lib|.dll (shared)
# - libboost_<module>.lib (static)
# - boost_<module>.lib|.dll (shared)
# where compiler is vc141 for example.
#
# NOTE: -gb means runtime and build time debugging is on
# -mt means threading=multi
#
# The `modules` argument accept library names. This is because every module that
# has libraries to link against also has multiple options regarding how to
# link. See for example:
# * http://www.boost.org/doc/libs/1_65_1/libs/test/doc/html/boost_test/usage_variants.html
# * http://www.boost.org/doc/libs/1_65_1/doc/html/stacktrace/configuration_and_build.html
# * http://www.boost.org/doc/libs/1_65_1/libs/math/doc/html/math_toolkit/main_tr1.html
class BoostDependency(ExternalDependency):
# Some boost libraries have different names for
# their sources and libraries. This dict maps
# between the two.
name2lib = {'test': 'unit_test_framework'}
def __init__(self, environment, kwargs):
super().__init__('boost', environment, 'cpp', kwargs)
self.need_static_link = ['boost_exception', 'boost_test_exec_monitor']
self.is_debug = environment.cmd_line_options.buildtype.startswith('debug')
threading = kwargs.get("threading", "multi")
self.is_multithreading = threading == "multi"
self.requested_modules = self.get_requested(kwargs)
self.boost_root = None
self.boost_roots = []
self.incdir = None
self.libdir = None
try:
if 'BOOST_ROOT' in os.environ:
self.boost_root = os.environ['BOOST_ROOT']
self.boost_roots = [self.boost_root]
if not os.path.isabs(self.boost_root):
raise DependencyException('BOOST_ROOT must be an absolute path.')
except KeyError:
self.boost_root = None
if 'BOOST_INCLUDEDIR' in os.environ:
self.incdir = os.environ['BOOST_INCLUDEDIR']
if 'BOOST_LIBRARYDIR' in os.environ:
self.libdir = os.environ['BOOST_LIBRARYDIR']
if self.want_cross and self.boost_root is None and self.incdir is None:
raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling')
if self.boost_root is None:
if self.want_cross:
if 'BOOST_INCLUDEDIR' in os.environ:
self.incdir = os.environ['BOOST_INCLUDEDIR']
else:
raise DependencyException('BOOST_ROOT or BOOST_INCLUDEDIR is needed while cross-compiling')
if mesonlib.is_windows():
self.boost_root = self.detect_win_root()
self.incdir = self.boost_root
self.boost_roots = self.detect_win_roots()
else:
if 'BOOST_INCLUDEDIR' in os.environ:
self.incdir = os.environ['BOOST_INCLUDEDIR']
else:
self.incdir = '/usr/include'
self.boost_roots = self.detect_nix_roots()
if self.boost_root is None and not self.boost_roots:
self.log_fail()
return
if self.incdir is None:
if mesonlib.is_windows():
self.incdir = self.detect_win_incdir()
else:
self.incdir = self.detect_nix_incdir()
if self.incdir is None:
self.log_fail()
return
mlog.debug('Boost library root dir is', mlog.bold(self.boost_root))
mlog.debug('Boost include directory is', mlog.bold(self.incdir))
if 'BOOST_LIBRARYDIR' in os.environ:
self.libdir = os.environ['BOOST_LIBRARYDIR']
else:
self.incdir = os.path.join(self.boost_root, 'include')
self.boost_inc_subdir = os.path.join(self.incdir, 'boost')
mlog.debug('Boost library root dir is', self.boost_root)
self.src_modules = {}
self.lib_modules = {}
self.lib_modules_mt = {}
self.detect_version()
self.requested_modules = self.get_requested(kwargs)
module_str = ', '.join(self.requested_modules)
if self.is_found:
self.detect_src_modules()
self.detect_lib_modules()
mlog.debug('Boost library directory is', mlog.bold(self.libdir))
self.validate_requested()
if self.boost_root is not None:
info = self.version + ', ' + self.boost_root
else:
info = self.version
mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info)
self.log_success()
else:
self.log_fail()
def log_fail(self):
module_str = ', '.join(self.requested_modules)
mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO'))
def log_success(self):
module_str = ', '.join(self.requested_modules)
if self.boost_root:
info = self.version + ', ' + self.boost_root
else:
mlog.log("Dependency Boost (%s) found:" % module_str, mlog.red('NO'))
info = self.version
mlog.log('Dependency Boost (%s) found:' % module_str, mlog.green('YES'), info)
def detect_nix_roots(self):
return ['/usr/local', '/usr']
def detect_win_root(self):
globtext = 'c:\\local\\boost_*'
def detect_win_roots(self):
res = []
# Where boost documentation says it should be
globtext = 'C:\\Program Files\\boost\\boost_*'
files = glob.glob(globtext)
if len(files) > 0:
return files[0]
return 'C:\\'
res.extend(files)
# Where boost built from source actually installs it
if os.path.isdir('C:\\Boost'):
res.append('C:\\Boost')
# Where boost prebuilt binaries are
globtext = 'C:\\local\\boost_*'
files = glob.glob(globtext)
res.extend(files)
return res
def detect_nix_incdir(self):
for root in self.boost_roots:
incdir = os.path.join(root, 'include', 'boost')
if os.path.isdir(incdir):
return os.path.join(root, 'include')
return None
# FIXME: Should pick a version that matches the requested version
# Returns the folder that contains the boost folder.
def detect_win_incdir(self):
for root in self.boost_roots:
globtext = os.path.join(root, 'include', 'boost-*')
incdirs = glob.glob(globtext)
if len(incdirs) > 0:
return incdirs[0]
incboostdir = os.path.join(root, 'include', 'boost')
if os.path.isdir(incboostdir):
return os.path.join(root, 'include')
incboostdir = os.path.join(root, 'boost')
if os.path.isdir(incboostdir):
return root
return None
def get_compile_args(self):
args = []
if self.boost_root is not None:
if mesonlib.is_windows():
include_dir = self.boost_root
else:
include_dir = os.path.join(self.boost_root, 'include')
else:
include_dir = self.incdir
include_dir = self.incdir
# Use "-isystem" when including boost headers instead of "-I"
# to avoid compiler warnings/failures when "-Werror" is used
@ -116,18 +191,7 @@ class BoostDependency(ExternalDependency):
# and http://stackoverflow.com/questions/37218953/isystem-on-a-system-include-directory-causes-errors
# for more details
# TODO: The correct solution would probably be to ask the
# compiler for it's default include paths (ie: "gcc -xc++ -E
# -v -") and avoid including those with -isystem
# For now, use -isystem for all includes except for some
# typical defaults (which don't need to be included at all
# since they are in the default include paths). These typical
# defaults include the usual directories at the root of the
# filesystem, but also any path that ends with those directory
# names in order to handle cases like cross-compiling where we
# might have a different sysroot.
if not include_dir.endswith(('/usr/include', '/usr/local/include')):
if include_dir and include_dir not in self.compiler.get_default_include_dirs():
args.append("".join(self.compiler.get_include_args(include_dir, True)))
return args
@ -136,19 +200,23 @@ class BoostDependency(ExternalDependency):
for c in candidates:
if not isinstance(c, str):
raise DependencyException('Boost module argument is not a string.')
if 'boost_' + c not in BOOST_LIBS:
raise DependencyException('Dependency {} not found. It is not a valid boost library.'.format(c))
return candidates
def validate_requested(self):
for m in self.requested_modules:
if m not in self.src_modules and m not in self.lib_modules and m + '-mt' not in self.lib_modules_mt:
msg = 'Requested Boost module {!r} not found'
if 'boost_' + m not in self.lib_modules:
msg = 'Requested Boost library {!r} not found'
raise DependencyException(msg.format(m))
def detect_version(self):
try:
ifile = open(os.path.join(self.boost_inc_subdir, 'version.hpp'))
ifile = open(os.path.join(self.incdir, 'boost', 'version.hpp'))
except FileNotFoundError:
return
except TypeError:
return
with ifile:
for line in ifile:
if line.startswith("#define") and 'BOOST_LIB_VERSION' in line:
@ -158,12 +226,6 @@ class BoostDependency(ExternalDependency):
self.is_found = True
return
def detect_src_modules(self):
for entry in os.listdir(self.boost_inc_subdir):
entry = os.path.join(self.boost_inc_subdir, entry)
if stat.S_ISDIR(os.stat(entry).st_mode):
self.src_modules[os.path.split(entry)[-1]] = True
def detect_lib_modules(self):
if mesonlib.is_windows():
return self.detect_lib_modules_win()
@ -171,32 +233,79 @@ class BoostDependency(ExternalDependency):
def detect_lib_modules_win(self):
arch = detect_cpu_family(self.env.coredata.compilers)
# Guess the libdir
if arch == 'x86':
gl = 'lib32*'
elif arch == 'x86_64':
gl = 'lib64*'
else:
# Does anyone do Boost cross-compiling to other archs on Windows?
gl = None
# See if the libdir is valid
if gl:
libdir = glob.glob(os.path.join(self.boost_root, gl))
else:
libdir = []
# Can't find libdir, bail
if not libdir:
compiler_ts = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version().split('.')
compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1])
if not self.libdir:
# The libdirs in the distributed binaries
if arch == 'x86':
gl = 'lib32*'
elif arch == 'x86_64':
gl = 'lib64*'
else:
# Does anyone do Boost cross-compiling to other archs on Windows?
gl = None
if self.boost_root:
roots = [self.boost_root]
else:
roots = self.boost_roots
for root in roots:
# The default libdir when building
libdir = os.path.join(root, 'lib')
if os.path.isdir(libdir):
self.libdir = libdir
break
if gl:
tmp = glob.glob(os.path.join(root, gl))
if len(tmp) > 0:
# FIXME: Should pick the correct version
self.libdir = tmp[0]
break
if not self.libdir:
return
libdir = libdir[0]
# Don't override what was set in the environment
if self.libdir:
self.libdir = libdir
globber = 'libboost_*-gd-*.lib' if self.static else 'boost_*-gd-*.lib' # FIXME
for entry in glob.glob(os.path.join(libdir, globber)):
for name in self.need_static_link:
libname = "lib{}".format(name) + '-' + compiler
if self.is_multithreading:
libname = libname + '-mt'
if self.is_debug:
libname = libname + '-gd'
libname = libname + "-{}.lib".format(self.version.replace('.', '_'))
if os.path.isfile(os.path.join(self.libdir, libname)):
modname = libname.split('-', 1)[0][3:]
self.lib_modules[modname] = libname
else:
libname = "lib{}.lib".format(name)
if os.path.isfile(os.path.join(self.libdir, libname)):
self.lib_modules[name[3:]] = libname
# globber1 applies to a layout=system installation
# globber2 applies to a layout=versioned installation
globber1 = 'libboost_*' if self.static else 'boost_*'
globber2 = globber1 + '-' + compiler
if self.is_multithreading:
globber2 = globber2 + '-mt'
if self.is_debug:
globber2 = globber2 + '-gd'
globber2 = globber2 + '-{}'.format(self.version.replace('.', '_'))
globber2_matches = glob.glob(os.path.join(self.libdir, globber2 + '.lib'))
for entry in globber2_matches:
(_, fname) = os.path.split(entry)
base = fname.split('_', 1)[1]
modname = base.split('-', 1)[0]
self.lib_modules_mt[modname] = fname
modname = fname.split('-', 1)
if len(modname) > 1:
modname = modname[0]
else:
modname = modname.split('.', 1)[0]
if self.static:
modname = modname[3:]
self.lib_modules[modname] = fname
if len(globber2_matches) == 0:
for entry in glob.glob(os.path.join(self.libdir, globber1 + '.lib')):
(_, fname) = os.path.split(entry)
modname = fname.split('.', 1)[0]
if self.static:
modname = modname[3:]
self.lib_modules[modname] = fname
def detect_lib_modules_nix(self):
if self.static:
@ -214,25 +323,32 @@ class BoostDependency(ExternalDependency):
else:
libdirs = [os.path.join(self.boost_root, 'lib')]
for libdir in libdirs:
for name in self.need_static_link:
libname = 'lib{}.a'.format(name)
if os.path.isfile(os.path.join(libdir, libname)):
self.lib_modules[name] = libname
for entry in glob.glob(os.path.join(libdir, globber)):
lib = os.path.basename(entry)
name = lib.split('.')[0].split('_', 1)[-1]
name = lib.split('.')[0][3:]
# I'm not 100% sure what to do here. Some distros
# have modules such as thread only as -mt versions.
if entry.endswith('-mt.{}'.format(libsuffix)):
self.lib_modules_mt[name] = True
else:
self.lib_modules[name] = True
# On debian all packages are built threading=multi
# but not suffixed with -mt.
# FIXME: implement detect_lib_modules_{debian, redhat, ...}
if self.is_multithreading and mesonlib.is_debianlike():
self.lib_modules[name] = lib
elif self.is_multithreading and entry.endswith('-mt.{}'.format(libsuffix)):
self.lib_modules[name] = lib
elif not entry.endswith('-mt.{}'.format(libsuffix)):
self.lib_modules[name] = lib
def get_win_link_args(self):
args = []
# TODO: should this check self.libdir?
if self.boost_root:
if self.libdir:
args.append('-L' + self.libdir)
for module in self.requested_modules:
module = BoostDependency.name2lib.get(module, module)
if module in self.lib_modules_mt:
args.append(self.lib_modules_mt[module])
for lib in self.requested_modules:
args.append(self.lib_modules['boost_' + lib])
return args
def get_link_args(self):
@ -243,33 +359,14 @@ class BoostDependency(ExternalDependency):
args.append('-L' + os.path.join(self.boost_root, 'lib'))
elif self.libdir:
args.append('-L' + self.libdir)
for module in self.requested_modules:
module = BoostDependency.name2lib.get(module, module)
libname = 'boost_' + module
for lib in self.requested_modules:
# The compiler's library detector is the most reliable so use that first.
default_detect = self.compiler.find_library(libname, self.env, [])
default_detect = self.compiler.find_library('boost_' + lib, self.env, [])
if default_detect is not None:
if module == 'unit_testing_framework':
emon_args = self.compiler.find_library('boost_test_exec_monitor')
else:
emon_args = None
args += default_detect
if emon_args is not None:
args += emon_args
elif module in self.lib_modules or module in self.lib_modules_mt:
linkcmd = '-l' + libname
args.append(linkcmd)
# FIXME a hack, but Boost's testing framework has a lot of
# different options and it's hard to determine what to do
# without feedback from actual users. Update this
# as we get more bug reports.
if module == 'unit_testing_framework':
args.append('-lboost_test_exec_monitor')
elif module + '-mt' in self.lib_modules_mt:
linkcmd = '-lboost_' + module + '-mt'
elif lib in self.lib_modules:
linkcmd = '-l' + lib
args.append(linkcmd)
if module == 'unit_testing_framework':
args.append('-lboost_test_exec_monitor-mt')
return args
def get_sources(self):
@ -664,3 +761,78 @@ class CupsDependency(ExternalDependency):
return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG, DependencyMethods.EXTRAFRAMEWORK]
else:
return [DependencyMethods.PKGCONFIG, DependencyMethods.CUPSCONFIG]
# Generated with boost_names.py
BOOST_LIBS = [
'boost_atomic',
'boost_chrono',
'boost_chrono',
'boost_container',
'boost_context',
'boost_coroutine',
'boost_date_time',
'boost_exception',
'boost_fiber',
'boost_filesystem',
'boost_graph',
'boost_iostreams',
'boost_locale',
'boost_log',
'boost_log_setup',
'boost_math_tr1',
'boost_math_tr1f',
'boost_math_tr1l',
'boost_math_c99',
'boost_math_c99f',
'boost_math_c99l',
'boost_math_tr1',
'boost_math_tr1f',
'boost_math_tr1l',
'boost_math_c99',
'boost_math_c99f',
'boost_math_c99l',
'boost_math_tr1',
'boost_math_tr1f',
'boost_math_tr1l',
'boost_math_c99',
'boost_math_c99f',
'boost_math_c99l',
'boost_math_tr1',
'boost_math_tr1f',
'boost_math_tr1l',
'boost_math_c99',
'boost_math_c99f',
'boost_math_c99l',
'boost_math_tr1',
'boost_math_tr1f',
'boost_math_tr1l',
'boost_math_c99',
'boost_math_c99f',
'boost_math_c99l',
'boost_math_tr1',
'boost_math_tr1f',
'boost_math_tr1l',
'boost_math_c99',
'boost_math_c99f',
'boost_math_c99l',
'boost_mpi',
'boost_random',
'boost_regex',
'boost_serialization',
'boost_wserialization',
'boost_signals',
'boost_stacktrace_noop',
'boost_stacktrace_backtrace',
'boost_stacktrace_addr2line',
'boost_stacktrace_basic',
'boost_stacktrace_windbg',
'boost_stacktrace_windbg_cached',
'boost_system',
'boost_prg_exec_monitor',
'boost_test_exec_monitor',
'boost_unit_test_framework',
'boost_thread',
'boost_timer',
'boost_type_erasure',
'boost_wave'
]

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

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

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