diff options
Diffstat (limited to '')
-rw-r--r-- | mesonbuild/dependencies/boost.py | 1090 |
1 files changed, 1090 insertions, 0 deletions
diff --git a/mesonbuild/dependencies/boost.py b/mesonbuild/dependencies/boost.py new file mode 100644 index 0000000..4ebd88d --- /dev/null +++ b/mesonbuild/dependencies/boost.py @@ -0,0 +1,1090 @@ +# Copyright 2013-2020 The Meson development team + +# 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. +from __future__ import annotations + +import re +import dataclasses +import functools +import typing as T +from pathlib import Path + +from .. import mlog +from .. import mesonlib + +from .base import DependencyException, SystemDependency +from .pkgconfig import PkgConfigDependency +from .misc import threads_factory + +if T.TYPE_CHECKING: + from ..environment import Environment, Properties + +# 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 +# +# Note that we should also try to support: +# mingw-w64 / Windows : libboost_<module>-mt.a (location = <prefix>/mingw64/lib/) +# libboost_<module>-mt.dll.a +# +# 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 + +# **On Unix**, official packaged versions of boost libraries follow the following schemes: +# +# Linux / Debian: libboost_<module>.so -> libboost_<module>.so.1.66.0 +# Linux / Red Hat: libboost_<module>.so -> libboost_<module>.so.1.66.0 +# Linux / OpenSuse: libboost_<module>.so -> libboost_<module>.so.1.66.0 +# Win / Cygwin: libboost_<module>.dll.a (location = /usr/lib) +# libboost_<module>.a +# cygboost_<module>_1_64.dll (location = /usr/bin) +# Win / VS: boost_<module>-vc<ver>-mt[-gd]-<arch>-1_67.dll (location = C:/local/boost_1_67_0) +# Mac / homebrew: libboost_<module>.dylib + libboost_<module>-mt.dylib (location = /usr/local/lib) +# Mac / macports: libboost_<module>.dylib + libboost_<module>-mt.dylib (location = /opt/local/lib) +# +# Its not clear that any other abi tags (e.g. -gd) are used in official packages. +# +# On Linux systems, boost libs have multithreading support enabled, but without the -mt tag. +# +# Boost documentation recommends using complex abi tags like "-lboost_regex-gcc34-mt-d-1_36". +# (See http://www.boost.org/doc/libs/1_66_0/more/getting_started/unix-variants.html#library-naming) +# However, its not clear that any Unix distribution follows this scheme. +# Furthermore, the boost documentation for unix above uses examples from windows like +# "libboost_regex-vc71-mt-d-x86-1_34.lib", so apparently the abi tags may be more aimed at windows. +# +# We follow the following strategy for finding modules: +# A) Detect potential boost root directories (uses also BOOST_ROOT env var) +# B) Foreach candidate +# 1. Look for the boost headers (boost/version.pp) +# 2. Find all boost libraries +# 2.1 Add all libraries in lib* +# 2.2 Filter out non boost libraries +# 2.3 Filter the renaining libraries based on the meson requirements (static/shared, etc.) +# 2.4 Ensure that all libraries have the same boost tag (and are thus compatible) +# 3. Select the libraries matching the requested modules + +@dataclasses.dataclass(eq=False, order=False) +class UnknownFileException(Exception): + path: Path + +@functools.total_ordering +class BoostIncludeDir(): + def __init__(self, path: Path, version_int: int): + self.path = path + self.version_int = version_int + major = int(self.version_int / 100000) + minor = int((self.version_int / 100) % 1000) + patch = int(self.version_int % 100) + self.version = f'{major}.{minor}.{patch}' + self.version_lib = f'{major}_{minor}' + + def __repr__(self) -> str: + return f'<BoostIncludeDir: {self.version} -- {self.path}>' + + def __lt__(self, other: object) -> bool: + if isinstance(other, BoostIncludeDir): + return (self.version_int, self.path) < (other.version_int, other.path) + return NotImplemented + +@functools.total_ordering +class BoostLibraryFile(): + # Python libraries are special because of the included + # minor version in the module name. + boost_python_libs = ['boost_python', 'boost_numpy'] + reg_python_mod_split = re.compile(r'(boost_[a-zA-Z]+)([0-9]*)') + + reg_abi_tag = re.compile(r'^s?g?y?d?p?n?$') + reg_ver_tag = re.compile(r'^[0-9_]+$') + + def __init__(self, path: Path): + self.path = path + self.name = self.path.name + + # Initialize default properties + self.static = False + self.toolset = '' + self.arch = '' + self.version_lib = '' + self.mt = True + + self.runtime_static = False + self.runtime_debug = False + self.python_debug = False + self.debug = False + self.stlport = False + self.deprecated_iostreams = False + + # Post process the library name + name_parts = self.name.split('.') + self.basename = name_parts[0] + self.suffixes = name_parts[1:] + self.vers_raw = [x for x in self.suffixes if x.isdigit()] + self.suffixes = [x for x in self.suffixes if not x.isdigit()] + self.nvsuffix = '.'.join(self.suffixes) # Used for detecting the library type + self.nametags = self.basename.split('-') + self.mod_name = self.nametags[0] + if self.mod_name.startswith('lib'): + self.mod_name = self.mod_name[3:] + + # Set library version if possible + if len(self.vers_raw) >= 2: + self.version_lib = '{}_{}'.format(self.vers_raw[0], self.vers_raw[1]) + + # Detecting library type + if self.nvsuffix in {'so', 'dll', 'dll.a', 'dll.lib', 'dylib'}: + self.static = False + elif self.nvsuffix in {'a', 'lib'}: + self.static = True + else: + raise UnknownFileException(self.path) + + # boost_.lib is the dll import library + if self.basename.startswith('boost_') and self.nvsuffix == 'lib': + self.static = False + + # Process tags + tags = self.nametags[1:] + # Filter out the python version tag and fix modname + if self.is_python_lib(): + tags = self.fix_python_name(tags) + if not tags: + return + + # Without any tags mt is assumed, however, an absence of mt in the name + # with tags present indicates that the lib was built without mt support + self.mt = False + for i in tags: + if i == 'mt': + self.mt = True + elif len(i) == 3 and i[1:] in {'32', '64'}: + self.arch = i + elif BoostLibraryFile.reg_abi_tag.match(i): + self.runtime_static = 's' in i + self.runtime_debug = 'g' in i + self.python_debug = 'y' in i + self.debug = 'd' in i + self.stlport = 'p' in i + self.deprecated_iostreams = 'n' in i + elif BoostLibraryFile.reg_ver_tag.match(i): + self.version_lib = i + else: + self.toolset = i + + def __repr__(self) -> str: + return f'<LIB: {self.abitag} {self.mod_name:<32} {self.path}>' + + def __lt__(self, other: object) -> bool: + if isinstance(other, BoostLibraryFile): + return ( + self.mod_name, self.static, self.version_lib, self.arch, + not self.mt, not self.runtime_static, + not self.debug, self.runtime_debug, self.python_debug, + self.stlport, self.deprecated_iostreams, + self.name, + ) < ( + other.mod_name, other.static, other.version_lib, other.arch, + not other.mt, not other.runtime_static, + not other.debug, other.runtime_debug, other.python_debug, + other.stlport, other.deprecated_iostreams, + other.name, + ) + return NotImplemented + + def __eq__(self, other: object) -> bool: + if isinstance(other, BoostLibraryFile): + return self.name == other.name + return NotImplemented + + def __hash__(self) -> int: + return hash(self.name) + + @property + def abitag(self) -> str: + abitag = '' + abitag += 'S' if self.static else '-' + abitag += 'M' if self.mt else '-' + abitag += ' ' + abitag += 's' if self.runtime_static else '-' + abitag += 'g' if self.runtime_debug else '-' + abitag += 'y' if self.python_debug else '-' + abitag += 'd' if self.debug else '-' + abitag += 'p' if self.stlport else '-' + abitag += 'n' if self.deprecated_iostreams else '-' + abitag += ' ' + (self.arch or '???') + abitag += ' ' + (self.toolset or '?') + abitag += ' ' + (self.version_lib or 'x_xx') + return abitag + + def is_boost(self) -> bool: + return any(self.name.startswith(x) for x in ['libboost_', 'boost_']) + + def is_python_lib(self) -> bool: + return any(self.mod_name.startswith(x) for x in BoostLibraryFile.boost_python_libs) + + def fix_python_name(self, tags: T.List[str]) -> T.List[str]: + # Handle the boost_python naming madeness. + # See https://github.com/mesonbuild/meson/issues/4788 for some distro + # specific naming variations. + other_tags = [] # type: T.List[str] + + # Split the current modname into the base name and the version + m_cur = BoostLibraryFile.reg_python_mod_split.match(self.mod_name) + cur_name = m_cur.group(1) + cur_vers = m_cur.group(2) + + # Update the current version string if the new version string is longer + def update_vers(new_vers: str) -> None: + nonlocal cur_vers + new_vers = new_vers.replace('_', '') + new_vers = new_vers.replace('.', '') + if not new_vers.isdigit(): + return + if len(new_vers) > len(cur_vers): + cur_vers = new_vers + + for i in tags: + if i.startswith('py'): + update_vers(i[2:]) + elif i.isdigit(): + update_vers(i) + elif len(i) >= 3 and i[0].isdigit and i[2].isdigit() and i[1] == '.': + update_vers(i) + else: + other_tags += [i] + + self.mod_name = cur_name + cur_vers + return other_tags + + def mod_name_matches(self, mod_name: str) -> bool: + if self.mod_name == mod_name: + return True + if not self.is_python_lib(): + return False + + m_cur = BoostLibraryFile.reg_python_mod_split.match(self.mod_name) + m_arg = BoostLibraryFile.reg_python_mod_split.match(mod_name) + + if not m_cur or not m_arg: + return False + + if m_cur.group(1) != m_arg.group(1): + return False + + cur_vers = m_cur.group(2) + arg_vers = m_arg.group(2) + + # Always assume python 2 if nothing is specified + if not arg_vers: + arg_vers = '2' + + return cur_vers.startswith(arg_vers) + + def version_matches(self, version_lib: str) -> bool: + # If no version tag is present, assume that it fits + if not self.version_lib or not version_lib: + return True + return self.version_lib == version_lib + + def arch_matches(self, arch: str) -> bool: + # If no version tag is present, assume that it fits + if not self.arch or not arch: + return True + return self.arch == arch + + def vscrt_matches(self, vscrt: str) -> bool: + # If no vscrt tag present, assume that it fits ['/MD', '/MDd', '/MT', '/MTd'] + if not vscrt: + return True + if vscrt in {'/MD', '-MD'}: + return not self.runtime_static and not self.runtime_debug + elif vscrt in {'/MDd', '-MDd'}: + return not self.runtime_static and self.runtime_debug + elif vscrt in {'/MT', '-MT'}: + return (self.runtime_static or not self.static) and not self.runtime_debug + elif vscrt in {'/MTd', '-MTd'}: + return (self.runtime_static or not self.static) and self.runtime_debug + + mlog.warning(f'Boost: unknown vscrt tag {vscrt}. This may cause the compilation to fail. Please consider reporting this as a bug.', once=True) + return True + + def get_compiler_args(self) -> T.List[str]: + args = [] # type: T.List[str] + if self.mod_name in boost_libraries: + libdef = boost_libraries[self.mod_name] # type: BoostLibrary + if self.static: + args += libdef.static + else: + args += libdef.shared + if self.mt: + args += libdef.multi + else: + args += libdef.single + return args + + def get_link_args(self) -> T.List[str]: + return [self.path.as_posix()] + +class BoostDependency(SystemDependency): + def __init__(self, environment: Environment, kwargs: T.Dict[str, T.Any]) -> None: + super().__init__('boost', environment, kwargs, language='cpp') + buildtype = environment.coredata.get_option(mesonlib.OptionKey('buildtype')) + assert isinstance(buildtype, str) + self.debug = buildtype.startswith('debug') + self.multithreading = kwargs.get('threading', 'multi') == 'multi' + + self.boost_root = None # type: T.Optional[Path] + self.explicit_static = 'static' in kwargs + + # Extract and validate modules + self.modules = mesonlib.extract_as_list(kwargs, 'modules') # type: T.List[str] + for i in self.modules: + if not isinstance(i, str): + raise DependencyException('Boost module argument is not a string.') + if i.startswith('boost_'): + raise DependencyException('Boost modules must be passed without the boost_ prefix') + + self.modules_found = [] # type: T.List[str] + self.modules_missing = [] # type: T.List[str] + + # Do we need threads? + if 'thread' in self.modules: + if not self._add_sub_dependency(threads_factory(environment, self.for_machine, {})): + self.is_found = False + return + + # Try figuring out the architecture tag + self.arch = environment.machines[self.for_machine].cpu_family + self.arch = boost_arch_map.get(self.arch, None) + + # First, look for paths specified in a machine file + props = self.env.properties[self.for_machine] + if any(x in self.env.properties[self.for_machine] for x in + ['boost_includedir', 'boost_librarydir', 'boost_root']): + self.detect_boost_machine_file(props) + return + + # Finally, look for paths from .pc files and from searching the filesystem + self.detect_roots() + + def check_and_set_roots(self, roots: T.List[Path], use_system: bool) -> None: + roots = list(mesonlib.OrderedSet(roots)) + for j in roots: + # 1. Look for the boost headers (boost/version.hpp) + mlog.debug(f'Checking potential boost root {j.as_posix()}') + inc_dirs = self.detect_inc_dirs(j) + inc_dirs = sorted(inc_dirs, reverse=True) # Prefer the newer versions + + # Early abort when boost is not found + if not inc_dirs: + continue + + lib_dirs = self.detect_lib_dirs(j, use_system) + self.is_found = self.run_check(inc_dirs, lib_dirs) + if self.is_found: + self.boost_root = j + break + + def detect_boost_machine_file(self, props: 'Properties') -> None: + """Detect boost with values in the machine file or environment. + + The machine file values are defaulted to the environment values. + """ + # XXX: if we had a TypedDict we wouldn't need this + incdir = props.get('boost_includedir') + assert incdir is None or isinstance(incdir, str) + libdir = props.get('boost_librarydir') + assert libdir is None or isinstance(libdir, str) + + if incdir and libdir: + inc_dir = Path(incdir) + lib_dir = Path(libdir) + + if not inc_dir.is_absolute() or not lib_dir.is_absolute(): + raise DependencyException('Paths given for boost_includedir and boost_librarydir in machine file must be absolute') + + mlog.debug('Trying to find boost with:') + mlog.debug(f' - boost_includedir = {inc_dir}') + mlog.debug(f' - boost_librarydir = {lib_dir}') + + return self.detect_split_root(inc_dir, lib_dir) + + elif incdir or libdir: + raise DependencyException('Both boost_includedir *and* boost_librarydir have to be set in your machine file (one is not enough)') + + rootdir = props.get('boost_root') + # It shouldn't be possible to get here without something in boost_root + assert rootdir + + raw_paths = mesonlib.stringlistify(rootdir) + paths = [Path(x) for x in raw_paths] + if paths and any(not x.is_absolute() for x in paths): + raise DependencyException('boost_root path given in machine file must be absolute') + + self.check_and_set_roots(paths, use_system=False) + + def run_check(self, inc_dirs: T.List[BoostIncludeDir], lib_dirs: T.List[Path]) -> bool: + mlog.debug(' - potential library dirs: {}'.format([x.as_posix() for x in lib_dirs])) + mlog.debug(' - potential include dirs: {}'.format([x.path.as_posix() for x in inc_dirs])) + + # 2. Find all boost libraries + libs = [] # type: T.List[BoostLibraryFile] + for i in lib_dirs: + libs = self.detect_libraries(i) + if libs: + mlog.debug(f' - found boost library dir: {i}') + # mlog.debug(' - raw library list:') + # for j in libs: + # mlog.debug(' - {}'.format(j)) + break + libs = sorted(set(libs)) + + modules = ['boost_' + x for x in self.modules] + for inc in inc_dirs: + mlog.debug(f' - found boost {inc.version} include dir: {inc.path}') + f_libs = self.filter_libraries(libs, inc.version_lib) + + mlog.debug(' - filtered library list:') + for j in f_libs: + mlog.debug(f' - {j}') + + # 3. Select the libraries matching the requested modules + not_found = [] # type: T.List[str] + selected_modules = [] # type: T.List[BoostLibraryFile] + for mod in modules: + found = False + for l in f_libs: + if l.mod_name_matches(mod): + selected_modules += [l] + found = True + break + if not found: + not_found += [mod] + + # log the result + mlog.debug(' - found:') + comp_args = [] # type: T.List[str] + link_args = [] # type: T.List[str] + for j in selected_modules: + c_args = j.get_compiler_args() + l_args = j.get_link_args() + mlog.debug(' - {:<24} link={} comp={}'.format(j.mod_name, str(l_args), str(c_args))) + comp_args += c_args + link_args += l_args + + comp_args = list(mesonlib.OrderedSet(comp_args)) + link_args = list(mesonlib.OrderedSet(link_args)) + + self.modules_found = [x.mod_name for x in selected_modules] + self.modules_found = [x[6:] for x in self.modules_found] + self.modules_found = sorted(set(self.modules_found)) + self.modules_missing = not_found + self.modules_missing = [x[6:] for x in self.modules_missing] + self.modules_missing = sorted(set(self.modules_missing)) + + # if we found all modules we are done + if not not_found: + self.version = inc.version + self.compile_args = ['-I' + inc.path.as_posix()] + self.compile_args += comp_args + self.compile_args += self._extra_compile_args() + self.compile_args = list(mesonlib.OrderedSet(self.compile_args)) + self.link_args = link_args + mlog.debug(f' - final compile args: {self.compile_args}') + mlog.debug(f' - final link args: {self.link_args}') + return True + + # in case we missed something log it and try again + mlog.debug(' - NOT found:') + for mod in not_found: + mlog.debug(f' - {mod}') + + return False + + def detect_inc_dirs(self, root: Path) -> T.List[BoostIncludeDir]: + candidates = [] # type: T.List[Path] + inc_root = root / 'include' + + candidates += [root / 'boost'] + candidates += [inc_root / 'boost'] + if inc_root.is_dir(): + for i in inc_root.iterdir(): + if not i.is_dir() or not i.name.startswith('boost-'): + continue + candidates += [i / 'boost'] + candidates = [x for x in candidates if x.is_dir()] + candidates = [x / 'version.hpp' for x in candidates] + candidates = [x for x in candidates if x.exists()] + return [self._include_dir_from_version_header(x) for x in candidates] + + def detect_lib_dirs(self, root: Path, use_system: bool) -> T.List[Path]: + # First check the system include paths. Only consider those within the + # given root path + + if use_system: + system_dirs_t = self.clib_compiler.get_library_dirs(self.env) + system_dirs = [Path(x) for x in system_dirs_t] + system_dirs = [x.resolve() for x in system_dirs if x.exists()] + system_dirs = [x for x in system_dirs if mesonlib.path_is_in_root(x, root)] + system_dirs = list(mesonlib.OrderedSet(system_dirs)) + + if system_dirs: + return system_dirs + + # No system include paths were found --> fall back to manually looking + # for library dirs in root + dirs = [] # type: T.List[Path] + subdirs = [] # type: T.List[Path] + for i in root.iterdir(): + if i.is_dir() and i.name.startswith('lib'): + dirs += [i] + + # Some distros put libraries not directly inside /usr/lib but in /usr/lib/x86_64-linux-gnu + for i in dirs: + for j in i.iterdir(): + if j.is_dir() and j.name.endswith('-linux-gnu'): + subdirs += [j] + + # Filter out paths that don't match the target arch to avoid finding + # the wrong libraries. See https://github.com/mesonbuild/meson/issues/7110 + if not self.arch: + return dirs + subdirs + + arch_list_32 = ['32', 'i386'] + arch_list_64 = ['64'] + + raw_list = dirs + subdirs + no_arch = [x for x in raw_list if not any(y in x.name for y in arch_list_32 + arch_list_64)] + + matching_arch = [] # type: T.List[Path] + if '32' in self.arch: + matching_arch = [x for x in raw_list if any(y in x.name for y in arch_list_32)] + elif '64' in self.arch: + matching_arch = [x for x in raw_list if any(y in x.name for y in arch_list_64)] + + return sorted(matching_arch) + sorted(no_arch) + + def filter_libraries(self, libs: T.List[BoostLibraryFile], lib_vers: str) -> T.List[BoostLibraryFile]: + # MSVC is very picky with the library tags + vscrt = '' + try: + crt_val = self.env.coredata.options[mesonlib.OptionKey('b_vscrt')].value + buildtype = self.env.coredata.options[mesonlib.OptionKey('buildtype')].value + vscrt = self.clib_compiler.get_crt_compile_args(crt_val, buildtype)[0] + except (KeyError, IndexError, AttributeError): + pass + + # mlog.debug(' - static: {}'.format(self.static)) + # mlog.debug(' - not explicit static: {}'.format(not self.explicit_static)) + # mlog.debug(' - mt: {}'.format(self.multithreading)) + # mlog.debug(' - version: {}'.format(lib_vers)) + # mlog.debug(' - arch: {}'.format(self.arch)) + # mlog.debug(' - vscrt: {}'.format(vscrt)) + libs = [x for x in libs if x.static == self.static or not self.explicit_static] + libs = [x for x in libs if x.mt == self.multithreading] + libs = [x for x in libs if x.version_matches(lib_vers)] + libs = [x for x in libs if x.arch_matches(self.arch)] + libs = [x for x in libs if x.vscrt_matches(vscrt)] + libs = [x for x in libs if x.nvsuffix != 'dll'] # Only link to import libraries + + # Only filter by debug when we are building in release mode. Debug + # libraries are automatically preferred through sorting otherwise. + if not self.debug: + libs = [x for x in libs if not x.debug] + + # Take the abitag from the first library and filter by it. This + # ensures that we have a set of libraries that are always compatible. + if not libs: + return [] + abitag = libs[0].abitag + libs = [x for x in libs if x.abitag == abitag] + + return libs + + def detect_libraries(self, libdir: Path) -> T.List[BoostLibraryFile]: + libs = set() # type: T.Set[BoostLibraryFile] + for i in libdir.iterdir(): + if not i.is_file(): + continue + if not any(i.name.startswith(x) for x in ['libboost_', 'boost_']): + continue + # Windows binaries from SourceForge ship with PDB files alongside + # DLLs (#8325). Ignore them. + if i.name.endswith('.pdb'): + continue + + try: + libs.add(BoostLibraryFile(i.resolve())) + except UnknownFileException as e: + mlog.warning('Boost: ignoring unknown file {} under lib directory'.format(e.path.name)) + + return [x for x in libs if x.is_boost()] # Filter out no boost libraries + + def detect_split_root(self, inc_dir: Path, lib_dir: Path) -> None: + boost_inc_dir = None + for j in [inc_dir / 'version.hpp', inc_dir / 'boost' / 'version.hpp']: + if j.is_file(): + boost_inc_dir = self._include_dir_from_version_header(j) + break + if not boost_inc_dir: + self.is_found = False + return + + self.is_found = self.run_check([boost_inc_dir], [lib_dir]) + + def detect_roots(self) -> None: + roots = [] # type: T.List[Path] + + # Try getting the BOOST_ROOT from a boost.pc if it exists. This primarily + # allows BoostDependency to find boost from Conan. See #5438 + try: + boost_pc = PkgConfigDependency('boost', self.env, {'required': False}) + if boost_pc.found(): + boost_root = boost_pc.get_pkgconfig_variable('prefix', [], None) + if boost_root: + roots += [Path(boost_root)] + except DependencyException: + pass + + # Add roots from system paths + inc_paths = [Path(x) for x in self.clib_compiler.get_default_include_dirs()] + inc_paths = [x.parent for x in inc_paths if x.exists()] + inc_paths = [x.resolve() for x in inc_paths] + roots += inc_paths + + # Add system paths + if self.env.machines[self.for_machine].is_windows(): + # Where boost built from source actually installs it + c_root = Path('C:/Boost') + if c_root.is_dir(): + roots += [c_root] + + # Where boost documentation says it should be + prog_files = Path('C:/Program Files/boost') + # Where boost prebuilt binaries are + local_boost = Path('C:/local') + + candidates = [] # type: T.List[Path] + if prog_files.is_dir(): + candidates += [*prog_files.iterdir()] + if local_boost.is_dir(): + candidates += [*local_boost.iterdir()] + + roots += [x for x in candidates if x.name.lower().startswith('boost') and x.is_dir()] + else: + tmp = [] # type: T.List[Path] + + # Add some default system paths + tmp += [Path('/opt/local')] + tmp += [Path('/usr/local/opt/boost')] + tmp += [Path('/usr/local')] + tmp += [Path('/usr')] + + # Cleanup paths + tmp = [x for x in tmp if x.is_dir()] + tmp = [x.resolve() for x in tmp] + roots += tmp + + self.check_and_set_roots(roots, use_system=True) + + def log_details(self) -> str: + res = '' + if self.modules_found: + res += 'found: ' + ', '.join(self.modules_found) + if self.modules_missing: + if res: + res += ' | ' + res += 'missing: ' + ', '.join(self.modules_missing) + return res + + def log_info(self) -> str: + if self.boost_root: + return self.boost_root.as_posix() + return '' + + def _include_dir_from_version_header(self, hfile: Path) -> BoostIncludeDir: + # Extract the version with a regex. Using clib_compiler.get_define would + # also work, however, this is slower (since it the compiler has to be + # invoked) and overkill since the layout of the header is always the same. + assert hfile.exists() + raw = hfile.read_text(encoding='utf-8') + m = re.search(r'#define\s+BOOST_VERSION\s+([0-9]+)', raw) + if not m: + mlog.debug(f'Failed to extract version information from {hfile}') + return BoostIncludeDir(hfile.parents[1], 0) + return BoostIncludeDir(hfile.parents[1], int(m.group(1))) + + def _extra_compile_args(self) -> T.List[str]: + # BOOST_ALL_DYN_LINK should not be required with the known defines below + return ['-DBOOST_ALL_NO_LIB'] # Disable automatic linking + + +# See https://www.boost.org/doc/libs/1_72_0/more/getting_started/unix-variants.html#library-naming +# See https://mesonbuild.com/Reference-tables.html#cpu-families +boost_arch_map = { + 'aarch64': 'a64', + 'arc': 'a32', + 'arm': 'a32', + 'ia64': 'i64', + 'mips': 'm32', + 'mips64': 'm64', + 'ppc': 'p32', + 'ppc64': 'p64', + 'sparc': 's32', + 'sparc64': 's64', + 'x86': 'x32', + 'x86_64': 'x64', +} + + +#### ---- BEGIN GENERATED ---- #### +# # +# Generated with tools/boost_names.py: +# - boost version: 1.73.0 +# - modules found: 159 +# - libraries found: 43 +# + +class BoostLibrary(): + def __init__(self, name: str, shared: T.List[str], static: T.List[str], single: T.List[str], multi: T.List[str]): + self.name = name + self.shared = shared + self.static = static + self.single = single + self.multi = multi + +class BoostModule(): + def __init__(self, name: str, key: str, desc: str, libs: T.List[str]): + self.name = name + self.key = key + self.desc = desc + self.libs = libs + + +# dict of all know libraries with additional compile options +boost_libraries = { + 'boost_atomic': BoostLibrary( + name='boost_atomic', + shared=['-DBOOST_ATOMIC_DYN_LINK=1'], + static=['-DBOOST_ATOMIC_STATIC_LINK=1'], + single=[], + multi=[], + ), + 'boost_chrono': BoostLibrary( + name='boost_chrono', + shared=['-DBOOST_CHRONO_DYN_LINK=1'], + static=['-DBOOST_CHRONO_STATIC_LINK=1'], + single=['-DBOOST_CHRONO_THREAD_DISABLED'], + multi=[], + ), + 'boost_container': BoostLibrary( + name='boost_container', + shared=['-DBOOST_CONTAINER_DYN_LINK=1'], + static=['-DBOOST_CONTAINER_STATIC_LINK=1'], + single=[], + multi=[], + ), + 'boost_context': BoostLibrary( + name='boost_context', + shared=['-DBOOST_CONTEXT_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_contract': BoostLibrary( + name='boost_contract', + shared=['-DBOOST_CONTRACT_DYN_LINK'], + static=['-DBOOST_CONTRACT_STATIC_LINK'], + single=['-DBOOST_CONTRACT_DISABLE_THREADS'], + multi=[], + ), + 'boost_coroutine': BoostLibrary( + name='boost_coroutine', + shared=['-DBOOST_COROUTINES_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_date_time': BoostLibrary( + name='boost_date_time', + shared=['-DBOOST_DATE_TIME_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_exception': BoostLibrary( + name='boost_exception', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_fiber': BoostLibrary( + name='boost_fiber', + shared=['-DBOOST_FIBERS_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_fiber_numa': BoostLibrary( + name='boost_fiber_numa', + shared=['-DBOOST_FIBERS_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_filesystem': BoostLibrary( + name='boost_filesystem', + shared=['-DBOOST_FILESYSTEM_DYN_LINK=1'], + static=['-DBOOST_FILESYSTEM_STATIC_LINK=1'], + single=[], + multi=[], + ), + 'boost_graph': BoostLibrary( + name='boost_graph', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_iostreams': BoostLibrary( + name='boost_iostreams', + shared=['-DBOOST_IOSTREAMS_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_locale': BoostLibrary( + name='boost_locale', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_log': BoostLibrary( + name='boost_log', + shared=['-DBOOST_LOG_DYN_LINK=1'], + static=[], + single=['-DBOOST_LOG_NO_THREADS'], + multi=[], + ), + 'boost_log_setup': BoostLibrary( + name='boost_log_setup', + shared=['-DBOOST_LOG_SETUP_DYN_LINK=1'], + static=[], + single=['-DBOOST_LOG_NO_THREADS'], + multi=[], + ), + 'boost_math_c99': BoostLibrary( + name='boost_math_c99', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_math_c99f': BoostLibrary( + name='boost_math_c99f', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_math_c99l': BoostLibrary( + name='boost_math_c99l', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_math_tr1': BoostLibrary( + name='boost_math_tr1', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_math_tr1f': BoostLibrary( + name='boost_math_tr1f', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_math_tr1l': BoostLibrary( + name='boost_math_tr1l', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_mpi': BoostLibrary( + name='boost_mpi', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_nowide': BoostLibrary( + name='boost_nowide', + shared=['-DBOOST_NOWIDE_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_prg_exec_monitor': BoostLibrary( + name='boost_prg_exec_monitor', + shared=['-DBOOST_TEST_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_program_options': BoostLibrary( + name='boost_program_options', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_random': BoostLibrary( + name='boost_random', + shared=['-DBOOST_RANDOM_DYN_LINK'], + static=[], + single=[], + multi=[], + ), + 'boost_regex': BoostLibrary( + name='boost_regex', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_serialization': BoostLibrary( + name='boost_serialization', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_stacktrace_addr2line': BoostLibrary( + name='boost_stacktrace_addr2line', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_stacktrace_backtrace': BoostLibrary( + name='boost_stacktrace_backtrace', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_stacktrace_basic': BoostLibrary( + name='boost_stacktrace_basic', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_stacktrace_noop': BoostLibrary( + name='boost_stacktrace_noop', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_stacktrace_windbg': BoostLibrary( + name='boost_stacktrace_windbg', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_stacktrace_windbg_cached': BoostLibrary( + name='boost_stacktrace_windbg_cached', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_system': BoostLibrary( + name='boost_system', + shared=['-DBOOST_SYSTEM_DYN_LINK=1'], + static=['-DBOOST_SYSTEM_STATIC_LINK=1'], + single=[], + multi=[], + ), + 'boost_test_exec_monitor': BoostLibrary( + name='boost_test_exec_monitor', + shared=['-DBOOST_TEST_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_thread': BoostLibrary( + name='boost_thread', + shared=['-DBOOST_THREAD_BUILD_DLL=1', '-DBOOST_THREAD_USE_DLL=1'], + static=['-DBOOST_THREAD_BUILD_LIB=1', '-DBOOST_THREAD_USE_LIB=1'], + single=[], + multi=[], + ), + 'boost_timer': BoostLibrary( + name='boost_timer', + shared=['-DBOOST_TIMER_DYN_LINK=1'], + static=['-DBOOST_TIMER_STATIC_LINK=1'], + single=[], + multi=[], + ), + 'boost_type_erasure': BoostLibrary( + name='boost_type_erasure', + shared=['-DBOOST_TYPE_ERASURE_DYN_LINK'], + static=[], + single=[], + multi=[], + ), + 'boost_unit_test_framework': BoostLibrary( + name='boost_unit_test_framework', + shared=['-DBOOST_TEST_DYN_LINK=1'], + static=[], + single=[], + multi=[], + ), + 'boost_wave': BoostLibrary( + name='boost_wave', + shared=[], + static=[], + single=[], + multi=[], + ), + 'boost_wserialization': BoostLibrary( + name='boost_wserialization', + shared=[], + static=[], + single=[], + multi=[], + ), +} + +# # +#### ---- END GENERATED ---- #### |