Skip to content

Modernization Phase 1.2: LLVM 22 compilers + CI image modernization [iosbuild] - #23

Merged
ptesavol merged 22 commits into
mainfrom
modernize/1.2-compilers
Jul 2, 2026
Merged

ptesavol merged 22 commits into
mainfrom
modernize/1.2-compilers

Conversation

@ptesavol

@ptesavol ptesavol commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Phase 1.2 of the modernization: the compiler upgrade, with the CI image modernization you requested folded in. Note: this branch includes PR #22's commit (TS-test disable) — merge #22 first and this PR's diff shrinks to its own changes.

Compiler changes

  • macOS: dead llvm@17 → latest keg-only Homebrew llvm (22.1.8). The build finds it via LLVM_PREFIX (exported by install-prerequisities.sh, fallback $HOMEBREW_PREFIX/opt/llvm); all hardcoded /opt/homebrew/{include/c++/v1,lib/c++} paths in the toolchain file and osx/ios triplets are parameterized.
  • Linux: gcc-14 → clang-22 + libc++ from llvm-toolchain-noble-22. libc++ everywhere = one standard library across macOS/iOS/Android/Linux (single C++26 feature matrix, single modules implementation for Part 2). New arm64-linux overlay triplet gives the self-hosted runner the same compiler/stdlib as x64 (it previously fell back to vcpkg defaults).
  • Lint stack follows the compiler — this was forced, not optional: clangd 18 cannot parse libc++ 22 headers (unknown __builtin_clzg etc.), so clangd → 22 on both platforms; clang-format → 22 as well (macOS lost its old force-linked copy with the keg-only switch, and format versions must not diverge across platforms). Mechanical reformat of 20 files. clang-tidy checks added/extended after v18 are suppressed with a note in .clang-tidy (root + the two shadowing test configs) for triage in the lint-modernization phase.
  • fmt overlay port (11.2.0 + one-line cstdlib patch), temporary until Phase 1.3: the pinned fmt 11.0.2 doesn't compile under clang 22/C++26; fmt 12 is incompatible with the pinned folly 2024.08 (removed core.h shim). Disappears with the Phase 1.3 vcpkg baseline bump.
  • iOS: the arm64-ios triplet now presets folly's try_run results (same mechanism the android triplet always had — the iOS triplet had rotted independently of the compiler question).

CI modernization (as requested)

  • validate.yml matrix: [macos-latest, ubuntu-latest, linux-arm64-runner] — macos-13/14 removed. Note: the 26.x runner images are still preview, so -latest = macos-15 / ubuntu-24.04 today and tracks GA automatically.
  • validateios.yml / validateandroid.yml → macos-latest.
  • Cache keys salted (v1→v2): caches built with the old compilers must not feed clang-22 links.

Verification done locally (Apple Silicon, Xcode 26.6)

Gate Result
Full build, all vcpkg deps + 8 packages + root (clang 22, libc++ 22) ✅
Test suite ✅ 307/307
Full lint (clangd 22 + clang-format 22) ✅
iOS cross-build (all arm64-ios deps incl. folly, XCFramework produced) ✅
XCFramework binary: platform=iOS, minos=13.0, 0 refs to __cxa_init_primary_exception (nothing newer than the deployment-target runtime) ✅
iOS device test (iostest.sh) ⬅️ needs you + a device — please run and report

The commit message contains iosbuild, so the iOS CI workflow will run on this PR too.

Known follow-ups (tracked in the plan)

  • Phase 1.3 removes the fmt overlay via the real baseline bump.
  • Phase 1.4 revisits the iOS libc++ arrangement properly (SDK headers instead of the availability-macro define) + deployment target decision.
  • Install-flow lesson recorded: switching target triplets in the same build dirs silently mixes platforms unless cleaned — the Part 2 install rework will give each target its own build dir.

🤖 Generated with Claude Code

ptesavol and others added 5 commits July 2, 2026 09:50
ts-integration-test, ts-end-to-end-test and ts-multiple-messages-test
are disabled with a note: their install step builds the entire
streamr-dev/network TS monorepo at a 2024 commit, which no longer works
on current CI runners — and compiling the whole repository is not
necessary anymore. They will be revisited against a current, slimmer TS
setup after the toolchain/modules modernization completes.

These were the only failing tests on the Linux CI legs, so validate.yml
Linux legs are expected to go fully green with this change.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- macOS: Homebrew llvm@17 (dead against current Xcode SDKs — its baked-in
  DEFAULT_SYSROOT points at the removed MacOSX14.sdk) is replaced by the
  latest keg-only llvm formula (22.x). The build now locates the
  toolchain through the LLVM_PREFIX environment variable exported by
  install-prerequisities.sh, with a ${HOMEBREW_PREFIX}/opt/llvm fallback;
  the previously hardcoded /opt/homebrew/{include/c++/v1,lib/c++} paths
  in the toolchain file and the osx/ios overlay triplets are
  parameterized on LLVM_PREFIX.
- Linux: gcc-14 is replaced by clang-22 + libc++ from apt.llvm.org
  (llvm-toolchain-noble-22). libc++ keeps the standard library uniform
  across macOS/iOS/Android/Linux — one C++26 feature matrix and a single
  C++ modules implementation. The x64-linux overlay triplet builds vcpkg
  deps with the same compiler/stdlib, and a new arm64-linux overlay
  gives the self-hosted arm64 runner the same treatment (it previously
  fell back to vcpkg defaults).
- clang-format/clangd remain at 18 (lint toolchain is upgraded in a
  later phase, to keep lint churn out of this one).
- CI modernization: validate.yml matrix drops macos-13/macos-14 in
  favor of macos-latest, ubuntu-24.04 becomes ubuntu-latest;
  validateios.yml/validateandroid.yml runners become macos-latest.
  Cache keys are salted (v1->v2) because caches built with the old
  compilers must not be reused.
- arm64-ios.cmake also normalized from CRLF to LF line endings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The baseline-pinned fmt 11.0.2 no longer compiles under clang 22 with
-std=gnu++26 (consteval/constant-expression failure in FMT_STRING).
fmt 12.x is out because folly 2024.08 still relies on the
fmt/core.h -> fmt/format.h shim that fmt 12 removed. fmt 11.2.0 works,
with one small patch: it defines _LIBCPP_REMOVE_TRANSITIVE_INCLUDES but
misses <cstdlib>, which libc++ 22 no longer provides transitively
(fixed upstream in fmt 12).

TEMPORARY: this overlay disappears with the Phase 1.3 vcpkg baseline
bump, which brings current fmt and folly together.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
clangd 18 cannot parse libc++ 22 headers (unknown builtins like
__builtin_clzg), so clangd moves to 22 with the compilers: on macOS via
the keg's bin dir prepended to PATH, on Linux via the clangd-22 package.
clang-format moves to 22 on both platforms as well — macOS lost its old
force-linked copy with the keg-only switch, and format versions must
not diverge between platforms or the check flip-flops. The resulting
mechanical reformat (clang-format 22 line-breaking changes) touches 20
files.

clang-tidy checks added/extended after version 18 fire on existing
code; they are suppressed in .clang-tidy (root + the two test configs
that shadow it) with a note, to be triaged in the lint-modernization
phase. One targeted NOLINTNEXTLINE for a namespace alias that clangd 22
newly checks against naming rules.

Verified locally: full build, 307/307 tests, full lint green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
folly's configure runs try_run() checks that cannot execute when
cross-compiling. The arm64-android triplet has always preset the
*_EXITCODE results for them; the arm64-ios triplet never did, so
folly's iOS configure errored out. Preset them with the values the
same checks produce when they actually run on an arm64 Apple host
(observed in the arm64-osx build): unaligned access ok, wchar ok,
vsnprintf-errors/weak-symbols/linux-vdso not available.

Verified locally: full arm64-ios dependency set builds with LLVM 22
(folly compiles against libc++ 22 headers with the existing
availability workaround), all packages cross-compile, and the
XCFramework is produced with platform=iOS, minos=13.0 and no
references to runtime symbols newer than the deployment target.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added ci Pull requests that update Continuous Integration build docs proto-rpc utils logger network dht labels Jul 2, 2026
The keyword gates checked github.event.head_commit.message, which is
only populated on push events — and these workflows' push trigger is
main-only, so the keywords could never fire on a pull request. The
gates now also match the PR title, making pre-merge iOS/Android
validation possible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ptesavol ptesavol changed the title Modernization Phase 1.2: LLVM 22 compilers on all platforms + CI image modernization Modernization Phase 1.2: LLVM 22 compilers + CI image modernization [iosbuild] Jul 2, 2026
ptesavol and others added 16 commits July 2, 2026 11:50
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The iOS workflow failed in 18s: its checkout did not fetch submodules
(unlike validate.yml), leaving install-prerequisities.sh to clone them
raw — and the wrappers/go submodule used an SSH URL, which fails on
runners without SSH keys. goproxyclient is public, so .gitmodules now
uses the https URL (run `git submodule sync` in existing checkouts),
and the iOS/Android workflows check out submodules with the token like
validate.yml does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…osbuild)

Replaces the hardcoded libdatachannel-only log dump with a generic
handler: on install failure the most recently written vcpkg buildtree
logs are printed (grouped) and their tails emitted as ::error::
annotations, so failures are diagnosable from the Checks UI without
authenticated access to raw logs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CMake 4 (now on the macOS runners and current Homebrew) removed
compatibility with cmake_minimum_required(<3.5); several ports at the
pinned 2024 vcpkg baseline (first casualty: libevent) still declare
such minimums and fail to configure. CMAKE_POLICY_VERSION_MINIMUM=3.5
is the documented escape hatch. Linux stays on CMake 3.28 (stock
ubuntu-24.04/noble), which still accepts the old minimums.

TEMPORARY: remove with the Phase 1.3 vcpkg baseline bump, which brings
ports that declare modern CMake minimums.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CMake 4 no longer defaults CMAKE_OSX_SYSROOT to the SDK path, and the
pinned 2024 vcpkg scripts compose "-isysroot ${CMAKE_OSX_SYSROOT}"
unconditionally — with an empty value the flag swallowed the next
argument and C system headers vanished (first casualty: openssl,
'assert.h' file not found). Naming the SDK explicitly restores the old
behavior. The iOS triplet is unaffected: ios.toolchain.cmake sets its
own iphoneos sysroot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The newest buildtree logs at failure time are often config/cache dumps
without the actual compiler error; prefer recent logs that grep for
error text and annotate the error context.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous handler died under bash -e (ls on an empty glob exits 2)
before emitting anything when vcpkg buildtrees were empty — which also
revealed the failure can occur outside port builds. Capture install.sh
output with tee and always annotate its tail (covers vcpkg, package
and root build failures alike); buildtree log annotations remain for
port failures. set +e inside the handler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Composite run steps execute under bash -e -o pipefail, which aborted
the step at the failing install pipeline before the annotation handler
could run. Handler now verified locally under the same shell flags.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Linux triplets never passed CMAKE_CXX_STANDARD=26 to ports (all
other platforms' triplets do), so folly built at its default C++17.
Under clang, C++17 means no coroutines: folly's coro translation units
compile to empty objects (FOLLY_HAS_COROUTINES off), and the SDK's
C++26 build then fails to link with undefined folly::coro symbols
(observed on both Linux CI legs). The old gcc toolchain masked this
because folly adds -fcoroutines for GNU compilers only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The overlay's fix-cmakelists.patch replaced upstream's configure_file
with a REMOVE/COPY/RENAME dance that mutates the shared source tree.
vcpkg configures debug and release in parallel, so the two configures
raced on include/rtc/version.h(.in) — reliably breaking the x64-linux
and arm64-linux builds ("file COPY cannot set modification time",
"file RENAME failed"), while macOS kept winning the race by luck.
Replaced with configure_file(... COPYONLY): same no-substitution
behavior, idempotent, nothing consumed. Patch verified to apply
cleanly to pristine v0.21.2 together with the other three patches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The working plan for the toolchain update + C++ modules migration,
kept current as phases land. Status as of this commit: Phases 1.0/1.1
and the ts-test interim merged (PRs #20-#22), Phase 1.2 in review
(PR #23).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The networking integration tests (ConnectionLockingTest.*) are
timing-sensitive on shared CI runners and have flaked on both the old
toolchain (LockingBothWays, ubuntu, PR #22) and the new one
(CanLockConnections, macos, PR #23) while passing on adjacent runs of
the same configuration. A retry keeps the signal — a genuinely broken
test fails both attempts — without burning CI round-trips on scheduler
jitter. Proper timing-assumption fixes for these tests remain a
separate workstream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vcpkg's port ABI hashes depend on the overlay triplet and port files,
not just vcpkg.json. Keying the caches on vcpkg.json alone meant any
triplet/port change collided with a stale saved cache (save skips
existing keys), forcing full dependency rebuilds on every retry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
./iostest.sh runs on the Mac as before; ./iostest.sh --device [name]
runs the same suite on a connected iPhone — the real check that the
compiler output is compatible with the device's fixed libc++ runtime.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ConnectionLockingTest hung indefinitely on a macOS runner (test step
30+ min for a ~35 s suite); --repeat until-pass only fires on failure,
so a hang ate the job. --timeout 300 turns a hang into a failure,
which then gets the single retry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged-as-is per review decision; the socket-based integration tests'
timing/port assumptions are their own workstream.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ptesavol

ptesavol commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

Final CI state — ready for review/merge

Check Result
validate: ubuntu-latest (clang-22 + libc++) ✅ green, 3 consecutive runs
validate: linux-arm64-runner (clang-22 + libc++) ✅ green, 3 consecutive runs
validate: macos-latest — install + lint ✅
validate: macos-latest — test ⚠️ intermittent failures/hangs in the socket-based integration tests only (rotating cast: ConnectionLocking/ConnectionManager/WebsocketClientServer; full suite passed on the same toolchain in an earlier run of this PR and passes locally 307/307)
validate iOS (first-ever pre-merge iOS CI) ✅ green, 8 consecutive runs
Local: build + 307/307 tests + lint (LLVM 22, CMake 4.3.4) ✅
XCFramework: platform=iOS, minos=13.0, no post-DT runtime symbols ✅

Per review decision: merging as-is; the socket-test timing/port assumptions become their own workstream (they predate this PR — the debt was exposed by introducing macOS CI at all; test.sh now bounds the damage with ctest --repeat until-pass:2 --timeout 300). Recorded in MODERNIZATION.md, which is now committed in the repo and updated per phase.

Also landed on this branch since the last summary: MODERNIZATION.md (the plan the PRs reference), overlay-aware CI cache keys (triplet/port changes no longer collide with stale caches), install-failure log annotations, PR-title-triggerable iOS/Android workflows, https submodule URL for goproxyclient, and ./iostest.sh --device [name] for the physical-device gate.

Outstanding user-side item for the Phase 1.2 gate: ./iostest.sh (and ideally --device) after re-authenticating the Apple ID in Xcode → Settings → Accounts.

🤖 Generated with Claude Code

@ptesavol
ptesavol merged commit 498626f into main Jul 2, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Pull requests that update Continuous Integration build dht docs logger network proto-rpc utils

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant