Merge pull request #3004 from bredelings/clean-boost

Factor out code for windows abi tags.
pull/3075/head
Jussi Pakkanen 7 years ago committed by GitHub
commit 6257fe9e35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 206
      mesonbuild/dependencies/misc.py

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

Loading…
Cancel
Save