diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ded3df7..482d62b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,12 @@ -name: CI +# CI script to verify that CMake and B2 builds work. +# B2 builds include only tests that don't require a DB server, to avoid race conditions. +# CMake tests include the actual project tests and all the CMake integration workflows +# recommended by Boost.CI. +# Windows CMake jobs build the code but don't run the tests, +# since we don't have a way to set up a Redis server on Windows (yet). +# Subcommands are implemented by the tools/ci.py script in a platform-independent manner. +name: CI on: [push, pull_request] @@ -14,10 +21,12 @@ jobs: fail-fast: false matrix: include: - - { toolset: msvc-14.2, os: windows-2019, generator: "Visual Studio 16 2019", cxxstd: '17', build-type: 'Debug' } - - { toolset: msvc-14.2, os: windows-2019, generator: "Visual Studio 16 2019", cxxstd: '17', build-type: 'Release' } - - { toolset: msvc-14.3, os: windows-2022, generator: "Visual Studio 17 2022", cxxstd: '20', build-type: 'Debug' } - - { toolset: msvc-14.3, os: windows-2022, generator: "Visual Studio 17 2022", cxxstd: '20', build-type: 'Release' } + - { toolset: msvc-14.2, os: windows-2019, generator: "Visual Studio 16 2019", cxxstd: '17', build-type: 'Debug', build-shared-libs: 1 } + - { toolset: msvc-14.2, os: windows-2019, generator: "Visual Studio 16 2019", cxxstd: '17', build-type: 'Release', build-shared-libs: 0 } + - { toolset: msvc-14.3, os: windows-2022, generator: "Visual Studio 17 2022", cxxstd: '20', build-type: 'Debug', build-shared-libs: 0 } + - { toolset: msvc-14.3, os: windows-2022, generator: "Visual Studio 17 2022", cxxstd: '20', build-type: 'Release', build-shared-libs: 1 } + env: + CMAKE_BUILD_PARALLEL_LEVEL: 4 steps: - name: Checkout uses: actions/checkout@v3 @@ -39,7 +48,8 @@ jobs: --build-type ${{ matrix.build-type }} \ --cxxstd ${{ matrix.cxxstd }} \ --toolset ${{ matrix.toolset }} \ - --generator "${{ matrix.generator }}" + --generator "${{ matrix.generator }}" \ + --build-shared-libs ${{ matrix.build-shared-libs }} - name: Build the project tests run: | @@ -47,7 +57,8 @@ jobs: --build-type ${{ matrix.build-type }} \ --cxxstd ${{ matrix.cxxstd }} \ --toolset ${{ matrix.toolset }} \ - --generator "${{ matrix.generator }}" + --generator "${{ matrix.generator }}" \ + --build-shared-libs ${{ matrix.build-shared-libs }} # # TODO: re-enable this when a Redis server is available for this job # - name: Run the project tests @@ -61,7 +72,8 @@ jobs: --build-type ${{ matrix.build-type }} \ --cxxstd ${{ matrix.cxxstd }} \ --toolset ${{ matrix.toolset }} \ - --generator "${{ matrix.generator }}" + --generator "${{ matrix.generator }}" \ + --build-shared-libs ${{ matrix.build-shared-libs }} - name: Run find_package tests with the built cmake distribution run: | @@ -69,7 +81,8 @@ jobs: --build-type ${{ matrix.build-type }} \ --cxxstd ${{ matrix.cxxstd }} \ --toolset ${{ matrix.toolset }} \ - --generator "${{ matrix.generator }}" + --generator "${{ matrix.generator }}" \ + --build-shared-libs ${{ matrix.build-shared-libs }} - name: Run find_package tests with the built b2 distribution run: | @@ -77,7 +90,8 @@ jobs: --build-type ${{ matrix.build-type }} \ --cxxstd ${{ matrix.cxxstd }} \ --toolset ${{ matrix.toolset }} \ - --generator "${{ matrix.generator }}" + --generator "${{ matrix.generator }}" \ + --build-shared-libs ${{ matrix.build-shared-libs }} windows-b2: name: "B2 ${{matrix.toolset}}" @@ -135,6 +149,7 @@ jobs: env: CXXFLAGS: ${{matrix.cxxflags}} -Wall -Wextra LDFLAGS: ${{matrix.ldflags}} + CMAKE_BUILD_PARALLEL_LEVEL: 4 steps: - name: Checkout uses: actions/checkout@v3 diff --git a/tools/ci.py b/tools/ci.py index 8037836c..ba3ed04e 100755 --- a/tools/ci.py +++ b/tools/ci.py @@ -1,5 +1,8 @@ #!/usr/bin/python3 +# Contains commands that are invoked by the CI scripts. +# Having this as a Python file makes it platform-independent. + from pathlib import Path from typing import List, Union import subprocess @@ -9,6 +12,7 @@ from shutil import rmtree, copytree, ignore_patterns import argparse +# Variables _is_windows = os.name == 'nt' _home = Path(os.path.expanduser('~')) _boost_root = _home.joinpath('boost-root') @@ -17,6 +21,7 @@ _cmake_distro = _home.joinpath('boost-cmake-distro') _b2_command = str(_boost_root.joinpath('b2')) +# Utilities def _run(args: List[str]) -> None: print('+ ', args, flush=True) subprocess.run(args, check=True) @@ -36,10 +41,7 @@ def _remove_readonly(func, path, _): func(path) -def _build_prefix_path(*paths: Union[str, Path]) -> str: - return ';'.join(str(p) for p in paths) - - +# Parses a string into a boolean (for command-line parsing) def _str2bool(v: Union[bool, str]) -> bool: if isinstance(v, bool): return v @@ -51,6 +53,8 @@ def _str2bool(v: Union[bool, str]) -> bool: raise argparse.ArgumentTypeError('Boolean value expected.') +# Transforms a b2-like toolset into a compiler command suitable +# to be passed to CMAKE_CXX_COMPILER def _compiler_from_toolset(toolset: str) -> str: if toolset.startswith('gcc'): return toolset.replace('gcc', 'g++') @@ -62,6 +66,8 @@ def _compiler_from_toolset(toolset: str) -> str: return toolset +# If we're on the master branch, we should use the Boost superproject master branch. +# Otherwise, use the superproject develop branch. def _deduce_boost_branch() -> str: # Are we in GitHub Actions? if os.environ.get('GITHUB_ACTIONS') is not None: @@ -181,7 +187,7 @@ def _build_cmake_standalone_tests( 'cmake', '-DBUILD_TESTING=ON', '-DCMAKE_CXX_COMPILER={}'.format(_compiler_from_toolset(toolset)), - '-DCMAKE_PREFIX_PATH={}'.format(_build_prefix_path(_b2_distro)), + '-DCMAKE_PREFIX_PATH={}'.format(_b2_distro), '-DCMAKE_BUILD_TYPE={}'.format(build_type), '-DBUILD_SHARED_LIBS={}'.format(_cmake_bool(build_shared_libs)), '-DCMAKE_CXX_STANDARD={}'.format(cxxstd), @@ -245,7 +251,7 @@ def _run_cmake_find_package_tests( '-DCMAKE_BUILD_TYPE={}'.format(build_type), '-DBUILD_SHARED_LIBS={}'.format(_cmake_bool(build_shared_libs)), '-DCMAKE_CXX_STANDARD={}'.format(cxxstd), - '-DCMAKE_PREFIX_PATH={}'.format(_build_prefix_path(_cmake_distro)), + '-DCMAKE_PREFIX_PATH={}'.format(_cmake_distro), '..' ]) _run(['cmake', '--build', '.', '--config', build_type]) @@ -267,7 +273,7 @@ def _run_cmake_b2_find_package_tests( generator, '-DCMAKE_CXX_COMPILER={}'.format(_compiler_from_toolset(toolset)), '-DBUILD_TESTING=ON', - '-DCMAKE_PREFIX_PATH={}'.format(_build_prefix_path(_b2_distro)), + '-DCMAKE_PREFIX_PATH={}'.format(_b2_distro), '-DCMAKE_BUILD_TYPE={}'.format(build_type), '-DBUILD_SHARED_LIBS={}'.format(_cmake_bool(build_shared_libs)), '-DCMAKE_CXX_STANDARD={}'.format(cxxstd), @@ -297,6 +303,7 @@ def _run_b2_tests( def main(): + # Command line parsing parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() @@ -358,10 +365,13 @@ def main(): subp.add_argument('--toolset', default='gcc') subp.set_defaults(func=_run_b2_tests) + # Actually parse the arguments args = parser.parse_args() - os.environ['CMAKE_BUILD_PARALLEL_LEVEL'] = '4' - + # Invoke the relevant function (as defined by the func default), with + # the command-line arguments the user passed us (we need to get rid + # of the func property to match function signatures) + # This approach is recommended by Python's argparse docs args.func(**{k: v for k, v in vars(args).items() if k != 'func'})