diff options
author | Egor Tensin <Egor.Tensin@gmail.com> | 2020-03-29 20:34:08 +0300 |
---|---|---|
committer | Egor Tensin <Egor.Tensin@gmail.com> | 2020-03-29 20:34:08 +0300 |
commit | 1106f51640ee3cec107a8ac904a818767c21a9aa (patch) | |
tree | 477c6c94b3c5cf2d3cf700eee686377ad2f8ad7c /project/boost/toolchain.py | |
parent | project: add os.py (diff) | |
download | cmake-common-1106f51640ee3cec107a8ac904a818767c21a9aa.tar.gz cmake-common-1106f51640ee3cec107a8ac904a818767c21a9aa.zip |
project.boost: first-class MinGW-w64 support
Diffstat (limited to 'project/boost/toolchain.py')
-rw-r--r-- | project/boost/toolchain.py | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/project/boost/toolchain.py b/project/boost/toolchain.py new file mode 100644 index 0000000..9cc452b --- /dev/null +++ b/project/boost/toolchain.py @@ -0,0 +1,108 @@ +# Copyright (c) 2020 Egor Tensin <Egor.Tensin@gmail.com> +# This file is part of the "cmake-common" project. +# For details, see https://github.com/egor-tensin/cmake-common. +# Distributed under the MIT License. + +R'''Compiler detection. + +It is assumed that Boost.Build is good enough to detect both GCC on Linux and +MSVC on Windows. From that point on, it's just a matter of setting the correct +address-model= value. + +But I also frequently use MinGW-w64, and the most convinient way to use it that +I know is making a "user config" and passing it to b2 using the --user-config +parameter. +''' + +import abc +from contextlib import contextmanager +import logging +import tempfile + +import project.os + + +class Toolchain(abc.ABC): + def __init__(self, platform): + self.platform = platform + + @abc.abstractmethod + def get_b2_args(self): + pass + + +class NativeToolchain(Toolchain): + def get_b2_args(self): + return [f'address-model={self.platform.get_address_model()}'] + + +class MingwToolchain(Toolchain): + TAG = 'custom' + + def __init__(self, platform, config_path): + super().__init__(platform) + self.config_path = config_path + + def get_b2_args(self): + return [f'--user-config={self.config_path}', f'toolset=gcc-{MingwToolchain.TAG}'] + + +def _native_toolchain(platform): + return NativeToolchain(platform) + + +def _get_mingw_prefix(platform): + target_arch = platform.get_address_model() + if target_arch == 32: + return 'i686' + if target_arch == 64: + return 'x86_64' + raise RuntimeError(f'unexpected address model: {target_arch}') + + +def _get_mingw_path(platform): + prefix = _get_mingw_prefix(platform) + ext = '' + if project.os.on_windows_like(): + # Boost.Build wants the .exe extension at the end on Cygwin. + ext = '.exe' + path = f'{prefix}-w64-mingw32-g++{ext}' + return path + + +def _format_user_config(tag, compiler, **kwargs): + features = (f'<{k}>{v}' for k, v in kwargs.items()) + features = ' '.join(features) + return f'using gcc : {tag} : {compiler} : {features} ;' + + +def _format_mingw_user_config(platform): + compiler = _get_mingw_path(platform) + features = { + 'target-os': 'windows', + 'address-model': platform.get_address_model(), + } + return _format_user_config(MingwToolchain.TAG, compiler, **features) + + +@contextmanager +def _mingw_toolchain(platform): + tmp = tempfile.NamedTemporaryFile(mode='w', prefix='mingw_w64_', suffix='.jam') + with tmp as file: + config = _format_mingw_user_config(platform) + logging.info('Using user config:\n%s', config) + file.write(config) + file.flush() + try: + yield MingwToolchain(platform, file.name) + finally: + logging.info('Removing temporary user config file') + + +@contextmanager +def detect_toolchain(platform, mingw=False): + if mingw: + with _mingw_toolchain(platform) as toolchain: + yield toolchain + else: + yield _native_toolchain(platform) |