1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
#!/bin/sh
# Assemble pardes.app from libpardes.a and the Swift sources. Run it through
# `zig build macos-app -Dplatform=macos`, or by hand with the install prefix as
# $1, the deployment target as $2 and the Zig optimize mode as $3 once
# `zig build -Dplatform=macos` has produced the library.
#
# There is no Xcode project on purpose. An .app is a directory with a plist and
# a binary in it, swiftc ships with the Command Line Tools, and a hand-written
# pbxproj would be a second build system to keep in step for no gain at this
# stage. What Xcode buys — an xcframework of universal slices, codesigning,
# notarization, a DMG — is distribution machinery; see docs/macos.md for the
# upgrade path when that day comes.
set -eu
root=$(cd "$(dirname "$0")/../.." && pwd)
out=${1:-"$root/zig-out"}
# Keep in step with macos_min_version in build.zig, which passes it in. The
# default is only for a by-hand run.
minver=${2:-13.0}
# Both swiftc invocations below take the same triple; the note above the app
# link is why -target is not optional for either of them.
target="$(uname -m)-apple-macos$minver"
app="$out/pardes.app"
lib="$out/lib/libpardes.a"
# The two halves of this program are compiled by two compilers, and before this
# only one of them was told anything: swiftc was hardcoded to -O while the Zig
# core followed -Doptimize, so the ordinary `zig build macos-app` produced an
# optimized shell around a DEBUG core. It does not read as "I built Debug", it
# reads as "the mac backend is slow" — measured on this machine, one frame at
# 190x56 cost 4.5 ms with a Debug core and 0.88 ms with a ReleaseFast one, and
# 4.1 ms of that 4.5 was pardes_frame alone. So the mode travels, both halves
# agree, and a slow bundle says why.
zigmode=${3:-Debug}
case $zigmode in
Debug) swiftmode=-Onone ;;
ReleaseSmall) swiftmode=-Osize ;;
*) swiftmode=-O ;;
esac
[ -f "$lib" ] || { echo "missing $lib — run: zig build -Dplatform=macos" >&2; exit 1; }
command -v swiftc >/dev/null || { echo "swiftc not found (needs macOS + Command Line Tools)" >&2; exit 1; }
rm -rf "$app"
mkdir -p "$app/Contents/MacOS" "$app/Contents/Resources"
cp "$root/src/macos/Info.plist" "$app/Contents/Info.plist"
# One version, three consumers: the plist's claim is set from the same string
# the link below enforces, so a bumped deployment target cannot leave a stale
# LSMinimumSystemVersion behind.
/usr/libexec/PlistBuddy -c "Set :LSMinimumSystemVersion $minver" "$app/Contents/Info.plist" >/dev/null
# The icon is generated rather than committed. The mark is drawn out of the
# same palette PardesView.swift renders cells with — #121212 body, the tag bar
# and the block cursor straight from ansi16 — so a colour that moves there
# moves here on the next build, instead of a binary blob sitting in the tree
# quietly disagreeing with the app it ships in. Info.plist's CFBundleIconFile
# names the pardes.icns this drops into Resources; without both halves the Dock
# falls back to the generic blank page.
#
# The trap covers the compiled generator; the generator clears its own scratch
# iconset. set -eu means a failure here takes the whole build down, which is
# the point: a bundle that ships a blank icon should not have built.
icontmp=$(mktemp -d)
trap 'rm -rf "$icontmp"' EXIT
swiftc -O -target "$target" -o "$icontmp/pardes-icon" "$root/src/macos/icon.swift"
"$icontmp/pardes-icon" "$app/Contents/Resources"
# -import-objc-header rather than a module map: the header is consumed straight
# from the source tree, so there is nothing to stage and nothing to keep in
# sync. A module map is what an xcframework needs, and there isn't one.
#
# -lc++ because ghostty-vt pulls in simdutf and highway, which are C++. The Zig
# side bundles compiler_rt/ubsan_rt into the archive (see build.zig), so the
# C++ runtime is the only thing left for this link to supply.
# -target is not optional. Without it swiftc uses the host triple, so
# LC_BUILD_VERSION records whatever macOS built the thing and dyld refuses to
# launch it on anything older — the Info.plist's LSMinimumSystemVersion is a
# claim, not the enforcement. It is also what turns on the availability
# diagnostics that catch a post-13 API before a user does.
swiftc "$swiftmode" -target "$target" \
-import-objc-header "$root/src/macos/pardes.h" \
-o "$app/Contents/MacOS/pardes" \
"$root"/src/macos/Sources/*.swift \
"$lib" -lc++ \
-framework AppKit -framework CoreText -framework CoreGraphics
# An .app whose mtime never moves is an .app Launch Services keeps serving from
# its cache, icon and plist and all.
touch "$app"
if [ "$zigmode" = Debug ]; then
echo "built $app (Debug core — rebuild with -Doptimize=ReleaseFast to use it)"
else
echo "built $app"
fi
|