Files
terminalX/vendor/libghostty-spm/Script/build-ghostty.sh
kid aa92d0e676 初始提交:terminalX 可运行态(M0/M1/M1.5 已真机验证)
- M0: libghostty SSH 终端(渲染/输入/连接)+ 白屏修复(OutputGate) + 会话状态机/自动重连
- M1: tsnet 用户态组网 + SSH-over-tsnet(fd 桥),shell 级真机验证;R5(Go+gvisor+C+++Swift 同进程) retire
- M1.5: tmux -CC 原生 tab(MVP)
- 结构: packages/(TXCore·TXTransport), apps/TerminalX, vendor/(libghostty-spm/libssh2/mbedtls/tsnet-bridge), artifacts/
- 文档: CLAUDE.md + docs/HANDOFF.md(新会话入口)
- 环境: 认证代理→依赖 vendor 本地化;Go 在 ~/.local/go;仅模拟器/未签名
- 待续: M2 mosh, tmux 多 pane, M4 安全(host key/SE)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 10:20:46 +08:00

274 lines
8.3 KiB
Bash
Executable File

#!/bin/bash
set -euo pipefail
cd "$(dirname "$0")/.."
if [ ! -f .root ]; then
echo "[*] malformed project structure"
exit 1
fi
ROOT_DIR=$(pwd)
SOURCE_DIR=${1:-}
ZIG_TARGET=${2:-}
OUTPUT_DIR=${3:-}
ZIG_CPU=${ZIG_CPU:-}
ZIG_BUILD_EXTRA_ARGS=${ZIG_BUILD_EXTRA_ARGS:-}
if [ -z "$SOURCE_DIR" ] || [ -z "$ZIG_TARGET" ] || [ -z "$OUTPUT_DIR" ]; then
echo "Usage: $0 <source_dir> <zig_target> <output_dir>"
exit 1
fi
if [ ! -d "$SOURCE_DIR" ]; then
echo "[!] ghostty source directory not found: $SOURCE_DIR"
exit 1
fi
if [ ! -f "$SOURCE_DIR/include/ghostty.h" ]; then
echo "[!] ghostty header not found: $SOURCE_DIR/include/ghostty.h"
exit 1
fi
if ! command -v zig >/dev/null 2>&1; then
echo "[!] zig not found"
exit 1
fi
REQUESTED_TARGET="$ZIG_TARGET"
IS_ARM64E=0
APPLE_SDK=
APPLE_TARGET=
case "$REQUESTED_TARGET" in
arm64e-macos)
IS_ARM64E=1
ZIG_TARGET="aarch64-macos"
APPLE_SDK="macosx"
APPLE_TARGET="arm64e-apple-macosx13.0"
;;
arm64e-ios)
IS_ARM64E=1
ZIG_TARGET="aarch64-ios"
APPLE_SDK="iphoneos"
APPLE_TARGET="arm64e-apple-ios15.0"
;;
arm64e-ios-macabi)
IS_ARM64E=1
ZIG_TARGET="aarch64-ios-macabi"
APPLE_SDK="macosx"
APPLE_TARGET="arm64e-apple-ios15.0-macabi"
;;
esac
./Script/apply-patches.sh "$SOURCE_DIR"
CACHE_ROOT="${BUILD_CACHE_ROOT:-$ROOT_DIR/build/cache}"
GLOBAL_CACHE_DIR="${ZIG_GLOBAL_CACHE_DIR:-$CACHE_ROOT/zig-global}"
LOCAL_CACHE_DIR="$CACHE_ROOT/$REQUESTED_TARGET/zig-local"
MODULE_CACHE_DIR="${CLANG_MODULE_CACHE_ROOT:-$CACHE_ROOT/clang-module-cache}/$REQUESTED_TARGET"
if [ "$IS_ARM64E" -eq 1 ]; then
if ! command -v xcrun >/dev/null 2>&1; then
echo "[!] xcrun not found for arm64e build"
exit 1
fi
./Script/prepare-arm64e-source.sh "$SOURCE_DIR" "$GLOBAL_CACHE_DIR"
fi
echo "[*] building ghostty static library"
echo " target: $REQUESTED_TARGET"
echo " source: $SOURCE_DIR"
echo " output: $OUTPUT_DIR"
rm -rf "$OUTPUT_DIR" "$LOCAL_CACHE_DIR" "$MODULE_CACHE_DIR"
mkdir -p \
"$OUTPUT_DIR/lib" \
"$OUTPUT_DIR/include" \
"$GLOBAL_CACHE_DIR" \
"$LOCAL_CACHE_DIR" \
"$MODULE_CACHE_DIR"
rm -rf "$SOURCE_DIR/zig-out"
ZIG_BUILD_COMMAND=(
zig build
-Doptimize=${ZIG_OPTIMIZE:-ReleaseFast}
-Dapp-runtime=none
-Demit-exe=false
-Demit-xcframework=false
-Demit-macos-app=false
-Demit-docs=false
-Dsentry=false
-Dcustom-shaders=false
-Dinspector=false
-Dtarget="$ZIG_TARGET"
)
if [ -n "$ZIG_CPU" ]; then
ZIG_BUILD_COMMAND+=("-Dcpu=$ZIG_CPU")
fi
if [ -n "$ZIG_BUILD_EXTRA_ARGS" ]; then
# shellcheck disable=SC2206
EXTRA_ARGS=($ZIG_BUILD_EXTRA_ARGS)
ZIG_BUILD_COMMAND+=("${EXTRA_ARGS[@]}")
fi
(
cd "$SOURCE_DIR"
env \
CLANG_MODULE_CACHE_PATH="$MODULE_CACHE_DIR" \
ZIG_GLOBAL_CACHE_DIR="$GLOBAL_CACHE_DIR" \
ZIG_LOCAL_CACHE_DIR="$LOCAL_CACHE_DIR" \
"${ZIG_BUILD_COMMAND[@]}"
)
find_built_library() {
local preferred_name="$1"
find "$LOCAL_CACHE_DIR/o" -type f -name "$preferred_name" -print 2>/dev/null | sort | tail -n 1
}
LIBRARY_PATH=
if [ -f "$SOURCE_DIR/zig-out/lib/libghostty.a" ]; then
LIBRARY_PATH="$SOURCE_DIR/zig-out/lib/libghostty.a"
fi
if [ -z "$LIBRARY_PATH" ]; then
LIBRARY_PATH=$(find_built_library "libghostty-fat.a")
fi
if [ -z "$LIBRARY_PATH" ]; then
LIBRARY_PATH=$(find_built_library "libghostty.a")
fi
if [ -z "$LIBRARY_PATH" ]; then
echo "[!] failed to locate built libghostty archive in $LOCAL_CACHE_DIR"
if [[ "$ZIG_TARGET" == *macos* || "$ZIG_TARGET" == *ios* || "$ZIG_TARGET" == *tvos* || "$ZIG_TARGET" == *visionos* || "$ZIG_TARGET" == *watchos* ]]; then
echo "[!] note: upstream Ghostty does not install Darwin libghostty for app-runtime=none unless extra build wiring is triggered"
echo "[!] try again with ZIG_BUILD_EXTRA_ARGS='-Demit-xcframework=true' if you want to force Darwin libghostty build graph execution"
fi
find "$LOCAL_CACHE_DIR" -maxdepth 3 -type f | sort | tail -n 50
exit 1
fi
# Resolve std::__1::__libcpp_verbose_abort inside the archive: the Apple
# system libc++ only exports it since iOS 16.3 / macOS 13.3 / tvOS 16.3, and
# Zig's bundled libc++ headers reference it strongly (no availability markup),
# which crashes consumers at launch on older OS versions.
COMPAT_SOURCE="$ROOT_DIR/Script/support/libcxx-verbose-abort-compat.c"
COMPAT_OBJECT="$LOCAL_CACHE_DIR/libcxx-verbose-abort-compat.o"
zig cc -target "$ZIG_TARGET" -Os -fno-sanitize=undefined -c "$COMPAT_SOURCE" -o "$COMPAT_OBJECT"
if [ "$IS_ARM64E" -eq 1 ]; then
RAW_ARCHIVE="$LOCAL_CACHE_DIR/libghostty-arm64.a"
CONVERTED_ARCHIVE="$LOCAL_CACHE_DIR/libghostty-arm64e.a"
CORE_OBJECT="$LOCAL_CACHE_DIR/libghostty-arm64e-core.o"
ARM64E_COMPAT_OBJECT="$LOCAL_CACHE_DIR/arm64e-compat.o"
xcrun libtool -static -no_warning_for_no_symbols -o "$RAW_ARCHIVE" "$LIBRARY_PATH" "$COMPAT_OBJECT"
python3 "$ROOT_DIR/Script/convert-archive-arm64e.py" "$RAW_ARCHIVE" "$CONVERTED_ARCHIVE"
xcrun --sdk "$APPLE_SDK" clang \
-target "$APPLE_TARGET" \
-r \
-nostdlib \
"-Wl,-force_load,$CONVERTED_ARCHIVE" \
-Wl,-alias,_ghostty_app_new,_ghostty_arm64e_core_app_new \
-Wl,-unexported_symbol,_ghostty_app_new \
-Wl,-alias,_ghostty_surface_new,_ghostty_arm64e_core_surface_new \
-Wl,-unexported_symbol,_ghostty_surface_new \
-o "$CORE_OBJECT"
xcrun --sdk "$APPLE_SDK" clang \
-target "$APPLE_TARGET" \
-Os \
-fno-sanitize=undefined \
-I "$SOURCE_DIR/include" \
-c "$ROOT_DIR/Script/support/arm64e-compat.c" \
-o "$ARM64E_COMPAT_OBJECT"
xcrun libtool -static -no_warning_for_no_symbols \
-o "$OUTPUT_DIR/lib/libghostty.a" \
"$CORE_OBJECT" \
"$ARM64E_COMPAT_OBJECT"
if [ "$(lipo -archs "$OUTPUT_DIR/lib/libghostty.a")" != "arm64e" ]; then
echo "[!] built archive is not a single arm64e slice"
exit 1
fi
SYMBOLS=$(nm -gjU "$OUTPUT_DIR/lib/libghostty.a" | sort -u)
for symbol in \
_ghostty_app_new \
_ghostty_surface_new \
_ghostty_arm64e_core_app_new \
_ghostty_arm64e_core_surface_new \
_pa_pthread_cr \
_pa_qs; do
if ! grep -Fxq "$symbol" <<<"$SYMBOLS"; then
echo "[!] arm64e archive missing symbol: $symbol"
exit 1
fi
done
CORE_IMPORTS=$(nm -u "$CORE_OBJECT" | sort -u)
for symbol in _pa_pthread_cr _pa_qs; do
if ! grep -Fxq "$symbol" <<<"$CORE_IMPORTS"; then
echo "[!] arm64e core missing redirected import: $symbol"
exit 1
fi
done
for symbol in _pthread_create _qsort; do
if grep -Fxq "$symbol" <<<"$CORE_IMPORTS"; then
echo "[!] arm64e core contains unsigned callback import: $symbol"
exit 1
fi
done
echo "[*] built pointer-authenticated arm64e archive"
else
ARM64E_COMPAT_OBJECT="$LOCAL_CACHE_DIR/arm64e-compat.o"
case "$ZIG_TARGET" in
*-ios-simulator) COMPAT_SDK="iphonesimulator" ;;
*-ios-macabi | *-macos) COMPAT_SDK="macosx" ;;
*-ios) COMPAT_SDK="iphoneos" ;;
*-tvos-simulator) COMPAT_SDK="appletvsimulator" ;;
*-tvos) COMPAT_SDK="appletvos" ;;
*-visionos-simulator) COMPAT_SDK="xrsimulator" ;;
*-visionos) COMPAT_SDK="xros" ;;
*-watchos-simulator) COMPAT_SDK="watchsimulator" ;;
*-watchos) COMPAT_SDK="watchos" ;;
*)
echo "[!] unsupported compatibility target: $ZIG_TARGET"
exit 1
;;
esac
COMPAT_SDK_PATH=$(xcrun --sdk "$COMPAT_SDK" --show-sdk-path)
zig cc \
-target "$ZIG_TARGET" \
-Os \
-fno-sanitize=undefined \
-isystem "$COMPAT_SDK_PATH/usr/include" \
-I "$SOURCE_DIR/include" \
-c "$ROOT_DIR/Script/support/arm64e-compat.c" \
-o "$ARM64E_COMPAT_OBJECT"
xcrun libtool -static -no_warning_for_no_symbols \
-o "$OUTPUT_DIR/lib/libghostty.a" \
"$LIBRARY_PATH" \
"$COMPAT_OBJECT" \
"$ARM64E_COMPAT_OBJECT"
echo "[*] appended compatibility objects"
fi
cp "$SOURCE_DIR/include/ghostty.h" "$OUTPUT_DIR/include/ghostty.h"
cat >"$OUTPUT_DIR/include/module.modulemap" <<'EOF'
module libghostty {
umbrella header "ghostty.h"
export *
}
EOF
echo "[*] built archive: $OUTPUT_DIR/lib/libghostty.a"