#!/usr/bin/python3 # # Copyright (c) 2019-2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) # # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # from pathlib import Path import os from typing import Optional, Dict from .common import run, BOOST_ROOT, IS_WINDOWS, mkdir_and_cd from .db_setup import db_setup, db_setup_bench from .install_boost import install_boost from .bench import run_benchmarks def _cmake_prefix_path(extra_path: Optional[Path] = None) -> str: prefix_path_args = [extra_path, 'C:\\openssl-64' if IS_WINDOWS else None] return ';'.join(str(p) for p in prefix_path_args if p is not None) def _cmake_bool(value: bool) -> str: return 'ON' if value else 'OFF' class _CMakeRunner: def __init__(self, generator: str, build_type: str) -> None: self._generator = generator self._build_type = build_type os.environ['CMAKE_BUILD_PARALLEL_LEVEL'] = '4' def configure(self, source_dir: Path, binary_dir: Path, variables: Dict[str, str]) -> None: mkdir_and_cd(binary_dir) run( [ 'cmake', '-G', self._generator, '-DCMAKE_BUILD_TYPE={}'.format(self._build_type), ] + ['-D{}={}'.format(name, value) for name, value in variables.items()] + [str(source_dir)] ) def build(self, target: str) -> None: run(['cmake', '--build', '.', '--target', target, '--config', self._build_type]) def build_all(self) -> None: run(['cmake', '--build', '.', '--config', self._build_type]) def ctest(self, no_tests_error: bool = True) -> None: run( ['ctest', '--output-on-failure'] + (['--no-tests=error'] if no_tests_error else []) + ['--build-config', self._build_type] ) # Regular CMake build def cmake_build( source_dir: Path, boost_branch: str, generator: str, build_shared_libs: bool, build_type: str, cxxstd: str, server_host: str, install_test: bool, ) -> None: # Config cmake_distro = Path(os.path.expanduser('~')).joinpath('cmake-distro') test_folder = BOOST_ROOT.joinpath('libs', 'mysql', 'test', 'cmake_test') runner = _CMakeRunner(generator=generator, build_type=build_type) # Get Boost install_boost( source_dir=source_dir, boost_branch=boost_branch, ) # Setup DB db_setup(source_dir, server_host) # Build the library, run the tests, and install, as the Boost superproject does bin_dir = BOOST_ROOT.joinpath('__build') runner.configure( source_dir=BOOST_ROOT, binary_dir=bin_dir, variables={ 'CMAKE_PREFIX_PATH': _cmake_prefix_path(), 'BOOST_INCLUDE_LIBRARIES': 'mysql', 'BUILD_SHARED_LIBS': _cmake_bool(build_shared_libs), 'CMAKE_INSTALL_PREFIX': str(cmake_distro), 'BUILD_TESTING': 'ON', 'CMAKE_INSTALL_MESSAGE': 'NEVER', 'BOOST_MYSQL_INTEGRATION_TESTS': 'ON', **({ 'CMAKE_CXX_STANDARD': cxxstd } if cxxstd else {}) } ) runner.build(target='tests') runner.ctest() runner.build(target='install') # The library can be consumed using add_subdirectory runner.configure( source_dir=test_folder, binary_dir=test_folder.joinpath('__build_add_subdirectory'), variables={ 'CMAKE_PREFIX_PATH': _cmake_prefix_path(), 'BOOST_CI_INSTALL_TEST': 'OFF', 'BUILD_SHARED_LIBS': _cmake_bool(build_shared_libs) } ) runner.build_all() runner.ctest() # The library can be consumed using find_package on a Boost distro built by cmake. # Generating a modular installation requires CMake 3.13+, so this test can be disabled # for jobs running old cmake versions if install_test: runner.configure( source_dir=test_folder, binary_dir=test_folder.joinpath('__build_find_package'), variables={ 'BOOST_CI_INSTALL_TEST': 'ON', 'BUILD_SHARED_LIBS': _cmake_bool(build_shared_libs), 'CMAKE_PREFIX_PATH': _cmake_prefix_path(cmake_distro) } ) runner.build_all() runner.ctest() # Check that we bail out correctly when no OpenSSL is available def cmake_noopenssl_build( source_dir: Path, boost_branch: str, generator: str ): # Config runner = _CMakeRunner(generator=generator, build_type='Release') # Get Boost install_boost( source_dir=source_dir, boost_branch=boost_branch, ) # Build Boost and install. This won't build the library if there is no OpenSSL, # but shouldn't cause any error. runner.configure( source_dir=BOOST_ROOT, binary_dir=BOOST_ROOT.joinpath('__build'), variables={ 'BOOST_INCLUDE_LIBRARIES': 'mysql', 'BOOST_MYSQL_INTEGRATION_TESTS': 'ON', 'BUILD_TESTING': 'ON', 'CMAKE_INSTALL_MESSAGE': 'NEVER', } ) runner.build(target='tests') runner.ctest(no_tests_error=False) runner.build(target='install') # Check that disabling integration tests works def cmake_nointeg_build( source_dir: Path, boost_branch: str, generator: str ): # Config runner = _CMakeRunner(generator=generator, build_type='Release') # Get Boost install_boost( source_dir=source_dir, boost_branch=boost_branch, ) # Build the library and run the tests, as the Boost superproject does bin_dir = BOOST_ROOT.joinpath('__build') runner.configure( source_dir=BOOST_ROOT, binary_dir=bin_dir, variables={ 'CMAKE_PREFIX_PATH': _cmake_prefix_path(), 'BOOST_INCLUDE_LIBRARIES': 'mysql', 'BUILD_TESTING': 'ON' } ) runner.build(target='tests') runner.ctest() runner.build(target='install') # Check that CMake can consume a Boost distribution created by b2 def find_package_b2_test( source_dir: Path, boost_branch: str, generator: str ) -> None: # Config b2_distro = Path(os.path.expanduser('~')).joinpath('b2-distro') prefix_path = _cmake_prefix_path(b2_distro) runner = _CMakeRunner(generator=generator, build_type='Release') # Get Boost install_boost( source_dir=source_dir, boost_branch=boost_branch, ) # Generate a b2 Boost distribution run([ 'b2', '--prefix={}'.format(b2_distro), '--with-charconv', '-d0', 'install' ]) # Check that the library can be consumed using find_package on the distro above test_dir = BOOST_ROOT.joinpath('libs', 'mysql', 'test', 'cmake_b2_test') runner.configure( source_dir=test_dir, binary_dir=test_dir.joinpath('__build'), variables={ 'CMAKE_PREFIX_PATH': prefix_path, 'BUILD_TESTING': 'ON' } ) runner.build_all() runner.ctest() # Same as the above, but for separate-build mode test_dir = BOOST_ROOT.joinpath('libs', 'mysql', 'test', 'cmake_b2_separate_compilation_test') runner.configure( source_dir=test_dir, binary_dir=test_dir.joinpath('__build'), variables={ 'CMAKE_PREFIX_PATH': prefix_path, 'BUILD_TESTING': 'ON' } ) runner.build_all() runner.ctest() def bench_build( source_dir: Path, boost_branch: str, connection_pool_iters: int, protocol_iters: int, server_host: str, ) -> None: # Get Boost install_boost( source_dir=source_dir, boost_branch=boost_branch, ) # Setup DB db_setup_bench(source_dir) # Build the benchmark code runner = _CMakeRunner(generator='Ninja', build_type='Release') bin_dir = BOOST_ROOT.joinpath('__build') runner.configure( source_dir=BOOST_ROOT, binary_dir=bin_dir, variables={ 'CMAKE_PREFIX_PATH': '/opt/mysql-8.4.4', # Container's location 'BOOST_INCLUDE_LIBRARIES': 'mysql', 'BOOST_MYSQL_BENCH': 'ON', 'CMAKE_CXX_STANDARD': '23', } ) runner.build(target='boost_mysql_bench') # Run the benchmarks run_benchmarks( exe_dir=bin_dir.joinpath('stage', 'bin'), server_host=server_host, connection_pool_iters=connection_pool_iters, protocol_iters=protocol_iters, )