From 759d0be26c675142410d90206c87a70c90c0eed7 Mon Sep 17 00:00:00 2001 From: Alessandro Saccoia Date: Fri, 10 Apr 2026 10:28:38 +0200 Subject: [PATCH] Fix macOS packaging with Homebrew Qt on Apple Silicon --- INSTALL | 12 +++++--- mac_deploy.sh | 76 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/INSTALL b/INSTALL index 4a188b3c..0a0593c1 100644 --- a/INSTALL +++ b/INSTALL @@ -20,14 +20,18 @@ Linux: 'alternate/directory' before all installation names. macOS: - 1. `cmake -B build -S .' to create a location for the build and then + 1. Install Qt 6 if it is not already available. With Homebrew this is + typically `brew install qt'. + + 2. `cmake -B build -S .' to create a location for the build and then configure the program. There are more options you can pass to CMake, see below for details. - 2. `cmake --build build' to compile the program. + 3. `cmake --build build' to compile the program. - 3. Run `mac_deploy.sh' from inside the build directory to create a disk - image of the program. + 4. Run `mac_deploy.sh' from inside the build directory to create a disk + image of the program. The script automatically detects Qt tools and + translations from a Homebrew Qt installation. Windows: 1. `cmake -B ..\build -S .' to create a location for the build and then diff --git a/mac_deploy.sh b/mac_deploy.sh index 1086d0bc..7eff0a0c 100755 --- a/mac_deploy.sh +++ b/mac_deploy.sh @@ -1,12 +1,64 @@ #!/bin/bash +set -euo pipefail + APP='FocusWriter' BUNDLE="$APP.app" VERSION='1.9.0' +find_qt_tool() { + local tool + for tool in "$@"; do + if command -v "$tool" >/dev/null 2>&1; then + command -v "$tool" + return 0 + elif [ -n "${QTDIR:-}" ] && [ -x "${QTDIR}/bin/${tool}" ]; then + printf '%s\n' "${QTDIR}/bin/${tool}" + return 0 + fi + done + + return 1 +} + +copy_qt_plugin() { + local plugin="$1" + local source="${QT_PLUGINS}/${plugin}" + local target="${APP}/${BUNDLE}/Contents/PlugIns/${plugin}" + + if [ ! -f "$source" ]; then + echo "Missing Qt plugin: $source" >&2 + exit 1 + fi + + mkdir -p "$(dirname "$target")" + cp "$source" "$target" + DEPLOY_EXECUTABLES+=("-executable=${SCRIPT_DIR}/${target}") +} + # Locate deployment script BIN_DIR=$(pwd) -cd $(dirname "${BASH_SOURCE[0]}") +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd "$SCRIPT_DIR" + +QTPATHS_BIN=$(find_qt_tool qtpaths qtpaths6) || { + echo 'Unable to find qtpaths. Install Qt 6 and ensure its tools are in PATH or set QTDIR.' >&2 + exit 1 +} + +QT_PREFIX=$("$QTPATHS_BIN" --query QT_INSTALL_PREFIX) +QT_LIBS=$("$QTPATHS_BIN" --query QT_INSTALL_LIBS) +QT_PLUGINS=$("$QTPATHS_BIN" --query QT_INSTALL_PLUGINS) +QT_TRANSLATIONS=$("$QTPATHS_BIN" --query QT_INSTALL_TRANSLATIONS) + +MACDEPLOYQT_BIN=$(find_qt_tool macdeployqt macdeployqt6 || true) +if [ -z "$MACDEPLOYQT_BIN" ] && [ -x "${QT_PREFIX}/bin/macdeployqt" ]; then + MACDEPLOYQT_BIN="${QT_PREFIX}/bin/macdeployqt" +fi +if [ -z "$MACDEPLOYQT_BIN" ]; then + echo 'Unable to find macdeployqt. Install Qt 6 and ensure its tools are in PATH or set QTDIR.' >&2 + exit 1 +fi # Remove any previous disk folder or DMG echo -n 'Preparing... ' @@ -45,15 +97,27 @@ echo 'Done' # Copy Qt translations echo -n 'Copying Qt translations... ' TRANSLATIONS="$APP/$BUNDLE/Contents/Resources/translations" -cp $QTDIR/translations/qt_* "$TRANSLATIONS" -cp $QTDIR/translations/qtbase_* "$TRANSLATIONS" -rm -f $TRANSLATIONS/qt_help_* +mkdir -p "$TRANSLATIONS" +find "$QT_TRANSLATIONS" -maxdepth 1 -type f \( -name 'qt_*.qm' -o -name 'qtbase_*.qm' \) ! -name 'qt_help_*' -exec cp {} "$TRANSLATIONS" \; echo 'Done' # Copy frameworks and plugins echo -n 'Copying frameworks and plugins... ' -macdeployqt "$APP/$BUNDLE" -rm -Rf "$APP/$BUNDLE/Contents/PlugIns/iconengines" +DEPLOY_EXECUTABLES=() +DEPLOY_ARGS=( + "-no-plugins" + "-libpath=${QT_LIBS}" +) +if [ -d "${QT_PREFIX}/Frameworks" ]; then + DEPLOY_ARGS+=("-libpath=${QT_PREFIX}/Frameworks") +fi + +# Deploy only the plugins the app actually needs on macOS. +copy_qt_plugin 'platforms/libqcocoa.dylib' +copy_qt_plugin 'styles/libqmacstyle.dylib' +copy_qt_plugin 'imageformats/libqjpeg.dylib' + +"$MACDEPLOYQT_BIN" "${SCRIPT_DIR}/${APP}/${BUNDLE}" "${DEPLOY_ARGS[@]}" "${DEPLOY_EXECUTABLES[@]}" echo 'Done' # Copy background