aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--project/boost/build.py30
-rw-r--r--project/boost/directory.py8
-rw-r--r--project/boost/toolchain.py272
3 files changed, 133 insertions, 177 deletions
diff --git a/project/boost/build.py b/project/boost/build.py
index fd5ed24..32b355a 100644
--- a/project/boost/build.py
+++ b/project/boost/build.py
@@ -85,10 +85,11 @@ class BuildParameters:
def enum_b2_args(self):
with self._create_build_dir() as build_dir:
for platform in self.platforms:
- with Toolchain.detect(self.toolset, platform) as toolchain:
- for configuration in self.configurations:
- for link, runtime_link in self._enum_linkage_options():
- yield self._b2_args(build_dir, toolchain, configuration, link, runtime_link)
+ toolchain = Toolchain.make(self.toolset, platform)
+ for configuration in self.configurations:
+ for link, runtime_link in self._enum_linkage_options():
+ with self._b2_args(build_dir, toolchain, platform, configuration, link, runtime_link) as args:
+ yield args
def _enum_linkage_options(self):
for link in self.link:
@@ -117,16 +118,17 @@ class BuildParameters:
logging.info('Removing build directory: %s', build_dir)
return
- def _b2_args(self, build_dir, toolchain, configuration, link, runtime_link):
- result = []
- result.append(f'--build-dir={build_dir}')
- result.append('--layout=system')
- result += toolchain.b2_args(configuration)
- result += configuration.b2_args()
- result += link.b2_args()
- result += runtime_link.b2_args('runtime-link')
- result += self.b2_args
- return result
+ @contextmanager
+ def _b2_args(self, build_dir, toolchain, platform, configuration, link, runtime_link):
+ with toolchain.b2_args() as result:
+ result.append(f'--build-dir={build_dir}')
+ result.append('--layout=system')
+ result += platform.b2_args(configuration)
+ result += configuration.b2_args()
+ result += link.b2_args()
+ result += runtime_link.b2_args('runtime-link')
+ result += self.b2_args
+ yield result
def build(params):
diff --git a/project/boost/directory.py b/project/boost/directory.py
index 9b35194..162562c 100644
--- a/project/boost/directory.py
+++ b/project/boost/directory.py
@@ -6,7 +6,7 @@
import logging
import os.path
-from project.boost.toolchain import BootstrapToolchain
+from project.boost.toolchain import Toolchain
from project.utils import cd, run
from project.os import on_windows
@@ -33,8 +33,7 @@ class BoostDir:
def bootstrap(self, params):
with self._go():
- toolchain = BootstrapToolchain.detect(params.toolset)
- run([self._bootstrap_path()] + self._bootstrap_args(toolchain))
+ run([self._bootstrap_path()] + self._bootstrap_args(params.toolset))
def _b2(self, params):
for b2_params in params.enum_b2_args():
@@ -52,7 +51,8 @@ class BoostDir:
return f'bootstrap{ext}'
@staticmethod
- def _bootstrap_args(toolchain):
+ def _bootstrap_args(hint):
+ toolchain = Toolchain.detect(hint)
if on_windows():
return toolchain.get_bootstrap_bat_args()
return toolchain.get_bootstrap_sh_args()
diff --git a/project/boost/toolchain.py b/project/boost/toolchain.py
index e49914c..2ff409f 100644
--- a/project/boost/toolchain.py
+++ b/project/boost/toolchain.py
@@ -17,129 +17,74 @@ from project.toolchain import ToolchainType
from project.utils import temp_file
-class BootstrapToolchain(abc.ABC):
- @abc.abstractmethod
- def get_bootstrap_bat_args(self):
- pass
-
- @abc.abstractmethod
- def get_bootstrap_sh_args(self):
- pass
-
- @staticmethod
- def detect(hint):
- if hint is ToolchainType.AUTO:
- return BootstrapAuto()
- if hint is ToolchainType.MSVC:
- return BootstrapMSVC()
- if hint is ToolchainType.GCC:
- return BootstrapGCC()
- if hint is ToolchainType.MINGW:
- return BootstrapMinGW()
- if hint is ToolchainType.CLANG:
- return BootstrapClang()
- if hint is ToolchainType.CLANG_CL:
- return BootstrapClangCL()
- raise NotImplementedError(f'unrecognized toolset: {hint}')
-
-
-class BootstrapAuto(BootstrapToolchain):
- # Let Boost.Build do the detection. Most commonly it means GCC on
- # Linux-likes and MSVC on Windows.
-
- def get_bootstrap_bat_args(self):
- return []
-
- def get_bootstrap_sh_args(self):
- return []
-
-
-class BootstrapMSVC(BootstrapAuto):
- # bootstrap.bat picks up MSVC by default.
- pass
-
-
-class BootstrapGCC(BootstrapToolchain):
- def get_bootstrap_bat_args(self):
- return ['gcc']
-
- def get_bootstrap_sh_args(self):
- return ['--with-toolset=gcc']
-
-
def _gcc_or_auto():
if shutil.which('gcc') is not None:
return ['gcc']
return []
-class BootstrapMinGW(BootstrapToolchain):
- def get_bootstrap_bat_args(self):
- # On Windows, prefer GCC if it's available.
- return _gcc_or_auto()
-
- def get_bootstrap_sh_args(self):
- return []
-
-
-class BootstrapClang(BootstrapToolchain):
- def get_bootstrap_bat_args(self):
- # As of 1.74.0, bootstrap.bat isn't really aware of Clang, so try GCC,
- # then auto-detect.
- return _gcc_or_auto()
-
- def get_bootstrap_sh_args(self):
- # bootstrap.sh, on the other hand, is very much aware of Clang, and
- # it can build b2 using this compiler.
- return ['--with-toolset=clang']
-
-
-class BootstrapClangCL(BootstrapClang):
- # There's no point in building b2 using clang-cl; clang though, presumably
- # installed alongside clang-cl, should still be used if possible.
- pass
-
-
class Toolchain(abc.ABC):
- def __init__(self, platform):
- self.platform = platform
+ @contextmanager
+ def b2_args(self):
+ # Write the config file, etc.
+ yield []
- def b2_args(self, configuration):
- return self.platform.b2_args(configuration)
+ @staticmethod
+ @abc.abstractmethod
+ def get_bootstrap_bat_args():
+ pass
@staticmethod
- @contextmanager
- def detect(hint, platform):
+ @abc.abstractmethod
+ def get_bootstrap_sh_args():
+ pass
+
+ @staticmethod
+ def detect(hint):
if hint is ToolchainType.AUTO:
- yield Auto(platform)
+ return Auto
elif hint is ToolchainType.MSVC:
- yield MSVC(platform)
+ return MSVC
elif hint is ToolchainType.GCC:
- with GCC.setup(platform) as toolchain:
- yield toolchain
+ return GCC
elif hint is ToolchainType.MINGW:
- with MinGW.setup(platform) as toolchain:
- yield toolchain
+ return MinGW
elif hint is ToolchainType.CLANG:
- with Clang.setup(platform) as toolchain:
- yield toolchain
+ return Clang
elif hint is ToolchainType.CLANG_CL:
- yield ClangCL(platform)
+ return ClangCL
else:
raise NotImplementedError(f'unrecognized toolset: {hint}')
+ @staticmethod
+ def make(hint, platform):
+ # Platform is required here, since some toolchains (MinGW-w64) require
+ # it for the compiler path.
+ cls = Toolchain.detect(hint)
+ if cls is MinGW:
+ return MinGW(platform)
+ return cls()
+
class Auto(Toolchain):
# Let Boost.Build do the detection. Most commonly it means GCC on
# Linux-likes and MSVC on Windows.
- pass
+
+ @staticmethod
+ def get_bootstrap_bat_args():
+ return []
+
+ @staticmethod
+ def get_bootstrap_sh_args():
+ return []
class MSVC(Auto):
- def b2_args(self, configuration):
- return super().b2_args(configuration) + [
- 'toolset=msvc',
- ]
+ @contextmanager
+ def b2_args(self):
+ yield ['toolset=msvc']
+
+ # Note: bootstrap.bat picks up MSVC by default.
def _full_exe_name(exe):
@@ -169,88 +114,69 @@ def _full_exe_name(exe):
return os.path.basename(path)
-class CustomToolchain(Toolchain):
+class Custom(Toolchain):
COMPILER_VERSION = 'custom'
- def __init__(self, platform, config_path):
- super().__init__(platform)
- self.config_path = config_path
- compiler = self.get_compiler()
+ def __init__(self, compiler, path=None, build_options=None):
if not compiler:
raise RuntimeError('compiler type is required (like gcc, clang, etc.)')
self.compiler = compiler
- version = CustomToolchain.COMPILER_VERSION
+ version = Custom.COMPILER_VERSION
self.version = version
- path = self.get_compiler_path() or ''
+ path = path or ''
path = path and _full_exe_name(path)
self.path = path
-
- @abc.abstractmethod
- def get_compiler(self):
- pass
-
- @staticmethod
- def get_compiler_version():
- return CustomToolchain.COMPILER_VERSION
-
- @abc.abstractmethod
- def get_compiler_path(self):
- pass
-
- @abc.abstractmethod
- def get_build_options(self):
- pass
-
- def format_build_options(self):
- return ''.join(f'\n <{name}>{val}' for name, val in self.get_build_options())
+ build_options = build_options or []
+ self.build_options = build_options
def toolset(self):
if self.version:
return f'{self.compiler}-{self.version}'
return self.compiler
- def b2_toolset(self):
+ def b2_arg_toolset(self):
return f'toolset={self.toolset()}'
+ def _format_build_options(self):
+ return ''.join(f'\n <{name}>{val}' for name, val in self.build_options)
+
def format_config(self):
version = self.version and f'{self.version} '
path = self.path and f'{self.path} '
- return f'''using {self.compiler} : {version}: {path}:{self.format_build_options()}
+ return f'''using {self.compiler} : {version}: {path}:{self._format_build_options()}
;'''
- @classmethod
@contextmanager
- def setup(cls, platform):
+ def b2_args(self):
config_file = temp_file(prefix='user_config_', suffix='.jam')
with config_file as config_path:
- toolset = cls(platform, config_path)
- config = toolset.format_config()
+ config = self.format_config()
logging.info('Using user config:\n%s', config)
with open(config_path, mode='w') as fd:
fd.write(config)
- yield toolset
-
- def b2_args(self, configuration):
- # All the required options and the toolset definition should be in the
- # user configuration file.
- args = super().b2_args(configuration)
- args.append(self.b2_toolset())
- args.append(f'--user-config={self.config_path}')
- return args
+ args = []
+ args.append(self.b2_arg_toolset())
+ args.append(f'--user-config={config_path}')
+ yield args
-class GCC(CustomToolchain):
+class GCC(Custom):
# Force GCC. We don't care whether it's a native Linux GCC or a
# MinGW-flavoured GCC on Windows.
- COMPILER = 'gcc'
+ def __init__(self, path='g++', build_options=None):
+ build_options = build_options or self.get_build_options()
+ super().__init__('gcc', path, build_options)
- def get_compiler(self):
- return GCC.COMPILER
+ @staticmethod
+ def get_bootstrap_bat_args():
+ return ['gcc']
- def get_compiler_path(self):
- return 'g++'
+ @staticmethod
+ def get_bootstrap_sh_args():
+ return [f'--with-toolset=gcc']
- def get_build_options(self):
+ @staticmethod
+ def get_build_options():
return []
@@ -259,23 +185,39 @@ class MinGW(GCC):
# GCC prefix (like "x86_64-w64-mingw32" and prepend it to other tools like
# "ar").
- def get_compiler_path(self):
- paths = project.mingw.MinGW(self.platform)
- compiler = paths.gxx()
- return compiler
+ def __init__(self, platform):
+ paths = project.mingw.MinGW(platform)
+ super().__init__(paths.gxx())
+ @staticmethod
+ def get_bootstrap_bat_args():
+ # On Windows, prefer GCC if it's available.
+ return _gcc_or_auto()
-class Clang(GCC):
- COMPILER = 'clang'
+ @staticmethod
+ def get_bootstrap_sh_args():
+ return []
- def get_compiler(self):
- return Clang.COMPILER
- def get_compiler_path(self):
- return 'clang++'
+class Clang(Custom):
+ def __init__(self):
+ super().__init__('clang', 'clang++', self.get_build_options())
+
+ @staticmethod
+ def get_bootstrap_bat_args():
+ # As of 1.74.0, bootstrap.bat isn't really aware of Clang, so try GCC,
+ # then auto-detect.
+ return _gcc_or_auto()
+
+ @staticmethod
+ def get_bootstrap_sh_args():
+ # bootstrap.sh, on the other hand, is very much aware of Clang, and
+ # it can build b2 using this compiler.
+ return ['--with-toolset=clang']
- def get_build_options(self):
- options = super().get_build_options()
+ @staticmethod
+ def get_build_options():
+ options = GCC.get_build_options()
options += [
('cxxflags', '-DBOOST_USE_WINDOWS_H'),
@@ -313,8 +255,20 @@ class Clang(GCC):
class ClangCL(Toolchain):
- def b2_args(self, configuration):
- return super().b2_args(configuration) + [
+ @contextmanager
+ def b2_args(self):
+ yield [
'toolset=clang-win',
'define=BOOST_USE_WINDOWS_H',
]
+
+ # There's no point in building b2 using clang-cl; clang though, presumably
+ # installed alongside clang-cl, should still be used if possible.
+
+ @staticmethod
+ def get_bootstrap_bat_args():
+ return Clang.get_bootstrap_bat_args()
+
+ @staticmethod
+ def get_bootstrap_sh_args():
+ return Clang.get_bootstrap_sh_args()