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
install -m 644 "$package/LICENSE" _Build/macos/install/LICENSE.MoltenVK
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
shell: bash
run: |
file _Build/macos/install/launcher
file _Build/macos/install/kyty_emulator
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/libMoltenVK.dylib -verify_arch x86_64
codesign --verify --strict _Build/macos/install/kyty_emulator
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
uses: actions/upload-artifact@v4
@@ -426,8 +447,18 @@ jobs:
run: |
macos_dir="artifacts/KytyPS5-macOS-x86_64"
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 \
"$macos_dir/launcher" \
"$macos_dir/kyty_emulator" \
"$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
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
[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
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
@@ -274,6 +279,10 @@ To use the graphical 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
folders recursively for game directories containing `eboot.bin`. Select a detected game and run it
from the game list.
+48 -2
View File
@@ -65,11 +65,57 @@ if(WIN32)
)
endif()
set(launcher_name "launcher")
if(APPLE)
set(launcher_name "KytyPS5")
else()
set(launcher_name "launcher")
endif()
set_target_properties(launcher PROPERTIES OUTPUT_NAME ${launcher_name})
install(TARGETS launcher DESTINATION .)
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 .)
endif()
if(WIN32)
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>