- macOS plugin: Swift bridge + universal xcframework (arm64 + x86_64) - macOS podspec with direct force_load (no script phase needed — single slice) - Make TailscaleStart() idempotent — return success if already started - Document macOS entitlements (network.client + network.server) - Build script: ./build_go.sh [ios|macos|all] Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
199 lines
6.9 KiB
Bash
Executable File
199 lines
6.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build Go static libraries for iOS and macOS using go build -buildmode=c-archive.
|
|
#
|
|
# Prerequisites:
|
|
# - Go 1.23+
|
|
# - Xcode with iOS + macOS SDKs
|
|
#
|
|
# Usage:
|
|
# ./build_go.sh # build all platforms
|
|
# ./build_go.sh ios # iOS only
|
|
# ./build_go.sh macos # macOS only
|
|
|
|
set -euo pipefail
|
|
|
|
export PATH="${GOPATH:-$HOME/go}/bin:$PATH"
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
GO_DIR="$SCRIPT_DIR/ios/Go"
|
|
MIN_IOS="14.0"
|
|
MIN_MACOS="12.0"
|
|
|
|
# Omit Tailscale features we don't need — we only use tsnet.Dial() for proxying.
|
|
OMIT_TAGS="ts_omit_ssh,ts_omit_drive,ts_omit_taildrop,ts_omit_serve"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_webclient,ts_omit_capture,ts_omit_appconnectors"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_debug,ts_omit_doctor,ts_omit_portlist,ts_omit_posture"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_cli,ts_omit_kube,ts_omit_aws,ts_omit_bird"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_synology,ts_omit_tpm,ts_omit_tap,ts_omit_conn25"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_qrcodes,ts_omit_relayserver,ts_omit_systray"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_webbrowser,ts_omit_completion,ts_omit_completion_scripts"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_colorable,ts_omit_clientupdate,ts_omit_wakeonlan"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_usermetrics,ts_omit_desktop_sessions,ts_omit_ace"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_acme,ts_omit_hujsonconf,ts_omit_tailnetlock"
|
|
OMIT_TAGS="$OMIT_TAGS,ts_omit_netlog,ts_omit_syspolicy,ts_omit_cachenetmap"
|
|
|
|
PLATFORM="${1:-all}"
|
|
|
|
cd "$GO_DIR"
|
|
echo "==> Tidying Go modules..."
|
|
go mod tidy
|
|
|
|
# Helper: create a framework bundle from a static library
|
|
create_framework() {
|
|
local lib_path="$1"
|
|
local header_path="$2"
|
|
local framework_dir="$3"
|
|
|
|
mkdir -p "$framework_dir/Headers" "$framework_dir/Modules"
|
|
cp "$lib_path" "$framework_dir/TailscaleKit"
|
|
cp "$header_path" "$framework_dir/Headers/tailscale.h"
|
|
|
|
cat > "$framework_dir/Modules/module.modulemap" <<'MODMAP'
|
|
framework module TailscaleKit {
|
|
header "tailscale.h"
|
|
export *
|
|
}
|
|
MODMAP
|
|
|
|
cat > "$framework_dir/Info.plist" <<PLIST
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>CFBundleIdentifier</key>
|
|
<string>io.svrnty.TailscaleKit</string>
|
|
<key>CFBundleName</key>
|
|
<string>TailscaleKit</string>
|
|
<key>CFBundleVersion</key>
|
|
<string>1</string>
|
|
<key>CFBundlePackageType</key>
|
|
<string>FMWK</string>
|
|
</dict>
|
|
</plist>
|
|
PLIST
|
|
}
|
|
|
|
# ============================================================
|
|
# iOS
|
|
# ============================================================
|
|
build_ios() {
|
|
local BUILD_DIR="$SCRIPT_DIR/ios/build"
|
|
local OUTPUT="$SCRIPT_DIR/ios/TailscaleKit.xcframework"
|
|
|
|
rm -rf "$BUILD_DIR" "$OUTPUT"
|
|
mkdir -p "$BUILD_DIR"
|
|
|
|
# iOS device (arm64)
|
|
echo "==> [iOS] Building for device (arm64)..."
|
|
local IPHONEOS_SDK=$(xcrun --sdk iphoneos --show-sdk-path)
|
|
local IPHONEOS_CC=$(xcrun --sdk iphoneos --find clang)
|
|
|
|
CGO_ENABLED=1 GOOS=ios GOARCH=arm64 \
|
|
CC="$IPHONEOS_CC" \
|
|
CGO_CFLAGS="-isysroot $IPHONEOS_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS" \
|
|
CGO_LDFLAGS="-isysroot $IPHONEOS_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS" \
|
|
go build -buildmode=c-archive -tags "$OMIT_TAGS" -ldflags="-s -w" \
|
|
-o "$BUILD_DIR/ios-arm64/libtailscale.a" .
|
|
|
|
create_framework \
|
|
"$BUILD_DIR/ios-arm64/libtailscale.a" \
|
|
"$BUILD_DIR/ios-arm64/libtailscale.h" \
|
|
"$BUILD_DIR/ios-arm64/TailscaleKit.framework"
|
|
|
|
# iOS simulator (arm64)
|
|
echo "==> [iOS] Building for simulator (arm64)..."
|
|
local SIM_SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
|
|
local SIM_CC=$(xcrun --sdk iphonesimulator --find clang)
|
|
|
|
CGO_ENABLED=1 GOOS=ios GOARCH=arm64 \
|
|
CC="$SIM_CC" \
|
|
CGO_CFLAGS="-isysroot $SIM_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS -target arm64-apple-ios${MIN_IOS}-simulator" \
|
|
CGO_LDFLAGS="-isysroot $SIM_SDK -arch arm64 -miphoneos-version-min=$MIN_IOS -target arm64-apple-ios${MIN_IOS}-simulator" \
|
|
go build -buildmode=c-archive -tags "$OMIT_TAGS" -ldflags="-s -w" \
|
|
-o "$BUILD_DIR/ios-sim-arm64/libtailscale.a" .
|
|
|
|
create_framework \
|
|
"$BUILD_DIR/ios-sim-arm64/libtailscale.a" \
|
|
"$BUILD_DIR/ios-sim-arm64/libtailscale.h" \
|
|
"$BUILD_DIR/ios-sim-arm64/TailscaleKit.framework"
|
|
|
|
# Create xcframework
|
|
echo "==> [iOS] Creating xcframework..."
|
|
xcodebuild -create-xcframework \
|
|
-framework "$BUILD_DIR/ios-arm64/TailscaleKit.framework" \
|
|
-framework "$BUILD_DIR/ios-sim-arm64/TailscaleKit.framework" \
|
|
-output "$OUTPUT"
|
|
|
|
rm -rf "$BUILD_DIR"
|
|
cp "$OUTPUT/ios-arm64/TailscaleKit.framework/Headers/tailscale.h" "$SCRIPT_DIR/ios/Classes/tailscale.h"
|
|
|
|
echo "==> [iOS] Done: $OUTPUT"
|
|
du -sh "$OUTPUT"
|
|
}
|
|
|
|
# ============================================================
|
|
# macOS
|
|
# ============================================================
|
|
build_macos() {
|
|
local BUILD_DIR="$SCRIPT_DIR/macos/build"
|
|
local OUTPUT="$SCRIPT_DIR/macos/TailscaleKit.xcframework"
|
|
|
|
rm -rf "$BUILD_DIR" "$OUTPUT"
|
|
mkdir -p "$BUILD_DIR"
|
|
|
|
local MACOS_SDK=$(xcrun --sdk macosx --show-sdk-path)
|
|
local MACOS_CC=$(xcrun --sdk macosx --find clang)
|
|
|
|
# macOS arm64
|
|
echo "==> [macOS] Building for arm64..."
|
|
CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 \
|
|
CC="$MACOS_CC" \
|
|
CGO_CFLAGS="-isysroot $MACOS_SDK -arch arm64 -mmacosx-version-min=$MIN_MACOS" \
|
|
CGO_LDFLAGS="-isysroot $MACOS_SDK -arch arm64 -mmacosx-version-min=$MIN_MACOS" \
|
|
go build -buildmode=c-archive -tags "$OMIT_TAGS" -ldflags="-s -w" \
|
|
-o "$BUILD_DIR/macos-arm64/libtailscale.a" .
|
|
|
|
# macOS amd64
|
|
echo "==> [macOS] Building for amd64..."
|
|
CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 \
|
|
CC="$MACOS_CC" \
|
|
CGO_CFLAGS="-isysroot $MACOS_SDK -arch x86_64 -mmacosx-version-min=$MIN_MACOS" \
|
|
CGO_LDFLAGS="-isysroot $MACOS_SDK -arch x86_64 -mmacosx-version-min=$MIN_MACOS" \
|
|
go build -buildmode=c-archive -tags "$OMIT_TAGS" -ldflags="-s -w" \
|
|
-o "$BUILD_DIR/macos-amd64/libtailscale.a" .
|
|
|
|
# Create universal binary with lipo
|
|
echo "==> [macOS] Creating universal binary (arm64 + x86_64)..."
|
|
mkdir -p "$BUILD_DIR/macos-universal"
|
|
lipo -create \
|
|
"$BUILD_DIR/macos-arm64/libtailscale.a" \
|
|
"$BUILD_DIR/macos-amd64/libtailscale.a" \
|
|
-output "$BUILD_DIR/macos-universal/libtailscale.a"
|
|
|
|
create_framework \
|
|
"$BUILD_DIR/macos-universal/libtailscale.a" \
|
|
"$BUILD_DIR/macos-arm64/libtailscale.h" \
|
|
"$BUILD_DIR/macos-universal/TailscaleKit.framework"
|
|
|
|
# Create xcframework (single macOS slice)
|
|
echo "==> [macOS] Creating xcframework..."
|
|
xcodebuild -create-xcframework \
|
|
-framework "$BUILD_DIR/macos-universal/TailscaleKit.framework" \
|
|
-output "$OUTPUT"
|
|
|
|
rm -rf "$BUILD_DIR"
|
|
|
|
echo "==> [macOS] Done: $OUTPUT"
|
|
du -sh "$OUTPUT"
|
|
}
|
|
|
|
# ============================================================
|
|
# Main
|
|
# ============================================================
|
|
case "$PLATFORM" in
|
|
ios) build_ios ;;
|
|
macos) build_macos ;;
|
|
all) build_ios; build_macos ;;
|
|
*) echo "Usage: $0 [ios|macos|all]"; exit 1 ;;
|
|
esac
|