macOS: add KytyPS5.app bundle packaging

Add a proper macOS application bundle when the launcher is built.
launcher becomes KytyPS5.app (CFBundleIdentifier org.kytyps5.kytyps5)
with KytyPS5 as the executable, and kyty_emulator is installed as a
helper inside Contents/MacOS so QCoreApplication::applicationDirPath()
finds it. MoltenVK is auto-discovered via SDL_GetBasePath() in that
directory, so no SDL_VULKAN_LIBRARY is required.

- src/launcher/Info.plist.in: minimal bundle plist (version from
  PROJECT_VERSION, LSMinimumSystemVersion 13.0).
- src/launcher/CMakeLists.txt: set MACOSX_BUNDLE, BUNDLE DESTINATION,
  install helper, re-sign helper with JIT entitlements, and invoke
  macdeployqt when available. Keep flat kyty_emulator for CLI.
- .github/workflows/build.yml: bundle MoltenVK into
  KytyPS5.app/Contents/MacOS when present, verify bundle artifacts
  (file/lipo/codesign), and handle bundle paths in the release zip.
- README.md: document bundle double-click and MoltenVK locations.
This commit is contained in:
nacimoualla
2026-08-29 12:10:13 +01:00
parent 6b8adb5e18
commit f294799b22
4 changed files with 111 additions and 8 deletions
+34 -3
View File
@@ -218,18 +218,39 @@ jobs:
_Build/macos/install/libMoltenVK.dylib _Build/macos/install/libMoltenVK.dylib
install -m 644 "$package/LICENSE" _Build/macos/install/LICENSE.MoltenVK install -m 644 "$package/LICENSE" _Build/macos/install/LICENSE.MoltenVK
codesign --force --sign - --timestamp=none _Build/macos/install/libMoltenVK.dylib codesign --force --sign - --timestamp=none _Build/macos/install/libMoltenVK.dylib
# Also bundle inside KytyPS5.app when the launcher bundle is produced.
if [[ -d _Build/macos/install/KytyPS5.app ]]; then
install -m 755 \
"$package/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib" \
_Build/macos/install/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib
install -m 644 "$package/LICENSE" _Build/macos/install/KytyPS5.app/Contents/Resources/LICENSE.MoltenVK 2>/dev/null || \
install -m 644 "$package/LICENSE" _Build/macos/install/KytyPS5.app/Contents/MacOS/LICENSE.MoltenVK
codesign --force --sign - --timestamp=none _Build/macos/install/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib
fi
- name: Verify artifacts - name: Verify artifacts
shell: bash shell: bash
run: | run: |
file _Build/macos/install/launcher
file _Build/macos/install/kyty_emulator file _Build/macos/install/kyty_emulator
file _Build/macos/install/libMoltenVK.dylib file _Build/macos/install/libMoltenVK.dylib
lipo _Build/macos/install/launcher -verify_arch x86_64
lipo _Build/macos/install/kyty_emulator -verify_arch x86_64 lipo _Build/macos/install/kyty_emulator -verify_arch x86_64
lipo _Build/macos/install/libMoltenVK.dylib -verify_arch x86_64 lipo _Build/macos/install/libMoltenVK.dylib -verify_arch x86_64
codesign --verify --strict _Build/macos/install/kyty_emulator codesign --verify --strict _Build/macos/install/kyty_emulator
codesign --verify --strict _Build/macos/install/libMoltenVK.dylib codesign --verify --strict _Build/macos/install/libMoltenVK.dylib
if [[ -d _Build/macos/install/KytyPS5.app ]]; then
file _Build/macos/install/KytyPS5.app/Contents/MacOS/KytyPS5
file _Build/macos/install/KytyPS5.app/Contents/MacOS/kyty_emulator
lipo _Build/macos/install/KytyPS5.app/Contents/MacOS/KytyPS5 -verify_arch x86_64
lipo _Build/macos/install/KytyPS5.app/Contents/MacOS/kyty_emulator -verify_arch x86_64
codesign --verify --strict _Build/macos/install/KytyPS5.app/Contents/MacOS/kyty_emulator
if [[ -f _Build/macos/install/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib ]]; then
lipo _Build/macos/install/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib -verify_arch x86_64
codesign --verify --strict _Build/macos/install/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib
fi
else
file _Build/macos/install/launcher
lipo _Build/macos/install/launcher -verify_arch x86_64
fi
- name: Upload macOS artifacts - name: Upload macOS artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -426,8 +447,18 @@ jobs:
run: | run: |
macos_dir="artifacts/KytyPS5-macOS-x86_64" macos_dir="artifacts/KytyPS5-macOS-x86_64"
test -d "$macos_dir" test -d "$macos_dir"
if [[ -d "$macos_dir/KytyPS5.app" ]]; then
chmod a+x \
"$macos_dir/KytyPS5.app/Contents/MacOS/KytyPS5" \
"$macos_dir/KytyPS5.app/Contents/MacOS/kyty_emulator" || true
if [[ -f "$macos_dir/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib" ]]; then
chmod a+x "$macos_dir/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib"
fi
fi
if [[ -f "$macos_dir/launcher" ]]; then
chmod a+x "$macos_dir/launcher"
fi
chmod a+x \ chmod a+x \
"$macos_dir/launcher" \
"$macos_dir/kyty_emulator" \ "$macos_dir/kyty_emulator" \
"$macos_dir/libMoltenVK.dylib" "$macos_dir/libMoltenVK.dylib"
( (
+12 -3
View File
@@ -220,17 +220,22 @@ cmake --install _Build/macos --prefix _Build/macos/install
``` ```
The build re-signs `kyty_emulator` with the JIT entitlements it needs to execute translated The build re-signs `kyty_emulator` with the JIT entitlements it needs to execute translated
guest code; no manual signing step is required. guest code; no manual signing step is required. When the launcher is built, the install
also produces `_Build/macos/install/KytyPS5.app` — double-click to launch the GUI.
A flat `kyty_emulator` is kept for CLI usage.
Vulkan comes from MoltenVK. Download `MoltenVK-macos.tar` from the Vulkan comes from MoltenVK. Download `MoltenVK-macos.tar` from the
[MoltenVK releases](https://github.com/KhronosGroup/MoltenVK/releases), then copy [MoltenVK releases](https://github.com/KhronosGroup/MoltenVK/releases), then copy
`MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib` next to `kyty_emulator` and ad-hoc sign it: `MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib` next to `kyty_emulator` (and, for
the bundle, into `KytyPS5.app/Contents/MacOS/`) and ad-hoc sign it:
```bash ```bash
codesign --force --sign - _Build/macos/install/libMoltenVK.dylib codesign --force --sign - _Build/macos/install/libMoltenVK.dylib
# For the bundle (if present):
codesign --force --sign - _Build/macos/install/KytyPS5.app/Contents/MacOS/libMoltenVK.dylib
``` ```
Release archives already include a signed `libMoltenVK.dylib`. Release archives already include a signed `libMoltenVK.dylib` (both flat and inside the bundle).
### Regression tests ### Regression tests
@@ -274,6 +279,10 @@ To use the graphical launcher:
./_Build/linux/install/launcher ./_Build/linux/install/launcher
``` ```
```bash
open _Build/macos/install/KytyPS5.app # or double-click in Finder
```
On first launch, add one or more game folders in the global settings. The launcher searches those On first launch, add one or more game folders in the global settings. The launcher searches those
folders recursively for game directories containing `eboot.bin`. Select a detected game and run it folders recursively for game directories containing `eboot.bin`. Select a detected game and run it
from the game list. from the game list.
+46
View File
@@ -65,11 +65,57 @@ if(WIN32)
) )
endif() endif()
if(APPLE)
set(launcher_name "KytyPS5")
else()
set(launcher_name "launcher") set(launcher_name "launcher")
endif()
set_target_properties(launcher PROPERTIES OUTPUT_NAME ${launcher_name}) set_target_properties(launcher PROPERTIES OUTPUT_NAME ${launcher_name})
if(APPLE)
# macOS bundle: KytyPS5.app with launcher as main executable and
# kyty_emulator as helper inside Contents/MacOS. MoltenVK is found
# via SDL_GetBasePath() + libMoltenVK.dylib, so placing it next to
# the executables (Contents/MacOS) is sufficient; no rpath fixup needed
# for the non-Qt case. Qt deployment (Frameworks + plugins) is handled
# by macdeployqt when a Qt installation is present.
set_target_properties(launcher PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
MACOSX_BUNDLE_BUNDLE_NAME "KytyPS5"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.kytyps5.kytyps5"
MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION}"
MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}"
)
install(TARGETS launcher BUNDLE DESTINATION .)
install(TARGETS kyty_emulator DESTINATION "KytyPS5.app/Contents/MacOS")
# Ad-hoc sign the helper with JIT entitlements inside the bundle (mirrors
# the top-level kyty_emulator signing). The bundle itself will be
# re-signed after Qt/MoltenVK deployment.
install(CODE "
execute_process(COMMAND codesign -s - --force --options runtime
--entitlements \"${KYTY_SOURCE_DIR}/macos_jit.entitlements\"
\"\${CMAKE_INSTALL_PREFIX}/KytyPS5.app/Contents/MacOS/kyty_emulator\"
RESULT_VARIABLE _kyty_sign_result)
if(NOT _kyty_sign_result EQUAL 0)
message(WARNING \"Failed to codesign bundled kyty_emulator\")
endif()
")
# Deploy Qt frameworks/plugins into the bundle when macdeployqt is available.
find_program(KYTY_MACDEPLOYQT NAMES macdeployqt PATHS "${Qt6_DIR}/../../../bin" NO_DEFAULT_PATH)
if(KYTY_MACDEPLOYQT)
install(CODE "
execute_process(COMMAND \"${KYTY_MACDEPLOYQT}\" \"\${CMAKE_INSTALL_PREFIX}/KytyPS5.app\"
RESULT_VARIABLE _kyty_deploy_result)
if(NOT _kyty_deploy_result EQUAL 0)
message(WARNING \"macdeployqt failed with \${_kyty_deploy_result}\")
endif()
")
endif()
else()
install(TARGETS launcher DESTINATION .) install(TARGETS launcher DESTINATION .)
endif()
if(WIN32) if(WIN32)
install(CODE " install(CODE "
+17
View File
@@ -0,0 +1,17 @@
<?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>KytyPS5</string>
<key>CFBundleDisplayName</key><string>KytyPS5</string>
<key>CFBundleIdentifier</key><string>org.kytyps5.kytyps5</string>
<key>CFBundleVersion</key><string>@PROJECT_VERSION@</string>
<key>CFBundleShortVersionString</key><string>@PROJECT_VERSION@</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleSignature</key><string>????</string>
<key>CFBundleExecutable</key><string>KytyPS5</string>
<key>LSMinimumSystemVersion</key><string>13.0</string>
<key>NSHighResolutionCapable</key><true/>
<key>NSRequiresAquaSystemAppearance</key><false/>
</dict>
</plist>