diff --git a/.github/workflows/_build.yml b/.github/workflows/_build.yml index 47b5b17b5e..43c52b052a 100644 --- a/.github/workflows/_build.yml +++ b/.github/workflows/_build.yml @@ -41,7 +41,9 @@ jobs: goarch: arm64 cc: gcc cxx: g++ - - os: macos-14 + # The macOS minimum (14.0) is pinned in Makefile.cbm, not inherited + # from this runner's SDK, so both darwin binaries still start on macOS 14. + - os: macos-15 goos: darwin goarch: arm64 cc: cc diff --git a/.github/workflows/_memwaste.yml b/.github/workflows/_memwaste.yml index 174490db6c..09deb0c37e 100644 --- a/.github/workflows/_memwaste.yml +++ b/.github/workflows/_memwaste.yml @@ -115,7 +115,7 @@ jobs: event-macos: if: ${{ inputs.mode == 'full' }} - runs-on: macos-14 + runs-on: macos-15 timeout-minutes: 60 steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 diff --git a/.github/workflows/_smoke.yml b/.github/workflows/_smoke.yml index 1a4d4eb57c..96c47d44f1 100644 --- a/.github/workflows/_smoke.yml +++ b/.github/workflows/_smoke.yml @@ -33,7 +33,7 @@ jobs: CORE_UNIX='[ {"os":"ubuntu-latest","goos":"linux","goarch":"amd64"}, {"os":"ubuntu-24.04-arm","goos":"linux","goarch":"arm64"}, - {"os":"macos-14","goos":"darwin","goarch":"arm64"}, + {"os":"macos-15","goos":"darwin","goarch":"arm64"}, {"os":"macos-15-intel","goos":"darwin","goarch":"amd64"} ]' # Broad legs reuse existing goos/goarch artifacts on additional OS @@ -47,9 +47,10 @@ jobs: # (ubuntu-22.04 / 22.04-arm). So the dynamic broad legs stay on # forward-compatible OSes only (macOS); running the dynamic binary on # ubuntu-22.04 would fail Phase 1 (glibc too old), not a real regression. - BROAD_UNIX='[ - {"os":"macos-15","goos":"darwin","goarch":"arm64"} - ]' + # Empty since the move off macos-14 (retired 2026-11-02): the darwin-arm64 + # artifact is now built AND smoked on macos-15, the core leg, which was + # this broad leg. + BROAD_UNIX='[]' CORE_WIN='[{"os":"windows-latest","arch":"amd64"}]' # windows-11-arm now runs the NATIVE arm64 binary (build-windows-arm64), # not the x86_64 binary under emulation — we smoke the artifact we ship. diff --git a/.github/workflows/_soak.yml b/.github/workflows/_soak.yml index abf365f541..63c3ec51e7 100644 --- a/.github/workflows/_soak.yml +++ b/.github/workflows/_soak.yml @@ -44,7 +44,7 @@ jobs: goarch: arm64 cc: gcc cxx: g++ - - os: macos-14 + - os: macos-15 goos: darwin goarch: arm64 cc: cc @@ -335,7 +335,7 @@ jobs: goarch: arm64 cc: gcc cxx: g++ - - os: macos-14 + - os: macos-15 goos: darwin goarch: arm64 cc: cc diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 39baa516c1..55a8bf6085 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -57,18 +57,21 @@ jobs: run: | # Every CORE leg is tagged with the lane (scripts/ci/select-lanes.sh) # it serves; the tag is what lane selection filters on below. + # The lane names unix-macos14 and tsan-mac are kept as lane keys + # (select-lanes.sh, ci-ok and the lane contracts key on them); both + # run on macos-15 because GitHub retires the macos-14 image on 2026-11-02. CORE_UNIX='[ {"os":"ubuntu-latest","cc":"gcc","cxx":"g++","lane":"unix-x86"}, {"os":"ubuntu-24.04-arm","cc":"gcc","cxx":"g++","lane":"unix-arm64"}, - {"os":"macos-14","cc":"cc","cxx":"c++","lane":"unix-macos14"}, + {"os":"macos-15","cc":"cc","cxx":"c++","lane":"unix-macos14"}, {"os":"macos-15-intel","cc":"cc","cxx":"c++","lane":"unix-macos-intel"} ]' # Broad matrix legs are REQUIRED gates (no optional/continue-on-error # escape hatches): the release dry run must be all-green, every platform. + # macos-15 is the CORE macOS arm64 leg now, so it is not repeated here. BROAD_UNIX='[ {"os":"ubuntu-22.04","cc":"gcc","cxx":"g++"}, - {"os":"ubuntu-22.04-arm","cc":"gcc","cxx":"g++"}, - {"os":"macos-15","cc":"cc","cxx":"c++"} + {"os":"ubuntu-22.04-arm","cc":"gcc","cxx":"g++"} ]' # Each Windows leg pins the msys2 environment + package arch to the # RUNNER architecture so the build is native, never emulated: @@ -92,7 +95,7 @@ jobs: TSAN='[ {"os":"ubuntu-latest","cc":"clang","cxx":"clang++","lane":"tsan-x86"}, {"os":"ubuntu-24.04-arm","cc":"clang","cxx":"clang++","lane":"tsan-arm"}, - {"os":"macos-14","cc":"cc","cxx":"c++","lane":"tsan-mac"} + {"os":"macos-15","cc":"cc","cxx":"c++","lane":"tsan-mac"} ]' # Lane selection. "all" (dry run, release) keeps every leg and drops # the tags, so those matrices -- and their job names -- stay exactly diff --git a/.github/workflows/bug-repro.yml b/.github/workflows/bug-repro.yml index 2910606d03..e3e1a647a6 100644 --- a/.github/workflows/bug-repro.yml +++ b/.github/workflows/bug-repro.yml @@ -40,7 +40,7 @@ jobs: group: linux cc: gcc cxx: g++ - - os: macos-14 + - os: macos-15 group: macos cc: cc cxx: c++ diff --git a/.github/workflows/cache-warm.yml b/.github/workflows/cache-warm.yml index ff15fbb1a7..bca57b23b7 100644 --- a/.github/workflows/cache-warm.yml +++ b/.github/workflows/cache-warm.yml @@ -27,7 +27,7 @@ jobs: include: - { os: ubuntu-latest, cc: gcc, cxx: g++ } - { os: ubuntu-24.04-arm, cc: gcc, cxx: g++ } - - { os: macos-14, cc: cc, cxx: c++ } + - { os: macos-15, cc: cc, cxx: c++ } - { os: macos-15-intel, cc: cc, cxx: c++ } runs-on: ${{ matrix.os }} timeout-minutes: 60 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 81a838e804..aade2b93da 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -175,7 +175,7 @@ jobs: cat "$RUNNER_TEMP/selection.txt" >> "$GITHUB_OUTPUT" # pr-smoke's legs, each tagged with its lane (kept in the job name, # where ci-ok reads it back); the job gets the selected ones. - SMOKE='[{"os":"ubuntu-latest","lane":"smoke-ubuntu"},{"os":"macos-14","lane":"smoke-mac"},{"os":"windows-latest","lane":"smoke-win"}]' + SMOKE='[{"os":"ubuntu-latest","lane":"smoke-ubuntu"},{"os":"macos-15","lane":"smoke-mac"},{"os":"windows-latest","lane":"smoke-win"}]' LANES=$(sed -n 's/^lanes=//p' "$RUNNER_TEMP/selection.txt") echo "smoke={\"include\":$(jq -c --argjson sel "$LANES" 'map(select(.lane | IN($sel[])))' <<< "$SMOKE")}" >> "$GITHUB_OUTPUT" # The CodeQL legs, tagged the same way (codeql.yml's full matrix has @@ -214,7 +214,7 @@ jobs: run: sudo apt-get update && sudo apt-get install -y zlib1g-dev ccache - name: Install ccache (macOS) - if: matrix.os == 'macos-14' + if: matrix.os == 'macos-15' run: command -v ccache >/dev/null 2>&1 || brew install ccache - uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2 @@ -254,7 +254,7 @@ jobs: SMOKE_REQUIRE_WRAPPERS: "1" - name: Build prod + smoke (macOS) - if: matrix.os == 'macos-14' + if: matrix.os == 'macos-15' run: | scripts/build.sh CC=cc CXX=c++ codesign --sign - --force build/c/codebase-memory-mcp diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index e9b4f93575..2de8e1b8e4 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -39,9 +39,6 @@ jobs: - os: ubuntu-24.04-arm cc: gcc cxx: g++ - - os: macos-14 # arm64 - cc: cc - cxx: c++ - os: macos-15 # arm64 cc: cc cxx: c++ diff --git a/Makefile.cbm b/Makefile.cbm index 3c73982925..12f0fe5c12 100644 --- a/Makefile.cbm +++ b/Makefile.cbm @@ -18,8 +18,24 @@ # that use their own *_CFLAGS — and so it survives a command-line `CC=` override. # ARCHFLAGS is empty on Linux/Windows and for native direct `make` invocations, # leaving CC/CXX unchanged there. -override CC := $(CC) $(ARCHFLAGS) -override CXX := $(CXX) $(ARCHFLAGS) +# +# Minimum macOS version (Apple targets only). Without one, clang takes the +# minimum from the SDK it compiles against (LC_BUILD_VERSION minos), so a +# release built on a macos-15 runner would refuse to start on macOS 14. 14.0 +# keeps every macOS that could run a release built on the macos-14 runner +# (retired 2026-11-02). A flag folded into the drivers like ARCHFLAGS, not an +# exported MACOSX_DEPLOYMENT_TARGET: it reaches every compile AND link on every +# build path (build.sh, test.sh, direct make) and is part of each command line. +# Detected from the compiler's target, not the host, so a cross compiler run +# on a Mac is left untouched. +MACOS_MIN_VERSION := 14.0 +IS_APPLE_TARGET := $(shell echo | $(CC) $(ARCHFLAGS) -dM -E - 2>/dev/null | grep -q '__APPLE__' && echo yes || echo no) +MACOS_MIN_FLAGS := +ifeq ($(IS_APPLE_TARGET),yes) +MACOS_MIN_FLAGS := -mmacosx-version-min=$(MACOS_MIN_VERSION) +endif +override CC := $(CC) $(ARCHFLAGS) $(MACOS_MIN_FLAGS) +override CXX := $(CXX) $(ARCHFLAGS) $(MACOS_MIN_FLAGS) # ── Common flags ───────────────────────────────────────────────── diff --git a/tests/test_lane_gate_contract.sh b/tests/test_lane_gate_contract.sh index 57e2cc12ee..f016f2e99d 100755 --- a/tests/test_lane_gate_contract.sh +++ b/tests/test_lane_gate_contract.sh @@ -49,7 +49,7 @@ t1_jobs() { # the jobs of a green T1 run; $1 = conclusion of the x86 leg job "lint / lint-mem" success job "test / setup-matrix" success job "test / test-unix (ubuntu-latest, gcc, g++, unix-x86, 1/1)" "$1" - job "test / test-unix (macos-14, cc, c++, unix-macos14, 1/1)" success + job "test / test-unix (macos-15, cc, c++, unix-macos14, 1/1)" success job "test / test-windows (windows-latest, CLANG64, x86_64, windows, 1/1)" success job "test / test-windows-guards" skipped job "test / test-package-wrappers" skipped @@ -116,7 +116,7 @@ gate "a selection without the job list is red" 1 "$NEEDS_OK" "$T1" "$WORK/does-n job "lint / lint" success job "lint / lint-mem" success job "test / test-windows-guards" success - job "pr-smoke (macos-14, smoke-mac)" success + job "pr-smoke (macos-15, smoke-mac)" success } >"$WORK/guards-only" gate "windows-guards is not the windows leg" 1 "$NEEDS_OK" '["lint","lint-mem","security-static","windows"]' "$WORK/guards-only" gate "pr-smoke matrix name maps to its lane" 0 "$NEEDS_OK" '["lint","lint-mem","security-static","smoke-mac","windows-guards"]' "$WORK/guards-only"