diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index a35c7b7..5e6bdea 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -211,6 +211,18 @@ jobs: std: 20, }, } + - { + name: "Ubuntu GCC-16 (C++26 Reflection)", + os: ubuntu-24.04, + compiler: + { + type: GCC16, + version: 16, + cc: "gcc-16", + cxx: "g++-16", + std: 26, + }, + } steps: - uses: actions/checkout@v4 - uses: lukka/get-cmake@v4.4.2 @@ -231,9 +243,15 @@ jobs: with: version: ${{ matrix.settings.compiler.version }} platform: x64 + - name: Install GCC 16 from ubuntu-toolchain-r PPA + if: matrix.settings.compiler.type == 'GCC16' + run: | + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + sudo apt-get update + sudo apt-get install -y --no-install-recommends g++-16 gcc-16 - name: Install uv uses: astral-sh/setup-uv@v5 - name: Set up Python run: uv sync - name: Run CMake - run: ./scripts/cmake.sh --${{ matrix.configuration == 'Debug' && 'debug' || 'release' }} + run: ./scripts/cmake.sh --${{ matrix.configuration == 'Debug' && 'debug' || 'release' }} ${{ matrix.settings.compiler.type == 'GCC16' && '--reflection' || '' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 459b0b1..ac8f1c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.22.4 FATAL_ERROR) +cmake_minimum_required(VERSION 3.25 FATAL_ERROR) cmake_policy(SET CMP0127 NEW) cmake_policy(SET CMP0135 NEW) cmake_policy(SET CMP0140 NEW) @@ -29,6 +29,35 @@ option(ENABLE_UBSAN "Enable Undefined Behaviour Sanitizer" OFF) option(ENABLE_TSAN "Enable Thread Sanitizer" OFF) option(ENABLE_MSAN "Enable Memory Sanitizer" OFF) +option( + XYZ_PROTOCOL_BUILD_REFLECTION + "Also build and test tutorials/reflection.cc, which requires a compiler \ +with C++26 P2996 reflection support (eg. GCC 16+ with -freflection)." + OFF) + +if(XYZ_PROTOCOL_BUILD_REFLECTION) + set(CMAKE_CXX_STANDARD 26) + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CMAKE_REQUIRED_FLAGS "-freflection") + endif() + include(CheckCXXSourceCompiles) + check_cxx_source_compiles( + " + #include + constexpr std::meta::info reflection_of_int = ^^int; + int main() {} + " + XYZ_PROTOCOL_REFLECTION_SUPPORTED) + unset(CMAKE_REQUIRED_FLAGS) + if(NOT XYZ_PROTOCOL_REFLECTION_SUPPORTED) + message( + FATAL_ERROR + "XYZ_PROTOCOL_BUILD_REFLECTION is ON but the compiler " + "(${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}) does not " + "support C++26 reflection.") + endif() +endif() + if(ENABLE_ASAN OR ENABLE_UBSAN OR ENABLE_TSAN OR ENABLE_MSAN) set(ENABLE_SANITIZERS ON) endif() diff --git a/cmake/xyz_add_test.cmake b/cmake/xyz_add_test.cmake index 00cf265..ff9f4a6 100644 --- a/cmake/xyz_add_test.cmake +++ b/cmake/xyz_add_test.cmake @@ -50,7 +50,7 @@ function(xyz_add_test) if(NOT XYZ_VERSION) set(XYZ_VERSION 20) else() - set(VALID_TARGET_VERSIONS 11 14 17 20 23) + set(VALID_TARGET_VERSIONS 11 14 17 20 23 26) list(FIND VALID_TARGET_VERSIONS ${XYZ_VERSION} index) if(index EQUAL -1) message(FATAL_ERROR "TYPE must be one of <${VALID_TARGET_VERSIONS}>") diff --git a/docker/Dockerfile b/docker/Dockerfile index 4966bbb..8debc67 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -2,7 +2,6 @@ FROM ubuntu:24.04 # Install base tools and C++ development tools. RUN apt-get update && apt-get install -y --no-install-recommends \ - cmake \ curl \ g++ \ gdb \ @@ -18,13 +17,20 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ssh \ unzip \ wget \ -&& rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* # Install newer CMake from kitware. RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null \ -&& apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ noble main' \ -&& apt-get update && apt-get install -y --no-install-recommends cmake \ -&& rm -rf /var/lib/apt/lists/* + && apt-add-repository -y 'deb https://apt.kitware.com/ubuntu/ noble main' \ + && apt-get update && apt-get install -y --no-install-recommends cmake \ + && rm -rf /var/lib/apt/lists/* + +# Install GCC 16 (experimental C++26 reflection support via -std=c++26 +# -freflection, see https://gcc.gnu.org/gcc-16/changes.html) from the Ubuntu +# Toolchain Test PPA, since Ubuntu 24.04's own repos only go up to GCC 14. +RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test \ + && apt-get update && apt-get install -y --no-install-recommends g++-16 gcc-16 \ + && rm -rf /var/lib/apt/lists/* # Install bazelisk. RUN ARCH=$(dpkg --print-architecture) && \ @@ -36,11 +42,11 @@ RUN ARCH=$(dpkg --print-architecture) && \ # https://github.com/cli/cli/blob/trunk/docs/install_linux.md (not reliably # available via Ubuntu 24.04's default repos). RUN mkdir -p -m 755 /etc/apt/keyrings \ -&& wget -nv -O /etc/apt/keyrings/githubcli-archive-keyring.gpg https://cli.github.com/packages/githubcli-archive-keyring.gpg \ -&& chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ -&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list >/dev/null \ -&& apt-get update && apt-get install -y --no-install-recommends gh \ -&& rm -rf /var/lib/apt/lists/* + && wget -nv -O /etc/apt/keyrings/githubcli-archive-keyring.gpg https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + && chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \ + && echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list >/dev/null \ + && apt-get update && apt-get install -y --no-install-recommends gh \ + && rm -rf /var/lib/apt/lists/* # Install jj (Jujutsu VCS) from its GitHub release binary. The jujutsu apt # package isn't built for Ubuntu 24.04 (noble) or Debian stable; it only diff --git a/scripts/cmake.py b/scripts/cmake.py index ecfca13..1d35436 100644 --- a/scripts/cmake.py +++ b/scripts/cmake.py @@ -2,6 +2,7 @@ """CMake helper script for building and testing the project.""" import argparse +import os import subprocess from typing import Any @@ -37,6 +38,12 @@ def main() -> None: ) parser.add_argument("--tsan", action="store_true", help="Enable Thread Sanitizer") parser.add_argument("--msan", action="store_true", help="Enable Memory Sanitizer") + parser.add_argument( + "--reflection", + action="store_true", + help="Build and test tutorials/reflection.cc (requires a P2996 " + "reflection compiler, e.g. CXX=g++-16 CC=gcc-16)", + ) parser.add_argument("-B", "--build-dir", help="Build directory") parser.add_argument( "--clean", action="store_true", help="Fresh configuration and clean-first build" @@ -74,6 +81,7 @@ def log(msg: Any) -> None: f"-DENABLE_UBSAN={'ON' if args.ubsan else 'OFF'}", f"-DENABLE_TSAN={'ON' if args.tsan else 'OFF'}", f"-DENABLE_MSAN={'ON' if args.msan else 'OFF'}", + "-DXYZ_PROTOCOL_BUILD_REFLECTION=" + ("ON" if args.reflection else "OFF"), ] if args.build_dir: configure_args.extend(["-B", args.build_dir]) @@ -82,8 +90,17 @@ def log(msg: Any) -> None: configure_args.extend(extra) + # A P2996 reflection compiler is required to configure with + # XYZ_PROTOCOL_BUILD_REFLECTION=ON. CMake only reads CXX/CC + # from the environment, not from -D cache variables, so set them here + # rather than as configure_args. + configure_env = os.environ.copy() + if args.reflection: + configure_env["CXX"] = "g++-16" + configure_env["CC"] = "gcc-16" + log(f"Running: {' '.join(configure_args)}") - subprocess.check_call(configure_args) + subprocess.check_call(configure_args, env=configure_env) # Build step (required for build, test, benchmark) build_args = ["cmake", "--build"]