Contents
Requirements and setup
Install Xcode Command Line Tools, Git, CMake 3.16 or later, Ninja, Python 3, and a Qt 6.7 or later macOS SDK. The packaging script also needs macdeployqt, codesign, vtool, and create-dmg.
xcode-select --install
brew install cmake ninja create-dmg python
Install Qt with the Qt Online Installer, including Charts, Multimedia, and developer tools. ShogiBoardQ requires Widgets, Charts, Network, Concurrent, Multimedia, Sql, and LinguistTools; packaging also needs the SVG and SQLite plugins. Homebrew Qt is an alternative when it provides all required modules, but its corresponding sources and any patches must match that build when distributing it.
These examples use the official Qt 6.7.3 macOS SDK. Adjust the paths for your installation:
export CMAKE_PREFIX_PATH="$HOME/Qt/6.7.3/macos"
export PATH="$HOME/Qt/6.7.3/macos/bin:$PATH"
macdeployqt -help
Get the source and build
Clone the repository with its Hayanagi submodule. An ordinary clone without submodules is incomplete.
git clone --recurse-submodules https://github.com/hnakada123/ShogiBoardQ.git
cd ShogiBoardQ
For an existing checkout, initialize the recorded submodule version with git submodule update --init --recursive.
cmake -B build -S . -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build --parallel
open build/ShogiBoardQ.app
For a universal binary, both Qt and the other libraries must provide arm64 and x86_64. The packaging script accepts --universal to build both architectures.
Choose a deployment target compatible with your SDK and Qt build. The script accepts --deployment-target VERSION, otherwise uses MACOSX_DEPLOYMENT_TARGET, and currently defaults to 26.0 if neither is set. Lowering that value alone does not make dependencies built for a newer macOS compatible with older systems.
To enable and run the test suite:
cmake -B build -S . -DBUILD_TESTING=ON
cmake --build build --parallel
ctest --test-dir build --output-on-failure
Prepare bundled Qt notices
A normal local CMake build does not download Qt sources. The distribution scripts additionally require prepared license documents for the exact Qt build they deploy. They include those documents and source information in the package and stop if validation fails.
For the unmodified official Qt 6.7.3 SDK, run the following from the repository root. These commands use the version and SHA-256 recorded in the release workflow. For a different Qt build, use its matching full source archive, checksum, and provenance instead.
python3 scripts/qt_licenses.py fetch --version 6.7.3 --sha256 a3f1d257cbb14c6536585ffccf7c203ce7017418e1a0c2ed7c316c20c729c801 --output build/qt-sources
python3 scripts/qt_licenses.py prepare --version 6.7.3 --archive build/qt-sources/qt-everywhere-src-6.7.3.tar.xz --sha256 a3f1d257cbb14c6536585ffccf7c203ce7017418e1a0c2ed7c316c20c729c801 --source-url https://download.qt.io/archive/qt/6.7/6.7.3/single/qt-everywhere-src-6.7.3.tar.xz --provenance "Official Qt 6.7.3 SDK, unmodified; build scripts in source archive" --output build/qt-licenses
Download the Qt source archive locally to extract license notices; it is build input and is not a release attachment. The preparation command does not overwrite an existing output directory. A clean build deletes build; if using the script's clean option, prepare the sources and notices outside that directory and set SHOGIBOARDQ_QT_LICENSE_DIR to the notices directory.
Attach only runnable product packages to a GitHub Release. Keep license texts and source acquisition information inside the application package. Record the Qt source URL and, for patched builds, the supplier’s patches and build instructions in QT-SOURCE.json. Do not attach Qt source archives or source/build metadata separately. The repository's Qt distribution notes (Japanese) describe the packaging policy and source manifests.
Create a DMG package
After preparing the Qt notices and source archive, run:
./scripts/build-macos.sh
The script builds build/ShogiBoardQ.app, deploys Qt frameworks and plugins with macdeployqt, copies all four application translations (ja_JP, en, zh_CN, zh_TW) and license documents, signs the app, and creates ShogiBoardQ.dmg in the repository root. It checks the bundled SQLite plugin used for puzzle history.
The DMG contains only the files needed to run ShogiBoardQ. Translations of the standard Qt dialogs are embedded in the executable. As in the Linux package, the Hayanagi USI engine for normal games and the tsume shogi collections are kept outside the DMG.
After the DMG, the script creates ShogiBoardQ-macos.zip in the repository root. It contains a ShogiBoardQ-macos folder with ShogiBoardQ.dmg, README.md (from resources/platform/README-macos.md), LICENSE, Hayanagi/hayanagi with its opening book Hayanagi/book/hayanagi_book.db and its README, and the six collections (3- to 13-move mates) with their README in data/tsumeshogi/. The script stops if more than one collection exists for a mate length. It strips hayanagi and signs it again with the same identity as the app. The book is the copy the build places in build/Hayanagi/book/; Hayanagi reads it from book/ in its working directory, and ShogiBoardQ starts each engine in the engine's own folder, so the book is used as extracted. Because downloaded files are quarantined, the README tells users to run xattr -d com.apple.quarantine Hayanagi/hayanagi before registering the engine.
After macdeployqt, the script removes Qt parts the application does not use, then checks that every framework still referenced is present in the bundle:
- Virtual keyboard, QML, and Qt Quick (
platforminputcontexts,QtQml*,QtQuick,QtVirtualKeyboard*) - TLS backends other than SecureTransport, and the network information plugin. The “TLS (encrypted)” connection for CSA play uses the SecureTransport backend, which relies on the macOS Security framework; the OpenSSL backend would need libssl in the bundle
- The FFmpeg multimedia backend and its
libav*/libsw*libraries (piece sounds use the native darwin backend) - SQL drivers other than SQLite
- Image format plugins other than SVG and ICO (icons) and JPEG, TIFF, and WebP (board image export)
Unless --universal is given, it also strips the x86_64 slices from Qt, so the app is arm64 only. This reduces the bundle from about 187 MB to about 89 MB and the DMG to about 50 MB. Expect harmless macdeployqt errors about .qm files not being object files, missing ODBC, PostgreSQL, or Mimer driver dependencies, and its own signing step; the script removes those drivers, re-signs the bundle, and verifies it strictly.
Use --skip-dmg to produce only the deployed app bundle without the DMG and ZIP, --universal for both CPU architectures, or --help for all options. Preparing a deployed app still requires the Qt notices. For a test DMG without them, --skip-qt-licenses keeps only the short license documents bundled by the build in Contents/MacOS/licenses; do not use it for a release.
Mount the DMG, copy the app to Applications, and test it on a machine without the Qt SDK. Check language switching, pieces, sound, board image export, and saving tsume puzzle progress. For a universal release, test both architectures. To confirm that nothing loads from the Qt SDK or Homebrew, run lsof -p "$(pgrep -x ShogiBoardQ)" | grep -E '/Qt/|homebrew' while the app is running; it should print nothing.
Code signing and notarization
The script uses ad hoc signing by default. A Developer ID release requires the Apple Developer Program. Import your Developer ID Application certificate into the keychain and pass its identity to the script. To notarize as well, set your Apple Account email, team ID, and an app-specific password (not your Apple Account password) in the environment and add --notarize:
export APPLE_ID="your@email.com" APPLE_TEAM_ID="TEAMID" APPLE_APP_PASSWORD="app-specific-password"
./scripts/build-macos.sh --sign-identity "Developer ID Application: Your Name (TEAMID)" --notarize
A Developer ID signs the app and Hayanagi/hayanagi with Hardened Runtime and a secure timestamp, and also signs the DMG. With --notarize, the script submits the DMG with xcrun notarytool, staples the ticket, and only then creates ShogiBoardQ-macos.zip, so the ZIP contains the stapled DMG. If Apple rejects the submission, the script prints the submission ID and stops; run xcrun notarytool log with that ID and the same credentials to see why. Confirm that notarization succeeded and test the final downloaded package before publishing a signed release.
The release workflow does the same when its signing secrets are configured: it imports the certificate before the build, passes the identity to the script, and adds --notarize when the notarization secrets are also set.
Without notarization, Gatekeeper blocks the downloaded app the first time it is opened. Since macOS 15, Control-clicking the app and choosing Open no longer bypasses this. Tell users to try opening the app, close the warning, then open System Settings > Privacy & Security and click Open Anyway. If Open Anyway does not appear, they can remove the quarantine attribute in Terminal with xattr -cr /Applications/ShogiBoardQ.app.
Publish on GitHub Releases
The release version is the release date (YYYY.MM.DD, for example 2026.10.07). Update APP_VERSION in CMakeLists.txt only on the day of a release: commit the change before building the packages, build them from that commit, and tag that commit with the same version, without a leading v. Use the version in the release name as well. For a second release on the same day, add a fourth number, as in 2026.10.07.1. See Versioning and releases (Japanese).
Releases are created by hand. Build the package with the script, test it, and attach only ShogiBoardQ-macos.zip; the other platforms add ShogiBoardQ-linux.zip and ShogiBoardQ-windows.zip to the same release. Select the package by its exact filename instead of uploading the entire working directory. License documents remain inside the application package; Qt sources and build metadata are not release attachments.
git tag -a 2026.10.07 -m "ShogiBoardQ 2026.10.07"
git push origin main 2026.10.07
gh release create 2026.10.07 \
--title "ShogiBoardQ 2026.10.07" \
--notes-file RELEASE_NOTES.md \
ShogiBoardQ-macos.zip
# If the release already exists (for example, created from Windows)
gh release upload 2026.10.07 ShogiBoardQ-macos.zip
The repository's release.yml builds all three operating systems for tags beginning with v or when run manually, so pushing a date tag does not start it. A manual run attaches the packages to a release only when Publish is turned on; by default it only builds and verifies them. Its macOS job attaches the same ShogiBoardQ-macos.zip that the script builds. Releases are still created by hand because the workflow's Linux job cannot create the Linux package yet (see the Linux build guide).
Troubleshooting
- Qt6Config.cmake or Qt Charts is missing: check the kit path and install all required modules. Use a fresh build directory after switching Qt kits.
- Hayanagi source files are missing: run
git submodule update --init --recursive. - macdeployqt is not found: add the Qt kit's
bindirectory toPATH. For missingcodesignorvtool, check your Xcode tools setup. - A framework cannot load on another Mac: inspect the deployment log and app bundle. Test the deployed app from the DMG, not an app that relies on the developer SDK.
- One architecture fails to link: verify that Qt and all dependencies contain both architectures before using
--universal. - Puzzle history cannot be saved: check
Contents/PlugIns/sqldrivers/libqsqlite.dylibin the app. - The script reports that a removed framework is still referenced: a new Qt version or feature now depends on it. Keep that framework in the pruning step of
scripts/build-macos.sh. - Signing or notarization fails: inspect the identity, entitlements, and notarization log. Re-sign after modifying the app bundle.
- Qt notice validation fails: prepare notices and sources matching the deployed Qt, including any package-manager patches.