a73x

deps/mac-sdk.sh

Ref:   Size: 3.3 KiB   History

#!/bin/sh
# deps/mac-sdk.sh — a shadow macOS SDK for zig 0.15.2, built on a Darwin host.
#
# Xcode 26.4 and later ship a libSystem.B.tbd whose `targets:` line lists
# arm64e-macos and no arm64-macos. zig 0.15.2's Mach-O linker matches the
# bare arm64 slice only, so against that SDK every libSystem symbol is
# undefined — for the build runner too, which is why `zig build` cannot
# even start (ziglang/zig#31658 on Codeberg; fixed in 0.16, which ghostty's
# pin cannot use). zig's own lib/libc/darwin/libSystem.tbd is what a
# `-target aarch64-macos` build links against, and it works. This script
# builds an SDK that is the real one in every path but usr/lib/libSystem*,
# where zig's stub stands in, and an `xcrun` shim that answers
# --show-sdk-path with it — zig finds the SDK by running `xcrun` off PATH
# (std/zig/system/darwin.zig), and so does ghostty's apple_sdk helper.
#
# Self-retiring: when the real SDK's stub lists arm64-macos again, no shadow
# is built and the shim, if a stale one is on PATH, passes straight through.
# Idempotent: a run that finds its own shadow already standing over the
# current SDK exits without touching it.
#
# That marker check is deliberately LAST of the three, after the xcrun fork
# and the tbd grep, even though `mac-sdk` is a phony target every make on a
# Mac runs. The fork cannot move: the marker compares against the real SDK's
# path and only xcrun knows it. The grep cannot move either, because an
# Xcode update in place leaves MacOSX.sdk at the same path -- so a marker
# consulted first would match its own stale shadow and go on shadowing an
# SDK that had been fixed. One fork and one local grep is what the retire
# check costs, and it is the cheaper half of the two.
#
#   ./deps/mac-sdk.sh            builds deps/mac-sdk/{sdk,bin/xcrun}
set -eu
[ "$(uname)" = Darwin ] || exit 0
SELF="$(cd "$(dirname "$0")" && pwd)"
OUT="$SELF/mac-sdk"
ZIG="${ZIG:?deps/mac-sdk: ZIG is not set}"
ZIG_ROOT="$(cd "$(dirname "$ZIG")" && pwd)"
ZIG_STUB="$ZIG_ROOT/lib/libc/darwin/libSystem.tbd"
REAL="$(/usr/bin/xcrun --sdk macosx --show-sdk-path)"
if grep -m1 '^targets:' "$REAL/usr/lib/libSystem.B.tbd" | grep -q 'arm64-macos'; then
    rm -rf "$OUT"      # the SDK is linkable again; leave nothing to shadow it
    exit 0
fi
[ -f "$ZIG_STUB" ] || { echo "deps/mac-sdk: no Zig 0.15.2 stub at $ZIG_STUB" >&2; exit 1; }
# Marker: the shim exists AND points at this SDK. A new Xcode moves REAL.
if [ -x "$OUT/bin/xcrun" ] && [ "$(readlink "$OUT/sdk/usr/include")" = "$REAL/usr/include" ]; then
    exit 0
fi
rm -rf "$OUT"
mkdir -p "$OUT/sdk/usr/lib" "$OUT/bin"
for e in "$REAL"/*; do b=$(basename "$e"); [ "$b" = usr ] || ln -s "$e" "$OUT/sdk/$b"; done
for e in "$REAL"/usr/*; do b=$(basename "$e"); [ "$b" = lib ] || ln -s "$e" "$OUT/sdk/usr/$b"; done
for e in "$REAL"/usr/lib/*; do
    b=$(basename "$e")
    case "$b" in libSystem.tbd | libSystem.B.tbd) ;; *) ln -s "$e" "$OUT/sdk/usr/lib/$b" ;; esac
done
cp "$ZIG_STUB" "$OUT/sdk/usr/lib/libSystem.tbd"
cp "$ZIG_STUB" "$OUT/sdk/usr/lib/libSystem.B.tbd"
cat > "$OUT/bin/xcrun" <<EOF
#!/bin/sh
# Shim from deps/mac-sdk.sh: only --show-sdk-path is answered here.
case "\$*" in
    *--show-sdk-path*) [ -d "$OUT/sdk" ] && { echo "$OUT/sdk"; exit 0; } ;;
esac
exec /usr/bin/xcrun "\$@"
EOF
chmod +x "$OUT/bin/xcrun"
echo "deps/mac-sdk: shadow SDK over $REAL (zig 0.15.2 cannot link the Xcode 26.4+ stub)" >&2