Merge pull request #802 from stenzek/macos-bundle

CI: macOS build
This commit is contained in:
Connor McLaughlin 2020-08-26 00:15:34 +10:00 committed by GitHub
commit 4d12b6a2a7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 240 additions and 4 deletions

View file

@ -233,9 +233,46 @@ jobs:
name: "android"
path: "duckstation-android-aarch64.apk"
macos-build:
runs-on: macos-10.15
steps:
- uses: actions/checkout@v2.3.1
with:
fetch-depth: 0
- name: Install packages
shell: bash
run: |
brew install qt5 sdl2
- name: Clone mac externals
shell: bash
run: |
git clone https://github.com/stenzek/duckstation-ext-mac.git dep/mac
- name: Compile build
shell: bash
run: |
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SDL_FRONTEND=OFF -DBUILD_QT_FRONTEND=ON -DUSE_SDL2=ON -DQt5_DIR=/usr/local/opt/qt/lib/cmake/Qt5 ..
cmake --build . --parallel 2
- name: Zip macOS .app
shell: bash
run: |
cd build/bin
zip -r duckstation-mac-release.zip DuckStation.app/
- name: Upload macOS .app
uses: actions/upload-artifact@v1
with:
name: "macos-x64"
path: "build/bin/duckstation-mac-release.zip"
create-release:
needs: [windows-build, windows-libretro-build, linux-build, linux-libretro-build, android-build]
needs: [windows-build, windows-libretro-build, linux-build, linux-libretro-build, android-build, macos-build]
runs-on: "ubuntu-latest"
if: github.ref == 'refs/heads/master'
steps:
@ -279,6 +316,11 @@ jobs:
with:
name: "android"
- name: Download Mac App
uses: actions/download-artifact@v1
with:
name: "macos-x64"
- name: Create release
uses: "marvinpinto/action-automatic-releases@latest"
with:
@ -296,4 +338,5 @@ jobs:
linux-libretro/duckstation_libretro_linux_aarch64.so.zip
linux-libretro/duckstation_libretro_android_aarch64.so.zip
android/duckstation-android-aarch64.apk
macos-x64/duckstation-mac-release.zip

3
.gitignore vendored
View file

@ -37,3 +37,6 @@ CMakeLists.txt.user
# python bytecode
__pycache__
# other repos
/dep/mac

View file

@ -0,0 +1,46 @@
# This module can be used in two different ways.
#
# When invoked as `cmake -P DolphinPostprocessBundle.cmake`, it fixes up an
# application folder to be standalone. It bundles all required libraries from
# the system and fixes up library IDs. Any additional shared libraries, like
# plugins, that are found under Contents/MacOS/ will be made standalone as well.
#
# When called with `include(DolphinPostprocessBundle)`, it defines a helper
# function `dolphin_postprocess_bundle` that sets up the command form of the
# module as a post-build step.
if(CMAKE_GENERATOR)
# Being called as include(DolphinPostprocessBundle), so define a helper function.
set(_DOLPHIN_POSTPROCESS_BUNDLE_MODULE_LOCATION "${CMAKE_CURRENT_LIST_FILE}")
function(dolphin_postprocess_bundle target)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${CMAKE_COMMAND} -DDOLPHIN_BUNDLE_PATH="$<TARGET_FILE_DIR:${target}>/../.."
-P "${_DOLPHIN_POSTPROCESS_BUNDLE_MODULE_LOCATION}"
)
endfunction()
return()
endif()
get_filename_component(DOLPHIN_BUNDLE_PATH "${DOLPHIN_BUNDLE_PATH}" ABSOLUTE)
message(STATUS "Fixing up application bundle: ${DOLPHIN_BUNDLE_PATH}")
# Make sure to fix up any additional shared libraries (like plugins) that are
# needed.
file(GLOB_RECURSE extra_libs "${DOLPHIN_BUNDLE_PATH}/Contents/MacOS/*.dylib")
# BundleUtilities doesn't support DYLD_FALLBACK_LIBRARY_PATH behavior, which
# makes it sometimes break on libraries that do weird things with @rpath. Specify
# equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625
# is fixed and in our minimum CMake version.
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib")
# BundleUtilities is overly verbose, so disable most of its messages
function(message)
if(NOT ARGV MATCHES "^STATUS;")
_message(${ARGV})
endif()
endfunction()
include(BundleUtilities)
set(BU_CHMOD_BUNDLE_ITEMS ON)
fixup_bundle("${DOLPHIN_BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}")

View file

@ -13,6 +13,7 @@ A "BIOS" ROM image is required to to start the emulator and to play games. You c
## Latest News
- 2020/08/25: Automated builds for macOS now available.
- 2020/08/22: XInput controller backend added.
- 2020/08/20: Per-game setting overrides added. Mostly for compatibility, but some options are customizable.
- 2020/08/19: CPU PGXP mode added. It is very slow and incompatible with the recompiler, only use for games which need it.
@ -96,6 +97,20 @@ To download:
- Run `chmod a+x` on the downloaded AppImage -- following this step, the AppImage can be run like a typical executable.
- Optionally use a program such as [appimaged](https://github.com/AppImage/appimaged) or [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher) for desktop integration. [AppImageUpdate](https://github.com/AppImage/AppImageUpdate) can be used alongside appimaged to easily update your DuckStation AppImage.
### macOS
To download:
- Go to https://github.com/stenzek/duckstation/releases/tag/latest, and download the Mac build. This is a zip archive containing the prebuilt binary.
- Alternatively, direct download link: https://github.com/stenzek/duckstation/releases/download/latest/duckstation-mac-release.zip
- Extract the zip archive. If you're using Safari, apparently this happens automatically. This will give you DuckStation.app.
- Right click DuckStation.app, and click Open. As the package is not signed (Mac certificates are expensive), you must do this the first time you open it. Subsequent runs can be done by double-clicking.
macOS support is considered experimental and not actively supported by the developer; the builds are provided here as a courtesy. Please feel free to submit issues, but it may be some time before
they are investigated.
**macOS builds do not support automatic updates yet.** If there is sufficient demand, this may be something I will consider.
### Android
A prebuilt APK is now available for Android. However, please keep in mind that the Android version is not yet feature complete, it is more of a preview of things to come. You will need a device running a 64-bit AArch64 userland (anything made in the last few years).
@ -170,12 +185,11 @@ Requirements:
- Qt 5 (`brew install qt5`)
1. Clone the repository. Submodules aren't necessary, there is only one and it is only used for Windows.
2. Clone the mac externals repository (for MoltenVK): `git clone https://github.com/stenzek/duckstation-ext-mac.git dep/mac`.
2. Create a build directory, either in-tree or elsewhere, e.g. `mkdir build-release`, `cd build-release`.
3. Run cmake to configure the build system: `cmake -DCMAKE_BUILD_TYPE=Release -DQt5_DIR=/usr/local/opt/qt/lib/cmake/Qt5 ..`. You may need to tweak `Qt5_DIR` depending on your system.
4. Compile the source code: `make`. Use `make -jN` where `N` is the number of CPU cores in your system for a faster build.
5. Run the binary, located in the build directory under `bin/duckstation-sdl`, or `bin/duckstation-qt`.
Application bundles/.apps are currently not created, so you can't launch it via Finder yet. This is planned for the future.
5. Run the binary, located in the build directory under `bin/duckstation-sdl`, or `bin/DuckStation.app` for Qt.
### Android
**NOTE:** The Android frontend is still incomplete, not all functionality is available yet. User directory is hardcoded to `/sdcard/duckstation` for now.

View file

@ -7,6 +7,8 @@
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include "vulkan_loader.h"
@ -14,6 +16,10 @@
#include <dlfcn.h>
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
#define VULKAN_MODULE_ENTRY_POINT(name, required) PFN_##name name;
#define VULKAN_INSTANCE_ENTRY_POINT(name, required) PFN_##name name;
#define VULKAN_DEVICE_ENTRY_POINT(name, required) PFN_##name name;
@ -111,6 +117,25 @@ bool LoadVulkanLibrary()
char* libvulkan_env = getenv("LIBVULKAN_PATH");
if (libvulkan_env)
vulkan_module = dlopen(libvulkan_env, RTLD_NOW);
if (!vulkan_module)
{
unsigned path_size = 0;
_NSGetExecutablePath(nullptr, &path_size);
std::string path;
path.resize(path_size);
if (_NSGetExecutablePath(path.data(), &path_size) == 0)
{
path[path_size] = 0;
size_t pos = path.rfind('/');
if (pos != std::string::npos)
{
path.erase(pos);
path += "/../Frameworks/libvulkan.dylib";
vulkan_module = dlopen(path.c_str(), RTLD_NOW);
}
}
}
if (!vulkan_module)
vulkan_module = dlopen("libvulkan.dylib", RTLD_NOW);
#else

View file

@ -105,3 +105,63 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qt.conf.win" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qt.conf"
)
endif()
if(APPLE)
include(BundleUtilities)
set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DuckStation.app)
# Ask for an application bundle.
set_target_properties(duckstation-qt PROPERTIES
MACOSX_BUNDLE true
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in
OUTPUT_NAME DuckStation
)
# Copy qt.conf into the bundle
target_sources(duckstation-qt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/qt.conf")
set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/qt.conf" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# Copy icon into the bundle
target_sources(duckstation-qt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/DuckStation.icns")
set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/DuckStation.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# Copy Qt plugins into the bundle
get_target_property(qtcocoa_location Qt5::QCocoaIntegrationPlugin LOCATION)
target_sources(duckstation-qt PRIVATE "${qtcocoa_location}")
set_source_files_properties("${qtcocoa_location}" PROPERTIES MACOSX_PACKAGE_LOCATION MacOS/platforms)
get_target_property(qtmacstyle_location Qt5::QMacStylePlugin LOCATION)
target_sources(duckstation-qt PRIVATE "${qtmacstyle_location}")
set_source_files_properties("${qtmacstyle_location}" PROPERTIES MACOSX_PACKAGE_LOCATION MacOS/styles)
# Copy resources into the bundle
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/data")
file(GLOB_RECURSE resources RELATIVE "${CMAKE_SOURCE_DIR}/data" "${CMAKE_SOURCE_DIR}/data/*")
foreach(res ${resources})
target_sources(duckstation-qt PRIVATE "${CMAKE_SOURCE_DIR}/data/${res}")
get_filename_component(resdir "${res}" DIRECTORY)
set_source_files_properties("${CMAKE_SOURCE_DIR}/data/${res}" PROPERTIES
MACOSX_PACKAGE_LOCATION "MacOS/${resdir}")
source_group("Resources" FILES "${CMAKE_SOURCE_DIR}/data/${res}")
endforeach()
# Copy translations into the bundle
add_custom_command(TARGET duckstation-qt
POST_BUILD
COMMAND mkdir $<TARGET_FILE_DIR:duckstation-qt>/translations
COMMAND cp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations/*.qm $<TARGET_FILE_DIR:duckstation-qt>/translations)
# Copy MoltenVK into the bundle
target_sources(duckstation-qt PRIVATE "${CMAKE_SOURCE_DIR}/dep/mac/MoltenVK/libvulkan.dylib")
set_source_files_properties("${CMAKE_SOURCE_DIR}/dep/mac/MoltenVK/libvulkan.dylib" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
# Update library references to make the bundle portable
include(DolphinPostprocessBundle)
dolphin_postprocess_bundle(duckstation-qt)
# Fix rpath
add_custom_command(TARGET duckstation-qt
POST_BUILD COMMAND
${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/"
$<TARGET_FILE:duckstation-qt>)
endif()

Binary file not shown.

View file

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>bin</string>
<string>cue</string>
<string>img</string>
<string>chd</string>
<string>m3u</string>
<string>psexe</string>
<string>psf</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>DuckStation.icns</string>
<key>CFBundleTypeName</key>
<string>PlayStation File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>DuckStation</string>
<key>CFBundleIconFile</key>
<string>DuckStation.icns</string>
<key>CFBundleIdentifier</key>
<string>com.github.stenzek.duckstation</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>NSHumanReadableCopyright</key>
<string>Licensed under GPL version 3</string>
<key>LSMinimumSystemVersion</key>
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>CSResourcesFileMapped</key>
<true/>
</dict>
</plist>

View file