|
|
|
@ -18,7 +18,6 @@ import glob |
|
|
|
|
import os |
|
|
|
|
import re |
|
|
|
|
import shlex |
|
|
|
|
import shutil |
|
|
|
|
import sysconfig |
|
|
|
|
|
|
|
|
|
from pathlib import Path |
|
|
|
@ -44,6 +43,10 @@ from .base import ( |
|
|
|
|
# - $BOOST_ROOT/boost/*.hpp |
|
|
|
|
# - $BOOST_ROOT/lib<arch>-<compiler>/*.lib where arch=32/64 and compiler=msvc-14.1 |
|
|
|
|
# |
|
|
|
|
# Note that we should also try to support: |
|
|
|
|
# mingw-w64 / Windows : libboost_<module>-mt.a (location = <prefix>/mingw64/lib/) |
|
|
|
|
# libboost_<module>-mt.dll.a |
|
|
|
|
# |
|
|
|
|
# Library names supported: |
|
|
|
|
# - libboost_<module>-<compiler>-mt-gd-x_x.lib (static) |
|
|
|
|
# - boost_<module>-<compiler>-mt-gd-x_x.lib|.dll (shared) |
|
|
|
@ -97,18 +100,13 @@ from .base import ( |
|
|
|
|
# 2.2. Find boost libraries with unknown suffixes using file-name globbing. |
|
|
|
|
|
|
|
|
|
# TODO: Unix: Don't assume we know where the boost dir is, rely on -Idir and -Ldir being set. |
|
|
|
|
# TODO: Determine a suffix (e.g. "-mt" or "") and use it. |
|
|
|
|
# TODO: Get_win_link_args( ) and get_link_args( ) |
|
|
|
|
# TODO: Genericize: 'args += ['-L' + dir] => args += self.compiler.get_linker_search_args(dir) |
|
|
|
|
# TODO: Allow user to specify suffix in BOOST_SUFFIX, or add specific options like BOOST_DEBUG for 'd' for debug. |
|
|
|
|
# TODO: fix cross: |
|
|
|
|
# is_windows() -> for_windows(self.want_cross, self.env) |
|
|
|
|
# is_osx() and self.want_cross -> for_darwin(self.want_cross, self.env) |
|
|
|
|
|
|
|
|
|
class BoostDependency(ExternalDependency): |
|
|
|
|
def __init__(self, environment, kwargs): |
|
|
|
|
super().__init__('boost', environment, 'cpp', kwargs) |
|
|
|
|
self.need_static_link = ['boost_exception', 'boost_test_exec_monitor'] |
|
|
|
|
# FIXME: is this the right way to find the build type? |
|
|
|
|
self.is_debug = environment.cmd_line_options.buildtype.startswith('debug') |
|
|
|
|
threading = kwargs.get("threading", "multi") |
|
|
|
|
self.is_multithreading = threading == "multi" |
|
|
|
@ -131,42 +129,34 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
self.libdir = os.environ['BOOST_LIBRARYDIR'] |
|
|
|
|
|
|
|
|
|
if self.boost_root is None: |
|
|
|
|
if mesonlib.is_windows(): |
|
|
|
|
if mesonlib.for_windows(self.want_cross, self.env): |
|
|
|
|
self.boost_roots = self.detect_win_roots() |
|
|
|
|
else: |
|
|
|
|
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(): |
|
|
|
|
if mesonlib.for_windows(self.want_cross, self.env): |
|
|
|
|
self.incdir = self.detect_win_incdir() |
|
|
|
|
else: |
|
|
|
|
self.incdir = self.detect_nix_incdir() |
|
|
|
|
|
|
|
|
|
if self.incdir is None and mesonlib.is_windows(): |
|
|
|
|
self.log_fail() |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
if self.check_invalid_modules(): |
|
|
|
|
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)) |
|
|
|
|
|
|
|
|
|
self.lib_modules = {} |
|
|
|
|
self.detect_version() |
|
|
|
|
# 1. check if we can find BOOST headers. |
|
|
|
|
self.detect_headers_and_version() |
|
|
|
|
|
|
|
|
|
# 2. check if we can find BOOST libraries. |
|
|
|
|
if self.is_found: |
|
|
|
|
self.detect_lib_modules() |
|
|
|
|
mlog.debug('Boost library directory is', mlog.bold(self.libdir)) |
|
|
|
|
for m in self.requested_modules: |
|
|
|
|
if 'boost_' + m not in self.lib_modules: |
|
|
|
|
mlog.debug('Requested Boost library {!r} not found'.format(m)) |
|
|
|
|
self.log_fail() |
|
|
|
|
self.is_found = False |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
# 3. Report success or failure |
|
|
|
|
if self.is_found: |
|
|
|
|
self.log_success() |
|
|
|
|
else: |
|
|
|
|
self.log_fail() |
|
|
|
@ -187,7 +177,6 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
|
|
|
|
|
if invalid_modules: |
|
|
|
|
mlog.log(mlog.red('ERROR:'), 'Invalid Boost modules: ' + ', '.join(invalid_modules)) |
|
|
|
|
self.log_fail() |
|
|
|
|
return True |
|
|
|
|
else: |
|
|
|
|
return False |
|
|
|
@ -275,7 +264,7 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
raise DependencyException('Boost module argument is not a string.') |
|
|
|
|
return candidates |
|
|
|
|
|
|
|
|
|
def detect_version(self): |
|
|
|
|
def detect_headers_and_version(self): |
|
|
|
|
try: |
|
|
|
|
version = self.compiler.get_define('BOOST_LIB_VERSION', '#include <boost/version.hpp>', self.env, self.get_compile_args(), []) |
|
|
|
|
except mesonlib.EnvironmentException: |
|
|
|
@ -289,9 +278,23 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
self.is_found = True |
|
|
|
|
|
|
|
|
|
def detect_lib_modules(self): |
|
|
|
|
if mesonlib.is_windows(): |
|
|
|
|
return self.detect_lib_modules_win() |
|
|
|
|
return self.detect_lib_modules_nix() |
|
|
|
|
self.lib_modules = {} |
|
|
|
|
|
|
|
|
|
# 1. Try to find modules using compiler.find_library( ) |
|
|
|
|
if self.find_libraries_with_abi_tags(self.abi_tags()): |
|
|
|
|
pass |
|
|
|
|
# 2. Fall back to the old method |
|
|
|
|
else: |
|
|
|
|
if mesonlib.for_windows(self.want_cross, self.env): |
|
|
|
|
self.detect_lib_modules_win() |
|
|
|
|
else: |
|
|
|
|
self.detect_lib_modules_nix() |
|
|
|
|
|
|
|
|
|
# 3. Check if we can find the modules |
|
|
|
|
for m in self.requested_modules: |
|
|
|
|
if 'boost_' + m not in self.lib_modules: |
|
|
|
|
mlog.debug('Requested Boost library {!r} not found'.format(m)) |
|
|
|
|
self.is_found = False |
|
|
|
|
|
|
|
|
|
def modname_from_filename(self, filename): |
|
|
|
|
modname = os.path.basename(filename) |
|
|
|
@ -301,20 +304,94 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
modname = modname[3:] |
|
|
|
|
return modname |
|
|
|
|
|
|
|
|
|
def detect_lib_modules_win(self): |
|
|
|
|
arch = detect_cpu_family(self.env.coredata.compilers) |
|
|
|
|
def compiler_tag(self): |
|
|
|
|
tag = None |
|
|
|
|
compiler = self.env.detect_cpp_compiler(self.want_cross) |
|
|
|
|
if mesonlib.for_windows(self.want_cross, self.env): |
|
|
|
|
if compiler.get_id() == 'msvc': |
|
|
|
|
comp_ts_version = compiler.get_toolset_version() |
|
|
|
|
compiler_ts = comp_ts_version.split('.') |
|
|
|
|
# FIXME - what about other compilers? |
|
|
|
|
tag = '-vc{}{}'.format(compiler_ts[0], compiler_ts[1]) |
|
|
|
|
else: |
|
|
|
|
tag = '' |
|
|
|
|
return tag |
|
|
|
|
|
|
|
|
|
def threading_tag(self): |
|
|
|
|
if not self.is_multithreading: |
|
|
|
|
return '' |
|
|
|
|
|
|
|
|
|
if mesonlib.for_darwin(self.want_cross, self.env): |
|
|
|
|
# - Mac: requires -mt for multithreading, so should not fall back to non-mt libraries. |
|
|
|
|
return '-mt' |
|
|
|
|
elif mesonlib.for_windows(self.want_cross, self.env): |
|
|
|
|
# - Windows: requires -mt for multithreading, so should not fall back to non-mt libraries. |
|
|
|
|
return '-mt' |
|
|
|
|
else: |
|
|
|
|
# - Linux: leaves off -mt but libraries are multithreading-aware. |
|
|
|
|
# - Cygwin: leaves off -mt but libraries are multithreading-aware. |
|
|
|
|
return '' |
|
|
|
|
|
|
|
|
|
def version_tag(self): |
|
|
|
|
return '-' + self.version.replace('.', '_') |
|
|
|
|
|
|
|
|
|
def debug_tag(self): |
|
|
|
|
return '-gd' if self.is_debug else '' |
|
|
|
|
|
|
|
|
|
def versioned_abi_tag(self): |
|
|
|
|
return self.compiler_tag() + self.threading_tag() + self.debug_tag() + self.version_tag() |
|
|
|
|
|
|
|
|
|
# FIXME - how to handle different distributions, e.g. for Mac? Currently we handle homebrew and macports, but not fink. |
|
|
|
|
def abi_tags(self): |
|
|
|
|
if mesonlib.for_windows(self.want_cross, self.env): |
|
|
|
|
return [self.versioned_abi_tag(), self.threading_tag()] |
|
|
|
|
else: |
|
|
|
|
return [self.threading_tag()] |
|
|
|
|
|
|
|
|
|
def sourceforge_dir(self): |
|
|
|
|
if self.env.detect_cpp_compiler(self.want_cross).get_id() != 'msvc': |
|
|
|
|
return None |
|
|
|
|
comp_ts_version = self.env.detect_cpp_compiler(self.want_cross).get_toolset_version() |
|
|
|
|
compiler_ts = comp_ts_version.split('.') |
|
|
|
|
compiler = 'vc{}{}'.format(compiler_ts[0], compiler_ts[1]) |
|
|
|
|
arch = detect_cpu_family(self.env.coredata.compilers) |
|
|
|
|
if arch == 'x86': |
|
|
|
|
return 'lib32-msvc-{}'.format(comp_ts_version) |
|
|
|
|
elif arch == 'x86_64': |
|
|
|
|
return 'lib64-msvc-{}'.format(comp_ts_version) |
|
|
|
|
else: |
|
|
|
|
# Does anyone do Boost cross-compiling to other archs on Windows? |
|
|
|
|
return None |
|
|
|
|
|
|
|
|
|
def find_libraries_with_abi_tag(self, tag): |
|
|
|
|
|
|
|
|
|
# All modules should have the same tag |
|
|
|
|
self.lib_modules = {} |
|
|
|
|
|
|
|
|
|
all_found = True |
|
|
|
|
|
|
|
|
|
for module in self.requested_modules: |
|
|
|
|
libname = 'boost_' + module + tag |
|
|
|
|
|
|
|
|
|
args = self.compiler.find_library(libname, self.env, self.extra_lib_dirs()) |
|
|
|
|
if args is None: |
|
|
|
|
mlog.debug("Couldn\'t find library '{}' for boost module '{}' (ABI tag = '{}')".format(libname, module, tag)) |
|
|
|
|
all_found = False |
|
|
|
|
else: |
|
|
|
|
mlog.debug('Link args for boost module "{}" are {}'.format(module, args)) |
|
|
|
|
self.lib_modules['boost_' + module] = args |
|
|
|
|
|
|
|
|
|
return all_found |
|
|
|
|
|
|
|
|
|
def find_libraries_with_abi_tags(self, tags): |
|
|
|
|
for tag in tags: |
|
|
|
|
if self.find_libraries_with_abi_tag(tag): |
|
|
|
|
return True |
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
def detect_lib_modules_win(self): |
|
|
|
|
if not self.libdir: |
|
|
|
|
# The libdirs in the distributed binaries (from sf) |
|
|
|
|
if arch == 'x86': |
|
|
|
|
lib_sf = 'lib32-msvc-{}'.format(comp_ts_version) |
|
|
|
|
elif arch == 'x86_64': |
|
|
|
|
lib_sf = 'lib64-msvc-{}'.format(comp_ts_version) |
|
|
|
|
else: |
|
|
|
|
# Does anyone do Boost cross-compiling to other archs on Windows? |
|
|
|
|
lib_sf = None |
|
|
|
|
lib_sf = self.sourceforge_dir() |
|
|
|
|
|
|
|
|
|
if self.boost_root: |
|
|
|
|
roots = [self.boost_root] |
|
|
|
|
else: |
|
|
|
@ -335,12 +412,8 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
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('.', '_')) |
|
|
|
|
# FIXME - why are we only looking for *.lib? Mingw provides *.dll.a and *.a |
|
|
|
|
libname = 'lib' + name + self.versioned_abi_tag() + '.lib' |
|
|
|
|
if os.path.isfile(os.path.join(self.libdir, libname)): |
|
|
|
|
self.lib_modules[self.modname_from_filename(libname)] = [libname] |
|
|
|
|
else: |
|
|
|
@ -351,52 +424,23 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
# 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 = globber1 + self.versioned_abi_tag() |
|
|
|
|
# FIXME - why are we only looking for *.lib? Mingw provides *.dll.a and *.a |
|
|
|
|
globber2_matches = glob.glob(os.path.join(self.libdir, globber2 + '.lib')) |
|
|
|
|
for entry in globber2_matches: |
|
|
|
|
fname = os.path.basename(entry) |
|
|
|
|
self.lib_modules[self.modname_from_filename(fname)] = [fname] |
|
|
|
|
if len(globber2_matches) == 0: |
|
|
|
|
# FIXME - why are we only looking for *.lib? Mingw provides *.dll.a and *.a |
|
|
|
|
for entry in glob.glob(os.path.join(self.libdir, globber1 + '.lib')): |
|
|
|
|
if self.static: |
|
|
|
|
fname = os.path.basename(entry) |
|
|
|
|
self.lib_modules[self.modname_from_filename(fname)] = [fname] |
|
|
|
|
|
|
|
|
|
# - Linux leaves off -mt but libraries are multithreading-aware. |
|
|
|
|
# - Cygwin leaves off -mt but libraries are multithreading-aware. |
|
|
|
|
# - Mac requires -mt for multithreading, so should not fall back |
|
|
|
|
# to non-mt libraries. |
|
|
|
|
def abi_tag(self): |
|
|
|
|
if mesonlib.for_windows(self.want_cross, self.env): |
|
|
|
|
return None |
|
|
|
|
if self.is_multithreading and mesonlib.for_darwin(self.want_cross, self.env): |
|
|
|
|
return '-mt' |
|
|
|
|
else: |
|
|
|
|
return '' |
|
|
|
|
|
|
|
|
|
def detect_lib_modules_nix(self): |
|
|
|
|
all_found = True |
|
|
|
|
for module in self.requested_modules: |
|
|
|
|
libname = 'boost_' + module + self.abi_tag() |
|
|
|
|
|
|
|
|
|
args = self.compiler.find_library(libname, self.env, self.extra_lib_dirs()) |
|
|
|
|
if args is None: |
|
|
|
|
mlog.debug('Couldn\'t find library "{}" for boost module "{}"'.format(module, libname)) |
|
|
|
|
all_found = False |
|
|
|
|
else: |
|
|
|
|
mlog.debug('Link args for boost module "{}" are {}'.format(module, args)) |
|
|
|
|
self.lib_modules['boost_' + module] = args |
|
|
|
|
if all_found: |
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
if self.static: |
|
|
|
|
libsuffix = 'a' |
|
|
|
|
elif mesonlib.is_osx() and not self.want_cross: |
|
|
|
|
elif mesonlib.for_darwin(self.want_cross, self.env): |
|
|
|
|
libsuffix = 'dylib' |
|
|
|
|
else: |
|
|
|
|
libsuffix = 'so' |
|
|
|
@ -442,7 +486,7 @@ class BoostDependency(ExternalDependency): |
|
|
|
|
def get_link_args(self): |
|
|
|
|
args = [] |
|
|
|
|
for dir in self.extra_lib_dirs(): |
|
|
|
|
args += self.compiler.get_linker_search_args(self.libdir) |
|
|
|
|
args += self.compiler.get_linker_search_args(dir) |
|
|
|
|
for lib in self.requested_modules: |
|
|
|
|
args += self.lib_modules['boost_' + lib] |
|
|
|
|
return args |
|
|
|
|