Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
daemon-install daemon-uninstall daemon-status test check format clean \
dev-generate dev-build-app dev-build-daemon dev-install-daemon \
dev-install-zmx dev-run-app dev-status \
third-party build-zmx install-zmx build-ghostty vendor-sdk \
third-party build-zmx install-zmx build-ghostty vendor-sdk zig-sdk \
build-cli install-cli release-dmg notarize signing-doctor tap-bump build-nod

SCHEME_APP := graphcode
Expand Down Expand Up @@ -86,7 +86,7 @@ build-nod:
rm -rf "$(NOD_BUILD_DIR)"
cd NodRuntime && sh scripts/package.sh "$(NOD_BUILD_DIR)" bun-darwin-arm64

build-zmx:
build-zmx: zig-sdk
@test -d ThirdParty/zmx || { echo "ThirdParty/zmx missing — run: git submodule update --init --recursive"; exit 1; }
@# -Doptimize is load-bearing: zig defaults to Debug, whose ghostty-vt runs
@# page-integrity verification on every scrolled line. Measured via
Expand Down Expand Up @@ -122,7 +122,7 @@ install-zmx: build-zmx
|| { echo "zmx installed but won't run — check its code signature"; exit 1; }
@echo "zmx installed: $(SUPPORT_DIR)/bin/zmx"

build-ghostty:
build-ghostty: zig-sdk
@test -d ThirdParty/ghostty || { echo "ThirdParty/ghostty missing — run: git submodule update --init --recursive"; exit 1; }
@if xcrun metal --version 2>&1 | grep -q "missing Metal Toolchain"; then \
echo "[missing] Metal toolchain — GhosttyKit compiles Metal shaders."; \
Expand All @@ -145,6 +145,11 @@ build-ghostty:
@ditto ThirdParty/ghostty/macos/GhosttyKit.xcframework "$(BUILD_DIR)/ghostty/GhosttyKit.xcframework"
@echo "GhosttyKit built: $(BUILD_DIR)/ghostty/GhosttyKit.xcframework"

# When no macOS 15 SDK exists (GitHub's macos-26 runners), a patched view of the
# newest SDK stands in. A no-op wherever the shim already finds one.
zig-sdk:
@sh Tools/zig-sdk-shim/make-zig-sdk

# Copy a macOS 15 SDK into the repo so a Command Line Tools update that drops it
# can't break the zig builds. The shim prefers this copy when it exists.
vendor-sdk:
Expand Down
57 changes: 57 additions & 0 deletions Tools/zig-sdk-shim/make-zig-sdk
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/sh
# Builds .build/sdk/<name>-zig.sdk when no macOS 15 SDK is available — the case on
# GitHub's macos-26 runners since image 20261013, and on any Mac whose Command Line
# Tools no longer ship one.
#
# The result is the newest installed SDK seen through symlinks, except for
# usr/lib/libSystem.B.tbd: every document in it that lists `arm64e-macos` but not
# `arm64-macos` gets `arm64-macos` added, which is the fallback Apple's ld makes on
# its own and zig 0.15.2's linker doesn't (see ./xcrun). Nothing is copied but that
# one text file.
set -eu

shim_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
repo_root=$(CDPATH= cd -- "$shim_dir/../.." && pwd)

if "$shim_dir/xcrun" --sdk macosx --show-sdk-path >/dev/null 2>&1; then
exit 0
fi

# 26.x first: zig 0.15.2's bundled libc++ doesn't compile against the macOS 27
# headers (`INFINITY` undeclared in __random/clamp_to_integral.h).
source_sdk=$(ls -d /Library/Developer/CommandLineTools/SDKs/MacOSX26.*.sdk \
"$(/usr/bin/xcode-select -p)"/Platforms/MacOSX.platform/Developer/SDKs/MacOSX26.*.sdk \
2>/dev/null | sort -t/ -k1 -V | tail -1)
[ -n "$source_sdk" ] || source_sdk=$(/usr/bin/xcrun --sdk macosx --show-sdk-path)
source_sdk=$(CDPATH= cd -- "$source_sdk" && pwd -P)
name=$(basename "$source_sdk" .sdk)
[ "$name" != MacOSX ] || name="MacOSX$(/usr/bin/xcrun --sdk macosx --show-sdk-version)"
mkdir -p "$repo_root/.build/sdk"
destination="$repo_root/.build/sdk/$name-zig.sdk"
staging=$(mktemp -d "$repo_root/.build/sdk/.staging.XXXXXX")
trap 'rm -rf "$staging"' EXIT

sdk="$staging/sdk"
mkdir -p "$sdk/usr/lib"
for entry in "$source_sdk"/*; do
[ "$(basename "$entry")" = usr ] || ln -s "$entry" "$sdk/"
done
for entry in "$source_sdk"/usr/*; do
[ "$(basename "$entry")" = lib ] || ln -s "$entry" "$sdk/usr/"
done
for entry in "$source_sdk"/usr/lib/*; do
case "$(basename "$entry")" in
libSystem.B.tbd | libSystem.tbd) ;;
*) ln -s "$entry" "$sdk/usr/lib/" ;;
esac
done
perl -0777 -pe 's{(--- !tapi-tbd.*?)(?=--- !tapi-tbd|\z)}{
my $doc = $1;
$doc =~ s/\barm64e-macos\b/arm64-macos, arm64e-macos/g unless $doc =~ /\barm64-macos\b/;
$doc
}gse' "$source_sdk/usr/lib/libSystem.B.tbd" >"$sdk/usr/lib/libSystem.B.tbd"
ln -s libSystem.B.tbd "$sdk/usr/lib/libSystem.tbd"

rm -rf "$destination"
mv "$sdk" "$destination"
echo "zig SDK: $destination (from $source_sdk)"
14 changes: 8 additions & 6 deletions Tools/zig-sdk-shim/xcrun
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@
# ── Why this exists ────────────────────────────────────────────────────────────
# usr/lib/libSystem.B.tbd is a multi-document YAML file: one `!tapi-tbd` document
# for libSystem itself, then one per reexported sub-library. In macOS SDK 26.x the
# *primary* libSystem document dropped the plain `arm64-macos` target, leaving only
# `arm64e-macos`:
# libSystem document and most of its sub-library documents dropped the plain
# `arm64-macos` target, leaving only `arm64e-macos` (34 of 40 documents in 26.5):
#
# SDK 26.5: targets: [ x86_64-macos, x86_64-maccatalyst, arm64e-macos, arm64e-maccatalyst ]
# SDK 15.4: targets: [ x86_64-macos, x86_64-maccatalyst, arm64-macos, arm64-maccatalyst,
# arm64e-macos, arm64e-maccatalyst ]
#
# (`grep arm64-macos` on the 26.5 file still hits ~22 times — those are the *other*
# libraries' documents further down, not libSystem's own.)
#
# Zig targets `arm64`, finds no matching target in libSystem's document, and so
# concludes libSystem exports nothing — every libc symbol (_malloc, _getcwd,
# _fork, …) comes back undefined. Apple's own ld falls back arm64 -> arm64e; zig
Expand Down Expand Up @@ -59,6 +56,11 @@ resolve_sdk() {
newest=$(ls -d /Library/Developer/CommandLineTools/SDKs/MacOSX15*.sdk 2>/dev/null \
| sort -V | tail -1)
[ -n "$newest" ] && { printf '%s\n' "$newest"; return 0; }
# 4. A newer SDK with its libSystem stub patched, for machines that have no macOS 15
# SDK at all (`make zig-sdk`, which runs ./make-zig-sdk).
for candidate in "$repo_root"/.build/sdk/MacOSX*-zig.sdk; do
[ -d "$candidate" ] && { printf '%s\n' "$candidate"; return 0; }
done
return 1
}

Expand All @@ -78,7 +80,7 @@ if [ "$want_sdk_path" = "1" ] && [ "$sdk" = "macosx" ]; then
exit 0
fi
echo "zig-sdk-shim: no macOS 15 SDK found. Install the Command Line Tools" >&2
echo " (xcode-select --install) or set GRAPHCODE_ZIG_SDK to a macOS 15 SDK." >&2
echo " (xcode-select --install), run \`make zig-sdk\`, or set GRAPHCODE_ZIG_SDK." >&2
exit 1
fi

Expand Down
Loading