diff --git a/.github/workflows/macos-build.yml b/.github/workflows/macos-build.yml
index 404ace12..f8612418 100644
--- a/.github/workflows/macos-build.yml
+++ b/.github/workflows/macos-build.yml
@@ -35,12 +35,13 @@ jobs:
(cd /tmp/gtk-mac-bundler && make install)
fi
- - name: Configure
+ - name: Configure (arm64 + x86_64)
run: |
set -eux
PREFIX="$(brew --prefix)"
- rm -rf build
- meson setup build \
+ rm -rf build-macos-arm64 build-macos-x86_64
+
+ CFLAGS="-arch arm64" LDFLAGS="-arch arm64" meson setup build-macos-arm64 \
--prefix="$PREFIX" \
-Dgtk3=true \
-Dtext-frontend=true \
@@ -49,30 +50,40 @@ jobs:
-Dwith-python=python3 \
-Dauto_features=enabled
- - name: Build
+ CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" meson setup build-macos-x86_64 \
+ --prefix="$PREFIX" \
+ -Dgtk3=true \
+ -Dtext-frontend=true \
+ -Dlibcanberra=disabled \
+ -Dwith-perl=perl \
+ -Dwith-python=python3 \
+ -Dauto_features=enabled
+
+ - name: Build (arm64 + x86_64)
run: |
set -eux
- meson compile -C build
+ CFLAGS="-arch arm64" LDFLAGS="-arch arm64" meson compile -C build-macos-arm64
+ CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" meson compile -C build-macos-x86_64
- - name: Install for bundling
+ - name: Install for bundling (arm64 runtime)
run: |
set -eux
- sudo meson install -C build
+ sudo meson install -C build-macos-arm64
- - name: Package unsigned .app
+ - name: Package unsigned .app (universal binary)
run: |
set -eux
VERSION="$(git describe --tags --always)"
PREFIX="$(brew --prefix)"
ENCHANT_PREFIX="$(brew --prefix enchant)"
- export PREFIX ENCHANT_PREFIX
+ export VERSION PREFIX ENCHANT_PREFIX
- sed "s/@VERSION@/${VERSION}/g" osx/Info.plist.in > osx/Info.plist
-
- perl -0pi -e 's|.*?|$ENV{PREFIX}|s' osx/zoitechat.bundle
- perl -0pi -e 's|.*?|$ENV{ENCHANT_PREFIX}|s' osx/zoitechat.bundle
-
- (cd osx && ./makebundle.sh)
+ (
+ cd osx
+ UNIVERSAL=1 \
+ UNIVERSAL_BINARIES="../build-macos-arm64/src/fe-gtk/zoitechat ../build-macos-x86_64/src/fe-gtk/zoitechat" \
+ ./makebundle.sh
+ )
mv osx/ZoiteChat-*.app.zip ./
- name: Upload unsigned macOS app artifact
diff --git a/osx/DEBUGGING.md b/osx/DEBUGGING.md
index 9b1291f8..91b036fc 100644
--- a/osx/DEBUGGING.md
+++ b/osx/DEBUGGING.md
@@ -130,6 +130,25 @@ meson compile -C build-macos-intel
If your dependency stack supports it, build universal (`arm64` + `x86_64`) and verify with `lipo -info`.
+Example with this repo's scripts:
+
+```bash
+PREFIX="$(brew --prefix)"
+
+CFLAGS="-arch arm64" LDFLAGS="-arch arm64" meson setup build-macos-arm64 --prefix="$PREFIX"
+CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" meson setup build-macos-x86_64 --prefix="$PREFIX"
+
+CFLAGS="-arch arm64" LDFLAGS="-arch arm64" meson compile -C build-macos-arm64
+CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" meson compile -C build-macos-x86_64
+
+sudo meson install -C build-macos-arm64
+
+cd osx
+UNIVERSAL=1 \
+UNIVERSAL_BINARIES="../build-macos-arm64/src/fe-gtk/zoitechat ../build-macos-x86_64/src/fe-gtk/zoitechat" \
+./makebundle.sh
+```
+
## 10) Recommended compatibility settings for macOS 11+
- Keep `LSMinimumSystemVersion` at `11.0`.
diff --git a/osx/makebundle.sh b/osx/makebundle.sh
index b8a79214..9d05332e 100755
--- a/osx/makebundle.sh
+++ b/osx/makebundle.sh
@@ -9,7 +9,15 @@ BUNDLE_DEF="zoitechat.bundle"
APP_NAME="ZoiteChat.app"
HOST_ARCH="$(uname -m 2>/dev/null || echo unknown)"
-TARGET_ARCHES="${TARGET_ARCHES:-$HOST_ARCH}"
+if [ -z "${TARGET_ARCHES+x}" ]; then
+ TARGET_ARCHES="$HOST_ARCH"
+fi
+UNIVERSAL_BINARIES="${UNIVERSAL_BINARIES:-}"
+UNIVERSAL_BUILD_DIRS="${UNIVERSAL_BUILD_DIRS:-../build-macos-arm64 ../build-macos-x86_64}"
+
+if [ "${UNIVERSAL:-0}" = "1" ]; then
+ TARGET_ARCHES="arm64 x86_64"
+fi
# Expected prefixes for macOS GTK dependencies:
# - Homebrew: /opt/homebrew (Apple Silicon) or /usr/local (Intel)
@@ -97,6 +105,44 @@ fi
BIN_PATH="$APP_NAME/Contents/MacOS/ZoiteChat-bin"
+if [ "${UNIVERSAL:-0}" = "1" ] && [ -z "$UNIVERSAL_BINARIES" ]; then
+ for build_dir in $UNIVERSAL_BUILD_DIRS; do
+ candidate="$build_dir/src/fe-gtk/zoitechat"
+ if [ -f "$candidate" ]; then
+ UNIVERSAL_BINARIES="${UNIVERSAL_BINARIES:+$UNIVERSAL_BINARIES }$candidate"
+ fi
+ done
+
+ if [ -z "$UNIVERSAL_BINARIES" ]; then
+ cat >&2 <<'MSG'
+error: UNIVERSAL=1 requested, but no source binaries were found.
+Set UNIVERSAL_BINARIES to one or more architecture-specific zoitechat binaries,
+or place builds at:
+ ../build-macos-arm64/src/fe-gtk/zoitechat
+ ../build-macos-x86_64/src/fe-gtk/zoitechat
+MSG
+ exit 1
+ fi
+fi
+
+if [ -n "$UNIVERSAL_BINARIES" ]; then
+ if ! command -v lipo >/dev/null 2>&1; then
+ echo "error: UNIVERSAL_BINARIES requires lipo, but lipo is unavailable" >&2
+ exit 1
+ fi
+
+ for binary in $UNIVERSAL_BINARIES; do
+ if [ ! -f "$binary" ]; then
+ echo "error: universal source binary not found: $binary" >&2
+ exit 1
+ fi
+ done
+
+ echo "Creating universal ZoiteChat-bin from: $UNIVERSAL_BINARIES"
+ # shellcheck disable=SC2086
+ lipo -create $UNIVERSAL_BINARIES -output "$BIN_PATH"
+fi
+
if command -v lipo >/dev/null 2>&1; then
BIN_ARCHS="$(lipo -archs "$BIN_PATH" 2>/dev/null || true)"
if [ -z "$BIN_ARCHS" ]; then