Skip to content

Instantly share code, notes, and snippets.

@pojntfx
Last active March 17, 2026 06:57
Show Gist options
  • Select an option

  • Save pojntfx/bc688a887a940e3e458684df62058843 to your computer and use it in GitHub Desktop.

Select an option

Save pojntfx/bc688a887a940e3e458684df62058843 to your computer and use it in GitHub Desktop.
Cross-Compile a puregotk app from Linux to macOS and run it via SSH
#!/bin/bash
set -ex
GOOS=darwin GOARCH=arm64 go build -x -o /tmp/sessions -ldflags="-X 'main.LocaleDir=/Users/pojntfx/Projects/sessions/po' -X 'main.SchemaDir=/Users/pojntfx/Projects/sessions/assets/resources'" . && scp /tmp/sessions pojntfx@[2001:569:7bcc:d80:98:6876:d203:c3b9]:/tmp/sessions && ssh -tt pojntfx@2001:569:7bcc:d80:98:6876:d203:c3b9 'codesign -s - /tmp/sessions && /tmp/sessions'
#!/bin/bash
set -ex
APP_NAME="Sessions"
APP_ID="com.pojtinger.felicitas.Sessions"
APP_VERSION="0.1.14"
BINARY_NAME="sessions"
SRC_DIR="$(cd "$(dirname "$0")" && pwd)"
OUT_DIR="$SRC_DIR/out"
WORK="$(mktemp -d)"
trap "rm -rf $WORK" EXIT
BOTTLE_CACHE="$SRC_DIR/.bottle-cache"
BOTTLE_ARCH="arm64_tahoe"
FORMULAS=(
pcre2 libpng pixman fribidi graphite2 jpeg-turbo xz lz4 lzo
libunistring libdatrie libepoxy libsass libfyaml
libxau libxdmcp libxcb libx11 libxext libxrender
icu4c@78 gettext glib freetype fontconfig zstd libtiff cairo
harfbuzz libthai pango gdk-pixbuf graphene librsvg libxmlb appstream
gtk4 libadwaita
)
echo "Generating resources..."
(cd "$SRC_DIR" && go generate ./...)
echo "Building darwin/arm64..."
(cd "$SRC_DIR" && CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
go build -o "$WORK/$BINARY_NAME" \
-ldflags="-X 'main.LocaleDir=../Resources/locale' -X 'main.SchemaDir=../Resources/schemas'" .)
echo "Downloading Homebrew bottles..."
FWDIR="$WORK/fw"
mkdir -p "$BOTTLE_CACHE" "$FWDIR"
for formula in "${FORMULAS[@]}"; do
key="${formula}-${BOTTLE_ARCH}"
if [ ! -f "$BOTTLE_CACHE/${key}.tar.gz" ]; then
echo " $formula..."
api=$(curl -sf "https://formulae.brew.sh/api/formula/${formula}.json")
url=$(echo "$api" | grep -o "\"${BOTTLE_ARCH}\":{\"url\":\"[^\"]*\"" | grep -o 'https://[^"]*')
if [ -z "$url" ]; then
url=$(echo "$api" | grep -o '"all":{"url":"[^"]*"' | grep -o 'https://[^"]*')
fi
[ -z "$url" ] && echo " SKIP: $formula" && continue
repo=$(echo "$url" | sed -n 's|https://ghcr.io/v2/\(.*\)/blobs/.*|\1|p')
tok=$(curl -sf "https://ghcr.io/token?scope=repository:${repo}:pull" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
curl -sfL -H "Authorization: Bearer $tok" -H "Accept: application/vnd.oci.image.layer.v1.tar+gzip" -o "$BOTTLE_CACHE/${key}.tar.gz" "$url"
fi
tar xf "$BOTTLE_CACHE/${key}.tar.gz" -C "$WORK"
find "$WORK" -name '*.dylib' -exec cp -n {} "$FWDIR/" \;
find "$WORK" -mindepth 1 -maxdepth 1 -type d ! -name fw -exec rm -rf {} + 2>/dev/null || true
done
echo "Assembling .app bundle..."
APP="$WORK/$APP_NAME.app"
mkdir -p "$APP/Contents/"{MacOS,Resources,Frameworks}
cp "$FWDIR"/*.dylib "$APP/Contents/Frameworks/"
chmod u+w "$APP/Contents/Frameworks/"*.dylib
cp "$WORK/$BINARY_NAME" "$APP/Contents/MacOS/${BINARY_NAME}-bin"
cat > "$APP/Contents/MacOS/$BINARY_NAME" <<'LAUNCHER'
#!/bin/bash
DIR="$(cd "$(dirname "$0")" && pwd)"
export PUREGOTK_LIB_FOLDER="$DIR/../Frameworks"
export DYLD_LIBRARY_PATH="$DIR/../Frameworks${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"
cd "$DIR"
exec "$DIR/sessions-bin" "$@"
LAUNCHER
chmod +x "$APP/Contents/MacOS/$BINARY_NAME"
for mo in "$SRC_DIR"/po/*/LC_MESSAGES/*.mo; do
[ -f "$mo" ] || continue
lang="$(basename "$(dirname "$(dirname "$mo")")")"
mkdir -p "$APP/Contents/Resources/locale/$lang/LC_MESSAGES"
cp "$mo" "$APP/Contents/Resources/locale/$lang/LC_MESSAGES/"
done
mkdir -p "$APP/Contents/Resources/schemas"
cp "$SRC_DIR/assets/resources/gschemas.compiled" "$APP/Contents/Resources/schemas/"
ICONS="$WORK/icons"
mkdir -p "$ICONS"
for s in 16 32 128 256 512; do
rsvg-convert -w $s -h $s "$SRC_DIR/assets/meta/icon.svg" -o "$ICONS/${s}.png"
done
png2icns "$APP/Contents/Resources/$APP_NAME.icns" "$ICONS/16.png" "$ICONS/32.png" "$ICONS/128.png" "$ICONS/256.png" "$ICONS/512.png"
cat > "$APP/Contents/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>CFBundleName</key><string>${APP_NAME}</string>
<key>CFBundleDisplayName</key><string>${APP_NAME}</string>
<key>CFBundleIdentifier</key><string>${APP_ID}</string>
<key>CFBundleVersion</key><string>${APP_VERSION}</string>
<key>CFBundleShortVersionString</key><string>${APP_VERSION}</string>
<key>CFBundleExecutable</key><string>${BINARY_NAME}</string>
<key>CFBundleIconFile</key><string>${APP_NAME}</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleSignature</key><string>????</string>
<key>NSHighResolutionCapable</key><true/>
<key>LSMinimumSystemVersion</key><string>11.0</string>
</dict>
</plist>
PLIST
echo -n "APPL????" > "$APP/Contents/PkgInfo"
echo "Signing Mach-O files..."
for f in "$APP/Contents/Frameworks/"*.dylib; do rcodesign sign "$f"; done
rcodesign sign "$APP/Contents/MacOS/${BINARY_NAME}-bin"
echo "Creating DMG..."
mkdir -p "$OUT_DIR"
STAGING="$WORK/dmg"
mkdir -p "$STAGING"
cp -a "$APP" "$STAGING/"
ln -s /Applications "$STAGING/Applications"
genisoimage -V "$APP_NAME" -D -R -apple -no-pad -o "$OUT_DIR/$APP_NAME.dmg" "$STAGING"
echo "$OUT_DIR/$APP_NAME.dmg"
MAC_USER="${MAC_USER:-pojntfx}"
MAC_ADDR="${MAC_ADDR:-2001:569:7bcc:d80:98:6876:d203:c3b9}"
echo "Deploying to Mac..."
rsync -avz --progress "$OUT_DIR/$APP_NAME.dmg" "${MAC_USER}@[${MAC_ADDR}]:/tmp/$APP_NAME.dmg"
ssh -tt "${MAC_USER}@${MAC_ADDR}" "
hdiutil detach /Volumes/$APP_NAME 2>/dev/null || true
hdiutil attach /tmp/$APP_NAME.dmg
rm -rf /tmp/$APP_NAME.app
cp -R /Volumes/$APP_NAME/$APP_NAME.app /tmp/$APP_NAME.app
hdiutil detach /Volumes/$APP_NAME
open /tmp/$APP_NAME.app
"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment