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

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

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

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

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