diff --git a/.github/workflows/build-ghosttykit.yml b/.github/workflows/build-ghosttykit.yml index 850bab3300f..c1454a8895b 100644 --- a/.github/workflows/build-ghosttykit.yml +++ b/.github/workflows/build-ghosttykit.yml @@ -85,7 +85,7 @@ jobs: export PATH="/usr/local/bin:$PATH" zig version fi - cd ghostty && zig build -Demit-xcframework=true -Demit-macos-app=false -Dxcframework-target=universal -Doptimize=ReleaseFast + cd ghostty && zig build -Demit-xcframework=true -Demit-macos-app=false -Dxcframework-target=native -Doptimize=ReleaseFast - name: Package xcframework if: steps.check-release.outputs.exists == 'false' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d312b557d7a..c44a2fd5b43 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -198,8 +198,16 @@ jobs: fi npm install --global "create-dmg@${CREATE_DMG_VERSION}" - - name: Download pre-built GhosttyKit.xcframework + - name: Cache GhosttyKit.xcframework + id: cache-ghosttykit-release if: steps.guard_release_assets.outputs.skip_all != 'true' + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4 + with: + path: GhosttyKit.xcframework + key: ghosttykit-v2-${{ hashFiles('.gitmodules', 'ghostty') }} + + - name: Download pre-built GhosttyKit.xcframework + if: steps.guard_release_assets.outputs.skip_all != 'true' && steps.cache-ghosttykit-release.outputs.cache-hit != 'true' run: | ./scripts/download-prebuilt-ghosttykit.sh @@ -236,7 +244,7 @@ jobs: xcodebuild -scheme programa -configuration Release -derivedDataPath build-universal \ -destination 'generic/platform=macOS' \ -clonedSourcePackagesDirPath .spm-cache \ - ARCHS="arm64 x86_64" \ + ARCHS="arm64" \ ONLY_ACTIVE_ARCH=NO \ CODE_SIGNING_ALLOWED=NO build @@ -253,9 +261,9 @@ jobs: echo "App binary architectures: $APP_ARCHS" echo "CLI binary architectures: $CLI_ARCHS" echo "Ghostty helper architectures: $HELPER_ARCHS" - [[ "$APP_ARCHS" == *arm64* && "$APP_ARCHS" == *x86_64* ]] - [[ "$CLI_ARCHS" == *arm64* && "$CLI_ARCHS" == *x86_64* ]] - [[ "$HELPER_ARCHS" == *arm64* && "$HELPER_ARCHS" == *x86_64* ]] + [[ "$APP_ARCHS" == "arm64" ]] + [[ "$CLI_ARCHS" == "arm64" ]] + [[ "$HELPER_ARCHS" == "arm64" ]] - name: Build remote daemon release assets and inject manifest if: steps.guard_release_assets.outputs.skip_all != 'true' diff --git a/scripts/ensure-ghosttykit.sh b/scripts/ensure-ghosttykit.sh index 8e9b13bf8ce..2d2299eb79b 100755 --- a/scripts/ensure-ghosttykit.sh +++ b/scripts/ensure-ghosttykit.sh @@ -120,7 +120,7 @@ else echo "==> Building GhosttyKit.xcframework (this may take a few minutes)..." ( cd ghostty - zig build -Demit-xcframework=true -Demit-macos-app=false -Dxcframework-target=universal -Doptimize=ReleaseFast + zig build -Demit-xcframework=true -Demit-macos-app=false -Dxcframework-target=native -Doptimize=ReleaseFast ) echo "$GHOSTTY_KEY" > "$LOCAL_KEY_STAMP" echo "$GHOSTTY_SHA" > "$LEGACY_LOCAL_SHA_STAMP" @@ -140,10 +140,19 @@ else echo "==> Cached GhosttyKit.xcframework at $CACHE_XCFRAMEWORK" fi -MACOS_ARCHIVE="$CACHE_XCFRAMEWORK/macos-arm64_x86_64/libghostty.a" -if [[ -f "$MACOS_ARCHIVE" ]]; then - # Xcode 26 can fail to resolve symbols from Ghostty's universal static archive - # until its ranlib index is refreshed after reuse or copy. +# The macos slice dir is named by its arch(s): macos-arm64 (native, arm64-only) or +# macos-arm64_x86_64 (universal) — match whichever exists. A non-matching glob leaves +# the literal pattern, which the -f guard rejects, so this is safe under `set -e`. +MACOS_ARCHIVE="" +for _macos_archive in "$CACHE_XCFRAMEWORK"/macos-*/libghostty.a; do + if [[ -f "$_macos_archive" ]]; then + MACOS_ARCHIVE="$_macos_archive" + break + fi +done +if [[ -n "$MACOS_ARCHIVE" ]]; then + # Xcode 26 can fail to resolve symbols from Ghostty's static archive until its + # ranlib index is refreshed after reuse or copy. echo "==> Refreshing libghostty archive index..." if ! command -v xcrun >/dev/null 2>&1; then echo "error: xcrun is required to refresh libghostty archive index." >&2 diff --git a/tests/test_ci_universal_release_settings.sh b/tests/test_ci_universal_release_settings.sh index c374c6fbf93..a4b94ed5faa 100644 --- a/tests/test_ci_universal_release_settings.sh +++ b/tests/test_ci_universal_release_settings.sh @@ -1,15 +1,38 @@ #!/usr/bin/env bash -# Regression test for universal GhosttyKit and Release build settings. +# Regression test for arm64-only GhosttyKit and Release build settings. set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" for file in \ "$ROOT_DIR/.github/workflows/build-ghosttykit.yml" \ - "$ROOT_DIR/scripts/setup.sh" + "$ROOT_DIR/scripts/ensure-ghosttykit.sh" do - if ! grep -Fq -- '-Dxcframework-target=universal' "$file"; then - echo "FAIL: $file must build GhosttyKit with -Dxcframework-target=universal" + if ! grep -Fq -- '-Dxcframework-target=native' "$file"; then + echo "FAIL: $file must build GhosttyKit with -Dxcframework-target=native (arm64-only)" + exit 1 + fi + if grep -Fq -- '-Dxcframework-target=universal' "$file"; then + echo "FAIL: $file must not build GhosttyKit as universal" + exit 1 + fi +done + +RELEASE_YML="$ROOT_DIR/.github/workflows/release.yml" + +if ! grep -Fq 'ARCHS="arm64"' "$RELEASE_YML"; then + echo "FAIL: release.yml must build the Release app with ARCHS=\"arm64\" only" + exit 1 +fi + +if grep -Fq 'ARCHS="arm64 x86_64"' "$RELEASE_YML"; then + echo "FAIL: release.yml must not build the Release app as universal (arm64 x86_64)" + exit 1 +fi + +for var in APP_ARCHS CLI_ARCHS HELPER_ARCHS; do + if ! grep -Fq "[[ \"\$${var}\" == \"arm64\" ]]" "$RELEASE_YML"; then + echo "FAIL: release.yml must verify \$${var} is exactly arm64 (single-arch)" exit 1 fi done @@ -25,4 +48,4 @@ if ! awk ' exit 1 fi -echo "PASS: GhosttyKit builds universal and Release configs disable ONLY_ACTIVE_ARCH" +echo "PASS: GhosttyKit builds arm64-only and Release configs build/verify arm64-only"