diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5eec73f..d067eb0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,85 +1,631 @@ +# +# Copyright (c) 2026 Steve Gerbino +# +# 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) +# +# Official repository: https://github.com/cppalliance/corosio/ +# + name: CI on: - push: - branches: [ "**" ] pull_request: branches: [ master, develop ] workflow_dispatch: + push: + branches: + - master + - develop + - bugfix/** + - feature/** + - fix/** + - pr/** + + +concurrency: + group: ${{format('{0}:{1}', github.repository, github.ref)}} + cancel-in-progress: true + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + DEFAULT_BUILD_VARIANT: debug,release + UBSAN_OPTIONS: "print_stacktrace=1" + DEBIAN_FRONTEND: "noninteractive" + TZ: "Europe/London" jobs: - build-and-test: - name: ${{ matrix.os }} - ${{ matrix.compiler }} - runs-on: ${{ matrix.os }} - + runner-selection: + name: Runner Selection + runs-on: ${{ github.repository_owner == 'boostorg' && fromJSON('[ "self-hosted", "linux", "x64", "ubuntu-latest-aws" ]') || 'ubuntu-latest' }} + outputs: + labelmatrix: ${{ steps.aws_hosted_runners.outputs.labelmatrix }} + steps: + - name: AWS Hosted Runners + id: aws_hosted_runners + uses: cppalliance/aws-hosted-runners@v1.0.0 + + build: + needs: [ runner-selection ] + defaults: + run: + shell: bash + strategy: fail-fast: false matrix: include: - # Linux - GCC - - os: ubuntu-24.04 - compiler: gcc - cc: gcc-14 - cxx: g++-14 - packages: g++-14 - - # Linux - Clang 18 - - os: ubuntu-24.04 - compiler: clang-18 - cc: clang-18 - cxx: clang++-18 - packages: clang-18 libc++-18-dev libc++abi-18-dev - - # Linux - Clang 20 (from LLVM repo) - - os: ubuntu-24.04 - compiler: clang-20 - cc: clang-20 - cxx: clang++-20 - install_clang_20: true - - # Windows - MSVC - - os: windows-2022 - compiler: msvc - cc: cl - cxx: cl - - # macOS - Clang - - os: macos-14 - compiler: clang - cc: clang - cxx: clang++ + # Windows (3 configurations) + + - compiler: "msvc" + version: "14.42" + cxxstd: "20" + latest-cxxstd: "20" + runs-on: "windows-2022" + b2-toolset: "msvc-14.4" + generator: "Visual Studio 17 2022" + is-latest: true + name: "MSVC 14.42: C++20" + shared: false + build-type: "Release" + build-cmake: true + + - compiler: "msvc" + version: "14.34" + cxxstd: "20" + latest-cxxstd: "20" + runs-on: "windows-2022" + b2-toolset: "msvc-14.3" + generator: "Visual Studio 17 2022" + name: "MSVC 14.34: C++20 (shared)" + shared: true + build-type: "Release" + + - compiler: "mingw" + version: "*" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "g++" + cc: "gcc" + runs-on: "windows-2022" + b2-toolset: "gcc" + generator: "MinGW Makefiles" + is-latest: true + is-earliest: true + name: "MinGW: C++20" + shared: false + build-type: "Release" + build-cmake: true + + # macOS (2 configurations) + # TODO: Re-enable when BSD/kqueue support is implemented + # + # - compiler: "apple-clang" + # version: "*" + # cxxstd: "20" + # latest-cxxstd: "20" + # cxx: "clang++" + # cc: "clang" + # runs-on: "macos-26" + # b2-toolset: "clang" + # is-latest: true + # name: "Apple-Clang (macOS 26, asan+ubsan): C++20" + # shared: true + # build-type: "RelWithDebInfo" + # asan: true + # ubsan: true + # + # - compiler: "apple-clang" + # version: "*" + # cxxstd: "20" + # latest-cxxstd: "20" + # cxx: "clang++" + # cc: "clang" + # runs-on: "macos-14" + # b2-toolset: "clang" + # name: "Apple-Clang (macOS 14): C++20" + # shared: true + # build-type: "Release" + # build-cmake: true + + # Linux GCC (4 configurations) + + - compiler: "gcc" + version: "15" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "g++-15" + cc: "gcc-15" + runs-on: "ubuntu-latest" + container: "ubuntu:25.04" + b2-toolset: "gcc" + is-latest: true + name: "GCC 15: C++20" + shared: true + build-type: "Release" + build-cmake: true + + - compiler: "gcc" + version: "15" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "g++-15" + cc: "gcc-15" + runs-on: "ubuntu-latest" + container: "ubuntu:25.04" + b2-toolset: "gcc" + is-latest: true + name: "GCC 15: C++20 (asan+ubsan)" + shared: true + asan: true + ubsan: true + build-type: "RelWithDebInfo" + + - compiler: "gcc" + version: "12" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "g++-12" + cc: "gcc-12" + runs-on: "ubuntu-latest" + container: "ubuntu:22.04" + b2-toolset: "gcc" + name: "GCC 12: C++20" + shared: true + build-type: "Release" + + - compiler: "gcc" + version: "13" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "g++-13" + cc: "gcc-13" + runs-on: "ubuntu-24.04" + b2-toolset: "gcc" + name: "GCC 13: C++20 (coverage)" + shared: false + coverage: true + build-type: "Debug" + cxxflags: "--coverage -fprofile-arcs -ftest-coverage" + ccflags: "--coverage -fprofile-arcs -ftest-coverage" + install: "lcov wget unzip" + + # Linux Clang (5 configurations) + + - compiler: "clang" + version: "20" + cxxstd: "20,23" + latest-cxxstd: "23" + cxx: "clang++-20" + cc: "clang-20" + runs-on: "ubuntu-latest" + container: "ubuntu:24.04" + b2-toolset: "clang" + is-latest: true + name: "Clang 20: C++20-23" + shared: true + build-type: "Release" + build-cmake: true + + - compiler: "clang" + version: "20" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "clang++-20" + cc: "clang-20" + runs-on: "ubuntu-latest" + container: "ubuntu:24.04" + b2-toolset: "clang" + is-latest: true + name: "Clang 20: C++20 (asan+ubsan)" + shared: false + asan: true + ubsan: true + build-type: "RelWithDebInfo" + + - compiler: "clang" + version: "17" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "clang++-17" + cc: "clang-17" + runs-on: "ubuntu-24.04" + b2-toolset: "clang" + name: "Clang 17: C++20" + shared: false + build-type: "Release" + + - compiler: "clang" + version: "14" + cxxstd: "20" + latest-cxxstd: "20" + cxx: "clang++-14" + cc: "clang-14" + runs-on: "ubuntu-latest" + container: "ubuntu:22.04" + b2-toolset: "clang" + name: "Clang 14: C++20" + shared: true + build-type: "Release" + + - compiler: "clang" + version: "20" + cxxstd: "20,23" + latest-cxxstd: "23" + cxx: "clang++-20" + cc: "clang-20" + runs-on: "ubuntu-latest" + container: "ubuntu:24.04" + b2-toolset: "clang" + is-latest: true + name: "Clang 20: C++20-23 (x86)" + shared: false + x86: true + build-type: "Release" + install: "gcc-multilib g++-multilib" + + name: ${{ matrix.name }} + runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.runs-on] }} + container: + image: ${{ matrix.container }} + options: --privileged + + timeout-minutes: 120 + + steps: + - name: Clone Boost.Corosio + uses: actions/checkout@v4 + with: + path: corosio-root + + - name: Setup C++ + uses: alandefreitas/cpp-actions/setup-cpp@v1.9.0 + id: setup-cpp + with: + compiler: ${{ matrix.compiler }} + version: ${{ matrix.version }} + check-latest: true + trace-commands: true + + - name: Install packages + uses: alandefreitas/cpp-actions/package-install@v1.9.0 + id: package-install + with: + apt-get-add-architecture: ${{ matrix.x86 && 'i386' || '' }} + apt-get: >- + ${{ matrix.install }} + build-essential + ${{ matrix.x86 && '' || '' }} + + - name: Clone Capy + uses: actions/checkout@v4 + with: + repository: cppalliance/capy + ref: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }} + path: capy-root + + - name: Clone Boost + uses: alandefreitas/cpp-actions/boost-clone@v1.9.0 + id: boost-clone + with: + branch: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }} + boost-dir: boost-source + modules-exclude-paths: '' + scan-modules-dir: corosio-root + scan-modules-ignore: corosio,capy + + - name: ASLR Fix + if: ${{ startsWith(matrix.runs-on, 'ubuntu' )}} + run: | + sysctl vm.mmap_rnd_bits=28 + + - name: Patch Boost + id: patch + shell: bash + run: | + set -xe + pwd + ls + ls -lah boost-source + + # Identify boost module being tested + module=${GITHUB_REPOSITORY#*/} + echo "module=$module" >> $GITHUB_OUTPUT + + # Identify GitHub workspace root + workspace_root=$(echo "$GITHUB_WORKSPACE" | sed 's/\\/\//g') + echo -E "workspace_root=$workspace_root" >> $GITHUB_OUTPUT + + # Remove module from boost-source + rm -r "boost-source/libs/$module" || true + rm -r "boost-source/libs/capy" || true + + # Copy cached boost-source to an isolated boost-root + cp -r boost-source boost-root + + # Set boost-root output + cd boost-root + boost_root="$(pwd)" + boost_root=$(echo "$boost_root" | sed 's/\\/\//g') + echo -E "boost_root=$boost_root" >> $GITHUB_OUTPUT + + # Patch boost-root with workspace module + cp -r "$workspace_root"/corosio-root "libs/$module" + + # Patch boost-root with capy dependency + cp -r "$workspace_root"/capy-root "libs/capy" + + - name: Boost B2 Workflow + uses: alandefreitas/cpp-actions/b2-workflow@v1.9.0 + if: ${{ !matrix.coverage }} + env: + ASAN_OPTIONS: ${{ ((matrix.compiler == 'apple-clang' || matrix.compiler == 'clang') && 'detect_invalid_pointer_pairs=0:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1') || 'detect_invalid_pointer_pairs=2:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1' }} + with: + source-dir: boost-root + modules: corosio + toolset: ${{ matrix.b2-toolset }} + build-variant: ${{ matrix.build-type }} + cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx || '' }} + cxxstd: ${{ matrix.cxxstd }} + address-model: ${{ (matrix.x86 && '32') || '64' }} + asan: ${{ matrix.asan }} + ubsan: ${{ matrix.ubsan }} + shared: ${{ matrix.shared }} + rtti: on + cxxflags: ${{ (matrix.asan && '-fsanitize-address-use-after-scope -fsanitize=pointer-subtract') || '' }} + stop-on-error: true + + - name: Boost CMake Workflow + uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.0 + if: ${{ matrix.coverage || matrix.build-cmake || matrix.is-earliest }} + with: + source-dir: boost-root + build-dir: __build_cmake_test__ + generator: ${{ matrix.generator }} + generator-toolset: ${{ matrix.generator-toolset }} + build-type: ${{ matrix.build-type }} + build-target: tests + run-tests: true + install-prefix: .local + cxxstd: ${{ matrix.latest-cxxstd }} + cc: ${{ steps.setup-cpp.outputs.cc || matrix.cc }} + ccflags: ${{ matrix.ccflags }} + cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx }} + cxxflags: ${{ matrix.cxxflags }} + shared: ${{ matrix.shared }} + cmake-version: '>=3.20' + extra-args: | + -D Boost_VERBOSE=ON + -D BOOST_INCLUDE_LIBRARIES="${{ steps.patch.outputs.module }}" + package: false + package-artifact: false + ref-source-dir: boost-root/libs/corosio + + - name: Set Path + if: startsWith(matrix.runs-on, 'windows') && matrix.shared + run: echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH + + - name: Set LD_LIBRARY_PATH + if: startsWith(matrix.runs-on, 'ubuntu') && matrix.shared + run: | + echo "LD_LIBRARY_PATH=$GITHUB_WORKSPACE/.local/lib:$LD_LIBRARY_PATH" >> "$GITHUB_ENV" + + - name: Find Package Integration Workflow + uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.0 + if: ${{ matrix.build-cmake || matrix.is-earliest }} + with: + source-dir: boost-root/libs/${{ steps.patch.outputs.module }}/test/cmake_test + build-dir: __build_cmake_install_test__ + generator: ${{ matrix.generator }} + generator-toolset: ${{ matrix.generator-toolset }} + build-type: ${{ matrix.build-type }} + cxxstd: ${{ matrix.latest-cxxstd }} + cc: ${{ steps.setup-cpp.outputs.cc || matrix.cc }} + ccflags: ${{ matrix.ccflags }} + cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx }} + cxxflags: ${{ matrix.cxxflags }} + shared: ${{ matrix.shared }} + install: false + cmake-version: '>=3.15' + extra-args: | + -D BOOST_CI_INSTALL_TEST=ON + -D CMAKE_PREFIX_PATH=${{ steps.patch.outputs.workspace_root }}/.local + ref-source-dir: boost-root/libs/corosio + trace-commands: true + + - name: Subdirectory Integration Workflow + uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.0 + if: ${{ matrix.build-cmake || matrix.is-earliest }} + with: + source-dir: boost-root/libs/${{ steps.patch.outputs.module }}/test/cmake_test + build-dir: __build_cmake_subdir_test__ + generator: ${{ matrix.generator }} + generator-toolset: ${{ matrix.generator-toolset }} + build-type: ${{ matrix.build-type }} + cxxstd: ${{ matrix.latest-cxxstd }} + cc: ${{ steps.setup-cpp.outputs.cc || matrix.cc }} + ccflags: ${{ matrix.ccflags }} + cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx }} + cxxflags: ${{ matrix.cxxflags }} + shared: ${{ matrix.shared }} + install: false + cmake-version: '>=3.15' + extra-args: -D BOOST_CI_INSTALL_TEST=OFF + ref-source-dir: boost-root/libs/corosio/test/cmake_test + + - name: Root Project CMake Workflow + uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.0 + if: ${{ matrix.build-cmake || matrix.is-earliest }} + with: + source-dir: boost-root/libs/${{ steps.patch.outputs.module }} + build-dir: __build_root_test__ + build-target: tests + run-tests: true + generator: ${{ matrix.generator }} + generator-toolset: ${{ matrix.generator-toolset }} + build-type: ${{ matrix.build-type }} + install: false + cxxstd: ${{ matrix.latest-cxxstd }} + cc: ${{ steps.setup-cpp.outputs.cc || matrix.cc }} + ccflags: ${{ matrix.ccflags }} + cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx }} + cxxflags: ${{ matrix.cxxflags }} + shared: ${{ matrix.shared }} + cmake-version: '>=3.20' + package: false + package-artifact: false + ref-source-dir: boost-root + + - name: Codecov + if: ${{ matrix.coverage }} + run: | + set -x + + # Generate report + gcov_tool="gcov" + if command -v "gcov-${{ steps.setup-cpp.outputs.version-major }}.${{ steps.setup-cpp.outputs.version-minor }}" &> /dev/null; then + gcov_tool="gcov" + elif command -v "gcov-${{ steps.setup-cpp.outputs.version-major }}" &> /dev/null; then + gcov_tool="gcov-${{ steps.setup-cpp.outputs.version-major }}" + fi + lcov -c -q -o "boost-root/__build_cmake_test__/coverage.info" -d "boost-root/__build_cmake_test__" --include "$(pwd)/boost-root/libs/${{steps.patch.outputs.module}}/*" --gcov-tool "$gcov_tool" + + # Upload to codecov + bash <(curl -s https://codecov.io/bash) -f "boost-root/__build_cmake_test__/coverage.info" + + # Summary + echo "# Coverage" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "[![codecov](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA/graphs/sunburst.svg)](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Commit: [![codecov](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA/graph/badge.svg)](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Branch: [![codecov](https://codecov.io/github/$GITHUB_REPOSITORY/branch/$GITHUB_REF_NAME/graph/badge.svg)](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + changelog: + needs: [ runner-selection ] + defaults: + run: + shell: bash + + name: Changelog Summary + runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['ubuntu-22.04'] }} + timeout-minutes: 120 steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Clang 20 from LLVM repo (Linux) - if: runner.os == 'Linux' && matrix.install_clang_20 - run: | - wget https://apt.llvm.org/llvm.sh - chmod +x llvm.sh - sudo ./llvm.sh 20 - sudo apt-get install -y libc++-20-dev libc++abi-20-dev - - - name: Install dependencies (Linux) - if: runner.os == 'Linux' && !matrix.install_clang_20 - run: | - sudo apt-get update - sudo apt-get install -y ${{ matrix.packages }} - - - name: Set up MSVC (Windows) - if: runner.os == 'Windows' - uses: ilammy/msvc-dev-cmd@v1 - - - name: Configure CMake - env: - CC: ${{ matrix.cc }} - CXX: ${{ matrix.cxx }} - run: | - cmake -B build -DCMAKE_BUILD_TYPE=Release - - - name: Build - run: cmake --build build --config Release - - - name: Run tests - run: ctest --test-dir build --build-config Release --output-on-failure --verbose + - name: Clone Boost.Corosio + uses: actions/checkout@v4 + with: + # Avoid the common API rate limit exceeded error in boostorg by including 100 latest commits in any case + fetch-depth: 100 + + - name: Changelog + uses: alandefreitas/cpp-actions/create-changelog@v1.9.0 + with: + thank-non-regular: ${{ startsWith(github.ref, 'refs/tags/') }} + github-token: ${{ secrets.GITHUB_TOKEN }} + limit: 200 + tag-pattern: 'boost-.*\..*\..*' + + antora: + needs: [ runner-selection ] + name: Antora Docs + runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['ubuntu-latest'] }} + defaults: + run: + shell: bash + steps: + - name: Install packages + uses: alandefreitas/cpp-actions/package-install@v1.9.0 + with: + apt-get: git cmake + + - name: Clone Boost.Corosio + uses: actions/checkout@v4 + with: + path: corosio-root + + - name: Clone Capy + uses: actions/checkout@v4 + with: + repository: cppalliance/capy + ref: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }} + path: capy-root + + - name: Clone Boost + uses: alandefreitas/cpp-actions/boost-clone@v1.9.0 + id: boost-clone + with: + branch: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }} + boost-dir: boost-source + modules-exclude-paths: '' + scan-modules-dir: corosio-root + scan-modules-ignore: corosio,capy + + - name: Patch Boost + id: patch + shell: bash + run: | + set -xe + pwd + ls + ls -lah boost-source + + # Identify boost module being tested + module=${GITHUB_REPOSITORY#*/} + echo "module=$module" >> $GITHUB_OUTPUT + + # Identify GitHub workspace root + workspace_root=$(echo "$GITHUB_WORKSPACE" | sed 's/\\/\//g') + echo -E "workspace_root=$workspace_root" >> $GITHUB_OUTPUT + + # Remove module from boost-source + rm -r "boost-source/libs/$module" || true + rm -r "boost-source/libs/capy" || true + + # Copy cached boost-source to an isolated boost-root + cp -r boost-source boost-root + + # Set boost-root output + cd boost-root + boost_root="$(pwd)" + boost_root=$(echo "$boost_root" | sed 's/\\/\//g') + echo -E "boost_root=$boost_root" >> $GITHUB_OUTPUT + + # Patch boost-root with workspace module + cp -r "$workspace_root"/corosio-root "libs/$module" + + # Patch boost-root with capy dependency + cp -r "$workspace_root"/capy-root "libs/capy" + + - uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Build Antora Docs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config --global --add safe.directory "$(pwd)" + + BOOST_SRC_DIR="$(pwd)/boost-root" + export BOOST_SRC_DIR + cd boost-root/libs/corosio + + cd doc + bash ./build_antora.sh + + # Antora returns zero even if it fails, so we check if the site directory exists + if [ ! -d "build/site" ]; then + echo "Antora build failed" + exit 1 + fi + + - name: Create Antora Docs Artifact + uses: actions/upload-artifact@v4 + with: + name: antora-docs + path: boost-root/libs/corosio/doc/build/site diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f0452b..391a240 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,6 +132,9 @@ file(GLOB_RECURSE BOOST_COROSIO_HEADERS CONFIGURE_DEPENDS file(GLOB_RECURSE BOOST_COROSIO_SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp") +# Exclude wolfssl files from main library (they are added separately when WolfSSL is found) +list(FILTER BOOST_COROSIO_HEADERS EXCLUDE REGEX ".*/wolfssl/.*") +list(FILTER BOOST_COROSIO_SOURCES EXCLUDE REGEX ".*/wolfssl/.*") source_group("" FILES "include/boost/corosio.hpp") source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include/boost/corosio" PREFIX "include" FILES ${BOOST_COROSIO_HEADERS}) @@ -147,6 +150,7 @@ function(boost_corosio_setup_properties target) $<$:ws2_32>) target_compile_definitions(${target} PUBLIC BOOST_COROSIO_NO_LIB) target_compile_definitions(${target} PRIVATE BOOST_COROSIO_SOURCE) + target_compile_definitions(${target} PRIVATE $<$:_WIN32_WINNT=0x0602>) if (BUILD_SHARED_LIBS) target_compile_definitions(${target} PUBLIC BOOST_COROSIO_DYN_LINK) else () @@ -157,6 +161,21 @@ function(boost_corosio_setup_properties target) $<$:-fcoroutines>) endfunction() +#------------------------------------------------- +# +# MrDocs Build (minimal for documentation) +# +#------------------------------------------------- +if (BOOST_COROSIO_MRDOCS_BUILD) + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/mrdocs.cpp" + "#include \n") + add_library(boost_corosio_mrdocs "${CMAKE_CURRENT_BINARY_DIR}/mrdocs.cpp") + boost_corosio_setup_properties(boost_corosio_mrdocs) + target_compile_definitions(boost_corosio_mrdocs PUBLIC BOOST_COROSIO_MRDOCS) + set_target_properties(boost_corosio_mrdocs PROPERTIES EXPORT_COMPILE_COMMANDS ON) + return() +endif() + add_library(boost_corosio ${BOOST_COROSIO_HEADERS} ${BOOST_COROSIO_SOURCES}) add_library(Boost::corosio ALIAS boost_corosio) boost_corosio_setup_properties(boost_corosio) diff --git a/build/Jamfile b/build/Jamfile index 4396f7d..e35d514 100644 --- a/build/Jamfile +++ b/build/Jamfile @@ -12,7 +12,7 @@ import config : requires ; constant c20-requires : [ requires - cxx20_constexpr + cxx20_hdr_concepts ] ; @@ -31,7 +31,15 @@ project boost/corosio : source-location $(COROSIO_ROOT) ; -alias corosio_sources : [ glob-tree-ex $(COROSIO_ROOT)/src/src : *.cpp ] ; +local COROSIO_SRC = + [ glob $(COROSIO_ROOT)/src/*.cpp ] + [ glob $(COROSIO_ROOT)/src/detail/*.cpp ] + ; + +alias corosio_sources : $(COROSIO_SRC) ; + +# System libraries +lib ws2_32 ; lib boost_corosio : corosio_sources @@ -40,6 +48,7 @@ lib boost_corosio /boost/url//boost_url /boost/system//boost_system windows:ws2_32 + windows:_WIN32_WINNT=0x0602 $(COROSIO_ROOT)/include $(COROSIO_ROOT)/src : usage-requirements diff --git a/include/boost/corosio/acceptor.hpp b/include/boost/corosio/acceptor.hpp index a6cb28a..aec9e65 100644 --- a/include/boost/corosio/acceptor.hpp +++ b/include/boost/corosio/acceptor.hpp @@ -61,7 +61,7 @@ namespace corosio { } @endcode */ -class acceptor : public io_object +class BOOST_COROSIO_DECL acceptor : public io_object { struct accept_awaitable { @@ -123,14 +123,12 @@ class acceptor : public io_object Closes the acceptor if open, cancelling any pending operations. */ - BOOST_COROSIO_DECL ~acceptor(); /** Construct an acceptor from an execution context. @param ctx The execution context that will own this acceptor. */ - BOOST_COROSIO_DECL explicit acceptor(capy::execution_context& ctx); /** Construct an acceptor from an executor. @@ -202,7 +200,6 @@ class acceptor : public io_object @throws std::system_error on failure. */ - BOOST_COROSIO_DECL void listen(endpoint ep, int backlog = 128); /** Close the acceptor. @@ -210,7 +207,6 @@ class acceptor : public io_object Releases acceptor resources. Any pending operations complete with `errc::operation_canceled`. */ - BOOST_COROSIO_DECL void close(); /** Check if the acceptor is listening. @@ -264,7 +260,6 @@ class acceptor : public io_object All outstanding operations complete with `errc::operation_canceled`. */ - BOOST_COROSIO_DECL void cancel(); struct acceptor_impl : io_object_impl diff --git a/include/boost/corosio/io_context.hpp b/include/boost/corosio/io_context.hpp index 3c42e10..cd6cb05 100644 --- a/include/boost/corosio/io_context.hpp +++ b/include/boost/corosio/io_context.hpp @@ -48,7 +48,7 @@ namespace corosio { ioc.run(); // Process all queued work @endcode */ -class io_context : public capy::execution_context +class BOOST_COROSIO_DECL io_context : public capy::execution_context { public: class executor_type; @@ -59,7 +59,6 @@ class io_context : public capy::execution_context available on the system. If more than one thread is available, thread-safe synchronization is used. */ - BOOST_COROSIO_DECL io_context(); /** Construct an io_context with a concurrency hint. @@ -68,7 +67,6 @@ class io_context : public capy::execution_context will call `run()`. If greater than 1, thread-safe synchronization is used internally. */ - BOOST_COROSIO_DECL explicit io_context(unsigned concurrency_hint); diff --git a/include/boost/corosio/io_object.hpp b/include/boost/corosio/io_object.hpp index d18bccd..df380ce 100644 --- a/include/boost/corosio/io_object.hpp +++ b/include/boost/corosio/io_object.hpp @@ -31,7 +31,7 @@ namespace corosio { The implementation pointer is accessible to derived classes through the protected member `impl_`. */ -class io_object +class BOOST_COROSIO_DECL io_object { public: struct io_object_impl diff --git a/include/boost/corosio/io_stream.hpp b/include/boost/corosio/io_stream.hpp index 22786ce..6293828 100644 --- a/include/boost/corosio/io_stream.hpp +++ b/include/boost/corosio/io_stream.hpp @@ -24,7 +24,7 @@ namespace boost { namespace corosio { -class io_stream : public io_object +class BOOST_COROSIO_DECL io_stream : public io_object { public: /** Initiate an asynchronous read operation. diff --git a/include/boost/corosio/resolver.hpp b/include/boost/corosio/resolver.hpp index 750cf15..2b67e18 100644 --- a/include/boost/corosio/resolver.hpp +++ b/include/boost/corosio/resolver.hpp @@ -136,7 +136,7 @@ operator&=(resolve_flags& a, resolve_flags b) noexcept auto results = (co_await r.resolve("www.example.com", "https")).value(); @endcode */ -class resolver : public io_object +class BOOST_COROSIO_DECL resolver : public io_object { struct resolve_awaitable { @@ -198,14 +198,12 @@ class resolver : public io_object Cancels any pending operations. */ - BOOST_COROSIO_DECL ~resolver(); /** Construct a resolver from an execution context. @param ctx The execution context that will own this resolver. */ - BOOST_COROSIO_DECL explicit resolver(capy::execution_context& ctx); /** Construct a resolver from an executor. @@ -313,7 +311,6 @@ class resolver : public io_object All outstanding operations complete with `errc::operation_canceled`. */ - BOOST_COROSIO_DECL void cancel(); public: diff --git a/include/boost/corosio/socket.hpp b/include/boost/corosio/socket.hpp index 9db61e9..7600c62 100644 --- a/include/boost/corosio/socket.hpp +++ b/include/boost/corosio/socket.hpp @@ -70,7 +70,7 @@ namespace corosio { auto bytes = (co_await s.read_some(buf)).value(); @endcode */ -class socket : public io_stream +class BOOST_COROSIO_DECL socket : public io_stream { public: struct socket_impl : io_stream_impl @@ -134,14 +134,12 @@ class socket : public io_stream Closes the socket if open, cancelling any pending operations. */ - BOOST_COROSIO_DECL ~socket(); /** Construct a socket from an execution context. @param ctx The execution context that will own this socket. */ - BOOST_COROSIO_DECL explicit socket(capy::execution_context& ctx); /** Construct a socket from an executor. @@ -207,7 +205,6 @@ class socket : public io_stream @throws std::system_error on failure. */ - BOOST_COROSIO_DECL void open(); /** Close the socket. @@ -215,7 +212,6 @@ class socket : public io_stream Releases socket resources. Any pending operations complete with `errc::operation_canceled`. */ - BOOST_COROSIO_DECL void close(); /** Check if the socket is open. @@ -270,7 +266,6 @@ class socket : public io_stream All outstanding operations complete with `errc::operation_canceled`. */ - BOOST_COROSIO_DECL void cancel(); private: diff --git a/include/boost/corosio/wolfssl_stream.hpp b/include/boost/corosio/wolfssl_stream.hpp index 099a516..05db62d 100644 --- a/include/boost/corosio/wolfssl_stream.hpp +++ b/include/boost/corosio/wolfssl_stream.hpp @@ -41,7 +41,7 @@ namespace corosio { // Use secure stream for TLS communication @endcode */ -class wolfssl_stream : public io_stream +class BOOST_COROSIO_DECL wolfssl_stream : public io_stream { struct handshake_awaitable { @@ -109,7 +109,6 @@ class wolfssl_stream : public io_stream @param stream Reference to the underlying stream to wrap. */ - BOOST_COROSIO_DECL explicit wolfssl_stream(io_stream& stream); @@ -161,7 +160,7 @@ class wolfssl_stream : public io_stream }; private: - BOOST_COROSIO_DECL void construct(); + void construct(); wolfssl_stream_impl& get() const noexcept { diff --git a/src/detail/posix_scheduler.cpp b/src/detail/posix_scheduler.cpp index fc293e2..652caf9 100644 --- a/src/detail/posix_scheduler.cpp +++ b/src/detail/posix_scheduler.cpp @@ -134,7 +134,7 @@ void posix_scheduler:: post(capy::any_coro h) const { - struct post_handler + struct post_handler final : capy::execution_context::handler { capy::any_coro h_; @@ -145,6 +145,8 @@ post(capy::any_coro h) const { } + ~post_handler() = default; + void operator()() override { auto h = h_; @@ -387,8 +389,10 @@ posix_scheduler:: wakeup() const { // Write to eventfd to wake up epoll_wait + // Return value intentionally ignored - eventfd write cannot fail + // when buffer has space (counter won't overflow with uint64_t max) std::uint64_t val = 1; - ::write(event_fd_, &val, sizeof(val)); + [[maybe_unused]] auto r = ::write(event_fd_, &val, sizeof(val)); } // RAII guard - work_finished called even if handler throws @@ -453,8 +457,9 @@ do_one(long timeout_us) if (events[i].data.ptr == nullptr) { // eventfd wakeup - drain it + // Return value intentionally ignored - we just need to consume the event std::uint64_t val; - ::read(event_fd_, &val, sizeof(val)); + [[maybe_unused]] auto r = ::read(event_fd_, &val, sizeof(val)); continue; } diff --git a/src/detail/win_iocp_resolver_service.cpp b/src/detail/win_iocp_resolver_service.cpp index 9752c30..217bab6 100644 --- a/src/detail/win_iocp_resolver_service.cpp +++ b/src/detail/win_iocp_resolver_service.cpp @@ -16,6 +16,13 @@ #include #include +// MinGW may not have GetAddrInfoExCancel declared +#if defined(__MINGW32__) || defined(__MINGW64__) +extern "C" { +INT WSAAPI GetAddrInfoExCancel(LPHANDLE lpHandle); +} +#endif + namespace boost { namespace corosio { namespace detail { diff --git a/src/detail/win_iocp_scheduler.cpp b/src/detail/win_iocp_scheduler.cpp index bccd1db..0d265db 100644 --- a/src/detail/win_iocp_scheduler.cpp +++ b/src/detail/win_iocp_scheduler.cpp @@ -168,7 +168,7 @@ void win_iocp_scheduler:: post(capy::any_coro h) const { - struct post_handler + struct post_handler final : capy::execution_context::handler { capy::any_coro h_; @@ -180,6 +180,8 @@ post(capy::any_coro h) const { } + ~post_handler() = default; + void operator()() override { auto h = h_; diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..899f58e --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,10 @@ +# +# Copyright (c) 2026 Steve Gerbino +# +# 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) +# +# Official repository: https://github.com/cppalliance/corosio +# + +build-project unit ; diff --git a/test/cmake_test/CMakeLists.txt b/test/cmake_test/CMakeLists.txt new file mode 100644 index 0000000..39aa3ed --- /dev/null +++ b/test/cmake_test/CMakeLists.txt @@ -0,0 +1,57 @@ +# +# Copyright (c) 2026 Steve Gerbino +# +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt +# + +cmake_minimum_required(VERSION 3.16...3.28) + +project(cmake_subdir_test LANGUAGES CXX) +set(__ignore__ ${CMAKE_C_COMPILER}) +set(__ignore__ ${CMAKE_C_FLAGS}) + +if(BOOST_CI_INSTALL_TEST) + find_package(Boost CONFIG REQUIRED COMPONENTS corosio) +else() + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + + set(deps + # Low-level dependencies (order matters - these must come first) + assert + config + core + mp11 + predef + static_assert + throw_exception + type_traits + winapi + + # Mid-level dependencies + align + compat + optional + variant2 + + # Primary dependencies (corosio) + system + url + capy + ) + + foreach(dep IN LISTS deps) + add_subdirectory(../../../${dep} boostorg/${dep} EXCLUDE_FROM_ALL) + endforeach() + + # Add corosio last, after all its dependencies + add_subdirectory(../.. boostorg/corosio) +endif() + +add_executable(main main.cpp) +target_link_libraries(main Boost::corosio) +target_compile_features(main PRIVATE cxx_std_20) + +enable_testing() +add_test(NAME main COMMAND main) +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $) diff --git a/test/cmake_test/main.cpp b/test/cmake_test/main.cpp new file mode 100644 index 0000000..62d25cf --- /dev/null +++ b/test/cmake_test/main.cpp @@ -0,0 +1,13 @@ +// +// Copyright (c) 2026 Steve Gerbino +// +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt +// + +#include + +int main() +{ + return 0; +} diff --git a/test/unit/Jamfile b/test/unit/Jamfile index 7e19a58..54b494c 100644 --- a/test/unit/Jamfile +++ b/test/unit/Jamfile @@ -12,10 +12,18 @@ import testing ; project boost/corosio/test/unit : requirements /boost/corosio//boost_corosio - /boost/url//boost_url_extra_test_suite + ../../../url/extra/test_suite/test_main.cpp + ../../../url/extra/test_suite/test_suite.cpp + ../../../url/extra/test_suite + . + ../.. gcc:-fcoroutines ; +run acceptor.cpp ; +run consuming_buffers.cpp ; +run io_context.cpp ; run io_result.cpp ; -run platform_reactor.cpp ; +run read.cpp ; run socket.cpp ; +run write.cpp ;