From cf2d5e57780dbd309c8b9f7d4c021efb313ab02f Mon Sep 17 00:00:00 2001 From: deepend Date: Thu, 19 Feb 2026 10:06:49 -0700 Subject: [PATCH] Fixed the macOS launcher errors you hit: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit suppressed noisy defaults read failures for missing preference keys, fixed unsafe/empty test expressions that caused test: argument expected, corrected the gettext app domain from APP=name to APP=zoitechat. Improved launcher behavior for architecture mismatches (Bad CPU type in executable) by detecting exit 126 and printing a clear hint plus file output for ZoiteChat-bin. Updated osx/makebundle.sh so bundling is more Intel/Apple Silicon friendly: dynamically resolves/writes prefix and prefix:enchant (Homebrew Intel vs Apple Silicon layouts), still adapts enchant data path (share/enchant vs share/enchant-2), prints bundled binary architecture after bundling so mismatches are immediately visible. Extended macOS debugging docs with a dedicated “Bad CPU type in executable” section and explicit Intel (x86_64) build commands. --- osx/DEBUGGING.md | 146 ++++++++++++++++++++++++++++++++++++++++++++++ osx/launcher.sh | 46 ++++++++++----- osx/makebundle.sh | 31 +++++++++- readme.md | 4 ++ 4 files changed, 208 insertions(+), 19 deletions(-) create mode 100644 osx/DEBUGGING.md diff --git a/osx/DEBUGGING.md b/osx/DEBUGGING.md new file mode 100644 index 00000000..9b1291f8 --- /dev/null +++ b/osx/DEBUGGING.md @@ -0,0 +1,146 @@ +# Debugging ZoiteChat on macOS (Xcode + CLI) + +If the unsigned `.app` launches but does nothing (or immediately exits), use the steps below to get actionable logs and a debugger session. + +## 1) Build with debug symbols + +ZoiteChat uses Meson. Build a debug configuration first so LLDB can show useful backtraces. + +```bash +meson setup build-macos-debug --buildtype=debug +meson compile -C build-macos-debug +``` + +This project default is `debugoptimized`, but a full `debug` build is better while diagnosing crashes/startup issues. + +## 2) Bundle the app and verify deployment target + +Use the existing bundle script: + +```bash +cd osx +./makebundle.sh +``` + +The generated `Info.plist` should keep: + +- `LSMinimumSystemVersion = 11.0` + +That is the project’s explicit minimum runtime target for macOS 11+. + +## 3) Sanity-check the Mach-O binary in the bundle + +Confirm architecture(s), deployment target, and linked libraries: + +```bash +file ZoiteChat.app/Contents/MacOS/ZoiteChat-bin +otool -l ZoiteChat.app/Contents/MacOS/ZoiteChat-bin | rg -n "LC_BUILD_VERSION|minos|sdk" +otool -L ZoiteChat.app/Contents/MacOS/ZoiteChat-bin +``` + +For widest compatibility, build universal (`arm64` + `x86_64`) or build separately per arch and test each on matching hosts. + +## 4) Ad-hoc sign for local debugging + +Unsigned GUI binaries can fail in unhelpful ways because of hardened runtime/quarantine/Gatekeeper interactions. For local debugging, ad-hoc sign the app: + +```bash +xattr -dr com.apple.quarantine ZoiteChat.app +codesign --force --deep --sign - ZoiteChat.app +codesign --verify --deep --strict --verbose=2 ZoiteChat.app +``` + +## 5) Launch from Terminal first (before Xcode) + +Direct launch exposes stdout/stderr and validates the launcher environment: + +```bash +./ZoiteChat.app/Contents/MacOS/ZoiteChat +``` + +The launcher script sets GTK/Pango/GDK environment variables. If direct launch fails, capture that output first. + +## 6) Debug with LLDB (reliable baseline) + +Debug the real executable inside the bundle: + +```bash +lldb -- ZoiteChat.app/Contents/MacOS/ZoiteChat-bin +(lldb) run +(lldb) bt +``` + +If it exits instantly, set breakpoints on startup entry points (for example `main`) and re-run. + +## 7) Debug with Xcode (if you prefer GUI) + +Xcode works best when opening the executable directly instead of importing build scripts. + +1. **File → Open…** and select `ZoiteChat.app/Contents/MacOS/ZoiteChat-bin`. +2. In **Product → Scheme → Edit Scheme…** + - Executable: `ZoiteChat-bin` + - Working directory: repo root (or `osx/`) + - Add environment variables equivalent to the launcher if needed. +3. Run under debugger. + +If Xcode “runs” but no UI appears, compare its environment to `osx/launcher.sh` and copy missing GTK-related variables into the scheme. + +## 8) Capture macOS crash diagnostics + +Even if no dialog appears, macOS usually logs termination reasons: + +```bash +log stream --style compact --predicate 'process == "ZoiteChat-bin"' +``` + +Also check: + +- `~/Library/Logs/DiagnosticReports/` + +## 9) Frequent root causes for “silent” startup failures + +- Missing GTK runtime libraries in app bundle (`otool -L` shows unresolved paths). +- Incorrect `@rpath`/install names after bundling. +- Running under Rosetta mismatch (x86_64 binary with arm64-only deps or vice versa). +- Quarantine/signature issues on unsigned artifacts. +- Missing `GDK_PIXBUF_MODULE_FILE`, `GTK_IM_MODULE_FILE`, or schema paths. + + +### "Bad CPU type in executable" + +This means the bundled `ZoiteChat-bin` architecture does not match the Mac you are running on. + +- Intel Mac requires `x86_64` +- Apple Silicon requires `arm64` (or Rosetta + `x86_64`) + +Check the binary quickly: + +```bash +file ZoiteChat.app/Contents/MacOS/ZoiteChat-bin +``` + +Build for Intel explicitly when needed: + +```bash +export CFLAGS="-arch x86_64" +export LDFLAGS="-arch x86_64" +meson setup build-macos-intel --buildtype=debug +meson compile -C build-macos-intel +``` + +If your dependency stack supports it, build universal (`arm64` + `x86_64`) and verify with `lipo -info`. + +## 10) Recommended compatibility settings for macOS 11+ + +- Keep `LSMinimumSystemVersion` at `11.0`. +- Build on the oldest macOS SDK/toolchain that still supports your dependencies, or explicitly set: + +```bash +export MACOSX_DEPLOYMENT_TARGET=11.0 +``` + +- Verify with `otool -l` that `minos` is actually `11.0` in the final executable. + +--- + +If you want, we can add an Xcode scheme file to this repo that mirrors `osx/launcher.sh` so “Run” in Xcode behaves exactly like launching the app bundle from Finder/Terminal. diff --git a/osx/launcher.sh b/osx/launcher.sh index d6887fae..601a91f3 100755 --- a/osx/launcher.sh +++ b/osx/launcher.sh @@ -1,13 +1,13 @@ -#!/bin/sh +#!/usr/bin/env bash if test "x$GTK_DEBUG_LAUNCHER" != x; then set -x fi if test "x$GTK_DEBUG_GDB" != x; then - EXEC="gdb --args" + EXEC_PREFIX=(gdb --args) else - EXEC=exec + EXEC_PREFIX=() fi name=`basename "$0"` @@ -50,7 +50,7 @@ export OPENSSL_CONF="/System/Library/OpenSSL/openssl.cnf" export ZOITECHAT_LIBDIR="$bundle_lib/zoitechat/plugins" -APP=name +APP=zoitechat I18NDIR="$bundle_data/locale" # Set the locale-related variables appropriately: unset LANG LC_MESSAGES LC_MONETARY LC_COLLATE @@ -58,7 +58,7 @@ unset LANG LC_MESSAGES LC_MONETARY LC_COLLATE # Has a language ordering been set? # If so, set LC_MESSAGES and LANG accordingly; otherwise skip it. # First step uses sed to clean off the quotes and commas, to change - to _, and change the names for the chinese scripts from "Hans" to CN and "Hant" to TW. -APPLELANGUAGES=`defaults read .GlobalPreferences AppleLanguages | sed -En -e 's/\-/_/' -e 's/Hant/TW/' -e 's/Hans/CN/' -e 's/[[:space:]]*\"?([[:alnum:]_]+)\"?,?/\1/p' ` +APPLELANGUAGES=`defaults read .GlobalPreferences AppleLanguages 2>/dev/null | sed -En -e 's/\-/_/' -e 's/Hant/TW/' -e 's/Hans/CN/' -e 's/[[:space:]]*\"?([[:alnum:]_]+)\"?,?/\1/p' ` if test "$APPLELANGUAGES"; then # A language ordering exists. # Test, item per item, to see whether there is an corresponding locale. @@ -89,26 +89,26 @@ fi unset APPLELANGUAGES L # If we didn't get a language from the language list, try the Collation preference, in case it's the only setting that exists. -APPLECOLLATION=`defaults read .GlobalPreferences AppleCollationOrder` -if test -z ${LANG} -a -n $APPLECOLLATION; then +APPLECOLLATION=`defaults read .GlobalPreferences AppleCollationOrder 2>/dev/null || true` +if test -z "${LANG:-}" -a -n "${APPLECOLLATION:-}"; then if test -f "$I18NDIR/${APPLECOLLATION:0:2}/LC_MESSAGES/$APP.mo"; then export LANG=${APPLECOLLATION:0:2} fi fi -if test ! -z $APPLECOLLATION; then +if test -n "${APPLECOLLATION:-}"; then export LC_COLLATE=$APPLECOLLATION fi unset APPLECOLLATION # Continue by attempting to find the Locale preference. -APPLELOCALE=`defaults read .GlobalPreferences AppleLocale` +APPLELOCALE=`defaults read .GlobalPreferences AppleLocale 2>/dev/null || true` if test -f "$I18NDIR/${APPLELOCALE:0:5}/LC_MESSAGES/$APP.mo"; then - if test -z $LANG; then + if test -z "${LANG:-}"; then export LANG="${APPLELOCALE:0:5}" fi -elif test -z $LANG -a -f "$I18NDIR/${APPLELOCALE:0:2}/LC_MESSAGES/$APP.mo"; then +elif test -z "${LANG:-}" -a -f "$I18NDIR/${APPLELOCALE:0:2}/LC_MESSAGES/$APP.mo"; then export LANG="${APPLELOCALE:0:2}" fi @@ -116,20 +116,20 @@ fi #5-character locale to avoid the "Locale not supported by C library" #warning from Gtk -- even though Gtk will translate with a #two-character code. -if test -n $LANG; then +if test -n "${LANG:-}"; then #If the language code matches the applelocale, then that's the message #locale; otherwise, if it's longer than two characters, then it's #probably a good message locale and we'll go with it. - if test $LANG == ${APPLELOCALE:0:5} -o $LANG != ${LANG:0:2}; then + if test "$LANG" = "${APPLELOCALE:0:5}" -o "$LANG" != "${LANG:0:2}"; then export LC_MESSAGES=$LANG #Next try if the Applelocale is longer than 2 chars and the language #bit matches $LANG - elif test $LANG == ${APPLELOCALE:0:2} -a $APPLELOCALE > ${APPLELOCALE:0:2}; then + elif test "$LANG" = "${APPLELOCALE:0:2}" -a "$APPLELOCALE" \> "${APPLELOCALE:0:2}"; then export LC_MESSAGES=${APPLELOCALE:0:5} #Fail. Get a list of the locales in $PREFIX/share/locale that match #our two letter language code and pick the first one, special casing #english to set en_US - elif test $LANG == "en"; then + elif test "$LANG" = "en"; then export LC_MESSAGES="en_US" else LOC=`find $PREFIX/share/locale -name $LANG???` @@ -181,4 +181,18 @@ if /bin/expr "x$1" : '^x-psn_' > /dev/null; then shift 1 fi -$EXEC "$bundle_contents/MacOS/$name-bin" "$@" $EXTRA_ARGS +BIN_PATH="$bundle_contents/MacOS/$name-bin" +if test ${#EXEC_PREFIX[@]} -gt 0; then + "${EXEC_PREFIX[@]}" "$BIN_PATH" "$@" $EXTRA_ARGS +else + "$BIN_PATH" "$@" $EXTRA_ARGS +fi +status=$? +if test "$status" -eq 126; then + echo "error: $BIN_PATH could not execute on this Mac (possible architecture mismatch)." >&2 + if command -v file >/dev/null 2>&1; then + file "$BIN_PATH" >&2 || true + fi + echo "hint: build ZoiteChat for this architecture (x86_64 on Intel, arm64 on Apple Silicon) or as a universal binary." >&2 +fi +exit "$status" diff --git a/osx/makebundle.sh b/osx/makebundle.sh index 377769b6..30be7eda 100755 --- a/osx/makebundle.sh +++ b/osx/makebundle.sh @@ -36,9 +36,29 @@ rm -f ./*.app.zip # - some have no share-level config dir at all # Keep the bundle definition in sync with what's actually available so # gtk-mac-bundler doesn't fail on a missing source path. -ENCHANT_PREFIX_PATH="${ENCHANT_PREFIX:-}" -if [ -z "$ENCHANT_PREFIX_PATH" ] && command -v brew >/dev/null 2>&1; then - ENCHANT_PREFIX_PATH="$(brew --prefix enchant 2>/dev/null || true)" + +# Resolve package-manager prefix dynamically so Intel (/usr/local) and +# Apple Silicon (/opt/homebrew) hosts both bundle correctly. +BUNDLE_PREFIX="${BUNDLE_PREFIX:-}" +if [ -z "$BUNDLE_PREFIX" ] && command -v brew >/dev/null 2>&1; then + BUNDLE_PREFIX="$(brew --prefix 2>/dev/null || true)" +fi +if [ -z "$BUNDLE_PREFIX" ]; then + BUNDLE_PREFIX="/usr/local" +fi + +ENCHANT_PREFIX_DEFAULT="${BUNDLE_PREFIX}/opt/enchant" +ENCHANT_PREFIX_PATH="${ENCHANT_PREFIX:-$ENCHANT_PREFIX_DEFAULT}" + +perl -0pi -e 's|()[^<]+()|$1'"$BUNDLE_PREFIX"'$2|s' "$BUNDLE_DEF" +perl -0pi -e 's|()[^<]+()|$1'"$ENCHANT_PREFIX_PATH"'$2|s' "$BUNDLE_DEF" + +if command -v brew >/dev/null 2>&1; then + BREW_ENCHANT_PREFIX="$(brew --prefix enchant 2>/dev/null || true)" + if [ -n "$BREW_ENCHANT_PREFIX" ]; then + ENCHANT_PREFIX_PATH="$BREW_ENCHANT_PREFIX" + perl -0pi -e 's|()[^<]+()|$1'"$ENCHANT_PREFIX_PATH"'$2|s' "$BUNDLE_DEF" + fi fi if [ -n "$ENCHANT_PREFIX_PATH" ]; then @@ -72,5 +92,10 @@ if [ ! -d "$APP_NAME" ]; then exit 1 fi +if command -v file >/dev/null 2>&1; then + echo "Bundled binary architecture:" + file "$APP_NAME/Contents/MacOS/ZoiteChat-bin" || true +fi + echo "Compressing bundle" zip -9rXq "./ZoiteChat-$(git describe --tags).app.zip" "./$APP_NAME" diff --git a/readme.md b/readme.md index cd148c8b..33dd181b 100644 --- a/readme.md +++ b/readme.md @@ -52,3 +52,7 @@ provide binary packages linked to the OpenSSL libraries, provided that all other requirements of the GPL are met. See file COPYING for details. + +## macOS debugging + +If you are troubleshooting local macOS build/run/debug issues (including Xcode setup), see `osx/DEBUGGING.md`.