# 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. import os import re import functools import typing as T from .._pathlib import Path from .. import mlog from .. import mesonlib from ..envconfig import get_env_var from ..environment import Environment from .base import DependencyException, ExternalDependency, PkgConfigDependency from .misc import threads_factory # 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-/*.lib where arch=32/64 and compiler=msvc-14.1 # # Note that we should also try to support: # mingw-w64 / Windows : libboost_-mt.a (location = /mingw64/lib/) # libboost_-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_.so -> libboost_.so.1.66.0 # Linux / Red Hat: libboost_.so -> libboost_.so.1.66.0 # Linux / OpenSuse: libboost_.so -> libboost_.so.1.66.0 # Win / Cygwin: libboost_.dll.a (location = /usr/lib) # libboost_.a # cygboost__1_64.dll (location = /usr/bin) # Win / VS: boost_-vc-mt[-gd]--1_67.dll (location = C:/local/boost_1_67_0) # Mac / homebrew: libboost_.dylib + libboost_-mt.dylib (location = /usr/local/lib) # Mac / macports: libboost_.dylib + libboost_-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 @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 = '{}.{}.{}'.format(major, minor, patch) self.version_lib = '{}_{}'.format(major, minor) def __repr__(self) -> str: return ''.format(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 DependencyException('Unable to process library extension "{}" ({})'.format(self.nvsuffix, 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 ''.format(self.abitag, self.mod_name, 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 variantions. 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('Boost: unknow vscrt tag {}. This may cause the compilation to fail. Please consider reporting this as a bug.'.format(vscrt), 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(ExternalDependency): def __init__(self, environment: Environment, kwargs: T.Dict[str, T.Any]) -> None: super().__init__('boost', environment, kwargs, language='cpp') buildtype = environment.coredata.get_builtin_option('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] boost_property_env = [props.get('boost_includedir'), props.get('boost_librarydir'), props.get('boost_root')] if any(boost_property_env): self.detect_boost_machine_file(props) return # Next, look for paths in the environment boost_manual_env_list = ['BOOST_INCLUDEDIR', 'BOOST_LIBRARYDIR', 'BOOST_ROOT', 'BOOSTROOT'] boost_manual_env = [get_env_var(self.for_machine, self.env.is_cross_build, x) for x in boost_manual_env_list] if any(boost_manual_env): self.detect_boost_env() 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]) -> None: roots = list(mesonlib.OrderedSet(roots)) for j in roots: # 1. Look for the boost headers (boost/version.hpp) mlog.debug('Checking potential boost root {}'.format(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) 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: T.Dict[str, str]) -> None: incdir = props.get('boost_includedir') libdir = props.get('boost_librarydir') if incdir and libdir: inc_dir = Path(props['boost_includedir']) lib_dir = Path(props['boost_librarydir']) 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(' - boost_includedir = {}'.format(inc_dir)) mlog.debug(' - boost_librarydir = {}'.format(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) def detect_boost_env(self) -> None: boost_includedir = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOST_INCLUDEDIR') boost_librarydir = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOST_LIBRARYDIR') boost_manual_env = [boost_includedir, boost_librarydir] if all(boost_manual_env): inc_dir = Path(boost_includedir) lib_dir = Path(boost_librarydir) if not inc_dir.is_absolute() or not lib_dir.is_absolute(): raise DependencyException('Paths given in BOOST_INCLUDEDIR and BOOST_LIBRARYDIR must be absolute') mlog.debug('Trying to find boost with:') mlog.debug(' - BOOST_INCLUDEDIR = {}'.format(inc_dir)) mlog.debug(' - BOOST_LIBRARYDIR = {}'.format(lib_dir)) return self.detect_split_root(inc_dir, lib_dir) elif any(boost_manual_env): raise DependencyException('Both BOOST_INCLUDEDIR *and* BOOST_LIBRARYDIR have to be set (one is not enough). Ignoring.') boost_root = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOST_ROOT') boostroot = get_env_var(self.for_machine, self.env.is_cross_build, 'BOOSTROOT') # It shouldn't be possible to get here without something in BOOST_ROOT or BOOSTROOT assert(boost_root or boostroot) for path, name in [(boost_root, 'BOOST_ROOT'), (boostroot, 'BOOSTROOT')]: if path: raw_paths = path.split(os.pathsep) paths = [Path(x) for x in raw_paths] if paths and any([not x.is_absolute() for x in paths]): raise DependencyException('Paths in {} must be absolute'.format(name)) break self.check_and_set_roots(paths) 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(' - found boost library dir: {}'.format(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(' - found boost {} include dir: {}'.format(inc.version, inc.path)) f_libs = self.filter_libraries(libs, inc.version_lib) mlog.debug(' - filtered library list:') for j in f_libs: mlog.debug(' - {}'.format(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(set(comp_args)) link_args = list(set(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(' - final compile args: {}'.format(self.compile_args)) mlog.debug(' - final link args: {}'.format(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(' - {}'.format(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) -> T.List[Path]: # First check the system include paths. Only consider those within the # given root path 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.base_options['b_vscrt'].value buildtype = self.env.coredata.builtins['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 prefered 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 = [] # type: T.List[BoostLibraryFile] for i in libdir.iterdir(): if not i.is_file() or i.is_symlink(): continue if not any([i.name.startswith(x) for x in ['libboost_', 'boost_']]): continue libs += [BoostLibraryFile(i)] 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', {'default': 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] # Homebrew brew_boost = Path('/usr/local/Cellar/boost') if brew_boost.is_dir(): tmp += [x for x in brew_boost.iterdir()] # 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) 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() m = re.search(r'#define\s+BOOST_VERSION\s+([0-9]+)', raw) if not m: mlog.debug('Failed to extract version information from {}'.format(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 ---- ####