ci: restructure the build matrix around the supported compiler range - #19
Merged
Conversation
The macOS GCC jobs have been failing since the macos-latest label moved to macOS 26: the SDK defines xnu_static_assert_struct_size only for Clang, so Homebrew GCC leaves the macro unexpanded and the build stops inside mach/message.h. Raising the GCC version does not help, as the same failure is reported for 15. That failure exposed a wider mismatch between what the documentation promises and what CI verifies. MSVC 2022+ was declared without a single Windows job, macOS was verified without being declared, and the three places stating the requirements disagreed with each other (README said Clang 17+, contributing.rst said Clang 16+). Rework the matrix so that it verifies the declared range and nothing else: - Pin every required job to a specific runner image and take compilers from the image only. ubuntu-24.04 provides GCC 13 and Clang 17 (the lower bound), ubuntu-26.04 provides GCC 15 and Clang 22 (the newest we verify). This drops the ppa:ubuntu-toolchain-r/test and apt.llvm.org dependencies, including the jammy-pinned list that was being added to a noble runner. - Replace macos-14/macos-15 with macos-15/macos-26. macOS 14 is scheduled for removal in November, and Apple Clang tracks the OS image, so varying the OS already varies the compiler. - Drop the macOS Homebrew GCC jobs. That combination was never declared as supported, and the breakage originates in the SDK rather than in this project. - Stop forcing -stdlib=libc++ on Linux Clang. Most Clang users on Linux build against the default standard library; libc++ moves to the nightly watch. - Pin the static library and installation jobs to specific images instead of the floating labels. Add a nightly watch for what the required gates deliberately exclude: the newest GCC and Clang from external repositories, libc++, and the floating runner labels. Breaking there is the signal we want ahead of users hitting it, so those jobs never gate a pull request. Restate the requirements as a verified range plus best effort, with the README as the single source. An open-ended "GCC 13+" cannot be verified by a finite matrix, and GCC 16 is deliberately left to the nightly watch. Remove MSVC and Windows from the declared support so the promise matches what is exercised.
Follow-up to the matrix rework, addressing three gaps found while reviewing it. The requirements listed compilers and operating systems on separate axes, which read as if macOS with GCC were supported. It is not: the required gates cover Linux with GCC or Clang, and macOS with the Apple Clang from the OS image. State the combinations per platform instead of listing them in parallel. The nightly jobs pinned GCC 16 and derived the Clang version by scanning /usr/lib for llvm-*, which also matches the versions the runner image ships and would silently pick one of those. Query apt after adding each repository instead, so both jobs install the newest version that repository offers and keep tracking upstream without edits. An empty result now fails the step rather than invoking a command with no version suffix. Matrix entries are objects, so the generated job names embedded the whole object. Name the jobs explicitly, and report cmake and pkg-config versions in the installation jobs now that the package installation steps are gone.
The comments claimed the resolved version comes from the repository just added, but the query looks at every configured source. State what the step does, and record that tracking the stable release rather than trunk is a choice: the watch exists to catch what users will hit, not what is still in development.
Clang 17 cannot compile the C++23 std::expected declarations in path.h against libstdc++. It only ever worked because the previous configuration forced libc++, so the lower bound was never verified against the standard library most Clang users on Linux get by default. Try 18, the next version the ubuntu-24.04 image ships, to find the oldest Clang that builds with either standard library.
GCC 13 builds fine, so libstdc++ 13 does provide std::expected; Clang just cannot consume that release's <expected> in C++23 mode. The 14 series fixed the interoperability, and ubuntu-24.04 ships it, so install those headers for the Clang jobs and let Clang pick them up.
Installing the libstdc++ 14 headers changed nothing: Clang 18 on ubuntu-24.04 still cannot see std::expected. Whichever way the exact cause falls, a consumer building on that image would hit the same wall and would have to work around it, so there is no Clang lower bound worth declaring there. Try Clang 20, the oldest the ubuntu-26.04 image ships, to find the oldest one that builds against the default standard library without help.
Clang 20 builds against the default standard library on ubuntu-26.04, so that is the oldest Clang worth declaring. Record the range in the three places that state the requirements, and explain in the getting started guide why the Clang bound sits higher than the GCC one — otherwise the asymmetry looks arbitrary. Move the libc++ watch onto the same image and compiler as the new lower bound, so the nightly run covers the standard library the required gates do not, rather than a version the project no longer claims to support.
The comment still claimed ubuntu-24.04 covers the lower bound, which stopped being true for Clang. Spell out the asymmetry instead — it is exactly the place a reader would look to understand why the two compilers start on different images.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The macOS GCC jobs have been failing since the
macos-latestlabel moved to macOS 26. The SDK definesxnu_static_assert_struct_sizeonly for Clang, so Homebrew GCC leaves the macro unexpanded and the build stops insidemach/message.h. Raising the GCC version does not help — the same failure is reported for 15, and the root cause sits in the SDK rather than in the compiler.Looking into it surfaced a wider mismatch between what the documentation promises and what CI verifies:
MSVC 2022+was declared without a single Windows jobcontributing.rstsaid Clang 16+apt.llvm.orglist was being added to a noble runnermacos-14is scheduled for removal in November, so the Clang matrix was already a generation staleWhat the verification found
Removing the
-stdlib=libc++override exposed something the declared range had been hiding:Clang on ubuntu-24.04 cannot compile the C++23
std::expecteddeclarations inplatform/path.hagainst the libstdc++ it is paired with, and installing newer libstdc++ headers alongside does not change that. GCC 13 builds fine on the same image, so libstdc++ 13 does providestd::expected— the failure is in how Clang consumes it.The old configuration only ever worked because it forced libc++, which meant the declared Clang lower bound had never been verified against the standard library most Linux users get by default. So the lower bound moves to Clang 20, the oldest release that builds with either standard library without help.
What changed
Required gates pin every runner image and take compilers from the image only:
ubuntu-24.04/ 13ubuntu-26.04/ 15ubuntu-26.04/ 20ubuntu-26.04/ 22macos-15macos-26The bounds deliberately do not line up across compilers — that asymmetry is what the table above measured, and
getting-started.rstexplains it so it does not read as arbitrary.This removes the
ppa:ubuntu-toolchain-r/testandapt.llvm.orgdependencies from the required path, so an upstream repository change can no longer break a merge. Allapt-get install/brew installsteps are gone as well —cmakeandpkg-configship with the runner images, and the installation jobs now report their versions so a missing tool surfaces immediately.Other changes to the required gates:
A nightly watch (
nightly.yml) covers what the required gates deliberately exclude: the newest GCC and Clang from external repositories, libc++, and the floating runner labels. Both version lookups resolve dynamically from apt, so they keep tracking upstream without edits. Breaking there is the signal we want ahead of users hitting it, so these jobs never gate a pull request and should not be added to required status checks.The requirements are restated as a verified range plus best effort, with the README as the single source:
An open-ended
GCC 13+cannot be verified by a finite matrix, so the old wording promised more than CI ever checked. MSVC and Windows are removed from the declared support for the same reason. The combinations are now stated per platform rather than as parallel lists, since listing compilers and operating systems on separate axes read as if macOS with GCC were supported.Effect on check count
Build checks go from 20 to 16: the four macOS GCC jobs are gone, and the rest is unchanged in count (contract verification 12, packaging 4).
Notes
-Werroris currentlyPUBLICinsrc/CMakeLists.txt, so it propagates to consumers usingfind_packageorFetchContent. Every time the newest verified compiler moves up, a newly added warning can break both this project and downstream builds. Worth addressing separately.docs/sphinx/source/api/platform.rststill describe Windows behaviour. Those are descriptions of implementation branches rather than support declarations, so they are left as they are, but the asymmetry is worth knowing about.mainhas no branch protection configured today. If required status checks are added later, they will need to match the new job names.