summaryrefslogtreecommitdiffstats
path: root/mesonbuild/dependencies/boost.py
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--mesonbuild/dependencies/boost.py1090
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 ---- ####