Support macOS bundling for binary distribution

This commit is contained in:
vit9696 2018-11-24 03:27:33 +03:00 committed by Ivan
parent c50d459b1e
commit 5a40c1802b
9 changed files with 109 additions and 39 deletions

View file

@ -15,7 +15,9 @@ unzip -: sdk-*.zip
mkdir vulkan-sdk mkdir vulkan-sdk
ln -s ${PWD}/Vulkan-Headers*/include vulkan-sdk/include ln -s ${PWD}/Vulkan-Headers*/include vulkan-sdk/include
mkdir vulkan-sdk/lib mkdir vulkan-sdk/lib
ln target/release/libportability.dylib vulkan-sdk/lib/libVulkan.dylib cp target/release/libportability.dylib vulkan-sdk/lib/libVulkan.dylib
# Let macdeployqt locate and install Vulkan library
install_name_tool -id ${PWD}/vulkan-sdk/lib/libVulkan.dylib vulkan-sdk/lib/libVulkan.dylib
export VULKAN_SDK=${PWD}/vulkan-sdk export VULKAN_SDK=${PWD}/vulkan-sdk
git submodule update --quiet --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng 3rdparty/cereal 3rdparty/hidapi 3rdparty/xxHash 3rdparty/yaml-cpp Vulkan/glslang git submodule update --quiet --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng 3rdparty/cereal 3rdparty/hidapi 3rdparty/xxHash 3rdparty/yaml-cpp Vulkan/glslang

View file

@ -1376,10 +1376,16 @@ const std::string& fs::get_config_dir()
dir.resize(dir.rfind('/') + 1); dir.resize(dir.rfind('/') + 1);
#else #else
#ifdef __APPLE__
if (const char* home = ::getenv("HOME"))
dir = home + "/Library/Application Support"s;
#else
if (const char* home = ::getenv("XDG_CONFIG_HOME")) if (const char* home = ::getenv("XDG_CONFIG_HOME"))
dir = home; dir = home;
else if (const char* home = ::getenv("HOME")) else if (const char* home = ::getenv("HOME"))
dir = home + "/.config"s; dir = home + "/.config"s;
#endif
else // Just in case else // Just in case
dir = "./config"; dir = "./config";

View file

@ -41,6 +41,15 @@ file(GLOB RPCS3_SRC "*.cpp")
if(WIN32) if(WIN32)
add_executable(rpcs3 WIN32 ${RPCS3_SRC}) add_executable(rpcs3 WIN32 ${RPCS3_SRC})
elseif(APPLE)
set(MACOSX_BUNDLE_BUNDLE_NAME rpcs3)
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.rpcs3.rpcs3")
set(MACOSX_BUNDLE_INFO_STRING "Open-source Sony PlayStation 3 emulator")
set(MACOSX_BUNDLE_ICON_FILE "rpcs3.icns")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "0.0.5")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "0.0.5")
set(MACOSX_BUNDLE_BUNDLE_VERSION "0.0.5")
add_executable(rpcs3 MACOSX_BUNDLE ${RPCS3_SRC} "${RPCS3_SRC_DIR}/rpcs3.icns")
else() else()
add_executable(rpcs3 ${RPCS3_SRC}) add_executable(rpcs3 ${RPCS3_SRC})
endif() endif()
@ -84,8 +93,17 @@ set_target_properties(rpcs3 PROPERTIES
cotire(rpcs3) cotire(rpcs3)
if (UNIX) # Copy icons to executable directory
# Copy icons to executable directory if(APPLE)
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${RPCS3_SRC_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
COMMAND "${Qt5_DIR}/../../../bin/macdeployqt" "${PROJECT_BINARY_DIR}/bin/rpcs3.app")
elseif(UNIX)
add_custom_command(TARGET rpcs3 POST_BUILD add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons) ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons)

View file

@ -15,6 +15,10 @@
#include <libgen.h> #include <libgen.h>
#endif #endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
// STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally // STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally
#include <stb_image.h> #include <stb_image.h>
#include <stb_truetype.h> #include <stb_truetype.h>
@ -505,24 +509,37 @@ namespace rsx
if (info->data == nullptr) if (info->data == nullptr)
{ {
// Resource was not found in config dir, try and grab from relative path (linux) // Resource was not found in config dir, try and grab from relative path (linux)
info = std::make_unique<image_info>(("Icons/ui/" + res).c_str()); auto src = "Icons/ui/" + res;
info = std::make_unique<image_info>(src.c_str());
#ifndef _WIN32 #ifndef _WIN32
// Check for Icons in ../share/rpcs3 for AppImages and /usr/bin/ // Check for Icons in ../share/rpcs3 for AppImages,
// in rpcs3.app/Contents/Resources for App Bundles, and /usr/bin.
if (info->data == nullptr) if (info->data == nullptr)
{ {
char result[ PATH_MAX ]; char result[ PATH_MAX ];
#ifdef __linux__ #if defined(__APPLE__)
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX ); uint32_t bufsize = PATH_MAX;
bool success = _NSGetExecutablePath( result, &bufsize ) == 0;
#elif defined(__linux__)
bool success = readlink( "/proc/self/exe", result, PATH_MAX ) >= 0;
#else #else
ssize_t count = readlink( "/proc/curproc/file", result, PATH_MAX ); bool success = readlink( "/proc/curproc/file", result, PATH_MAX ) >= 0;
#endif #endif
if (success)
{
std::string executablePath = dirname(result); std::string executablePath = dirname(result);
info = std::make_unique<image_info>((executablePath + "/../share/rpcs3/Icons/ui/" + res).c_str()); #ifdef __APPLE__
src = executablePath + "/../Resources/Icons/ui/" + res;
#else
src = executablePath + "/../share/rpcs3/Icons/ui/" + res;
#endif
info = std::make_unique<image_info>(src.c_str());
// Check if the icons are in the same directory as the executable (local builds) // Check if the icons are in the same directory as the executable (local builds)
if (info->data == nullptr) if (info->data == nullptr)
{ {
info = std::make_unique<image_info>((executablePath + "/Icons/ui/" + res).c_str()); src = executablePath + "/Icons/ui/" + res;
info = std::make_unique<image_info>(src.c_str());
}
} }
} }
#endif #endif
@ -530,7 +547,6 @@ namespace rsx
{ {
// Install the image to config dir // Install the image to config dir
auto dst_dir = fs::get_config_dir() + "Icons/ui/"; auto dst_dir = fs::get_config_dir() + "Icons/ui/";
auto src = "Icons/ui/" + res;
auto dst = dst_dir + res; auto dst = dst_dir + res;
if (!fs::is_dir(dst_dir)) if (!fs::is_dir(dst_dir))

View file

@ -18,6 +18,10 @@
#include <sys/resource.h> #include <sys/resource.h>
#endif #endif
#ifdef __APPLE__
#include <dispatch/dispatch.h>
#endif
#include "rpcs3_version.h" #include "rpcs3_version.h"
inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QString& _in) { return _in.toStdString(); }
@ -50,6 +54,8 @@ static semaphore<> s_qt_mutex{};
static QApplication app0{argc, argv}; static QApplication app0{argc, argv};
} }
auto show_report = [](const std::string& text)
{
QMessageBox msg; QMessageBox msg;
msg.setWindowTitle(tr("RPCS3: Fatal Error")); msg.setWindowTitle(tr("RPCS3: Fatal Error"));
msg.setIcon(QMessageBox::Critical); msg.setIcon(QMessageBox::Critical);
@ -67,6 +73,19 @@ static semaphore<> s_qt_mutex{};
.arg(tr("Please, don't send incorrect reports. Thanks for understanding."))); .arg(tr("Please, don't send incorrect reports. Thanks for understanding.")));
msg.layout()->setSizeConstraint(QLayout::SetFixedSize); msg.layout()->setSizeConstraint(QLayout::SetFixedSize);
msg.exec(); msg.exec();
};
#ifdef __APPLE__
// Cocoa access is not allowed outside of the main thread
if (!pthread_main_np())
{
dispatch_sync(dispatch_get_main_queue(), ^ { show_report(text); });
}
else
#endif
{
show_report(text);
}
std::abort(); std::abort();
} }

BIN
rpcs3/rpcs3.icns Normal file

Binary file not shown.

View file

@ -422,9 +422,13 @@ void rpcs3_app::OnChangeStyleSheetRequest(const QString& path)
QFile file(path); QFile file(path);
#if !defined(_WIN32) && !defined(__APPLE__) // If we can't open the file, try the /share or /Resources folder
// If we can't open the file, try the /share folder #if !defined(_WIN32)
#ifdef __APPLE__
QString share_dir = QCoreApplication::applicationDirPath() + "/../Resources/";
#else
QString share_dir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/"; QString share_dir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/";
#endif
QFile share_file(share_dir + "GuiConfigs/" + QFileInfo(file.fileName()).fileName()); QFile share_file(share_dir + "GuiConfigs/" + QFileInfo(file.fileName()).fileName());
#endif #endif
@ -451,7 +455,7 @@ void rpcs3_app::OnChangeStyleSheetRequest(const QString& path)
setStyleSheet(file.readAll()); setStyleSheet(file.readAll());
file.close(); file.close();
} }
#if !defined(_WIN32) && !defined(__APPLE__) #if !defined(_WIN32)
else if (share_file.open(QIODevice::ReadOnly | QIODevice::Text)) else if (share_file.open(QIODevice::ReadOnly | QIODevice::Text))
{ {
QDir::setCurrent(share_dir); QDir::setCurrent(share_dir);

View file

@ -9,5 +9,6 @@ namespace rpcs3
return RPCS3_GIT_BRANCH; return RPCS3_GIT_BRANCH;
} }
//TODO: Make this accessible from cmake and keep in sync with MACOSX_BUNDLE_BUNDLE_VERSION.
const extern utils::version version{ 0, 0, 5, utils::version_type::alpha, 1, RPCS3_GIT_VERSION }; const extern utils::version version{ 0, 0, 5, utils::version_type::alpha, 1, RPCS3_GIT_VERSION };
} }

View file

@ -338,10 +338,14 @@ QStringList gui_settings::GetStylesheetEntries()
{ {
QStringList nameFilter = QStringList("*.qss"); QStringList nameFilter = QStringList("*.qss");
QStringList res = gui::utils::get_dir_entries(m_settingsDir, nameFilter); QStringList res = gui::utils::get_dir_entries(m_settingsDir, nameFilter);
#if !defined(_WIN32) && !defined(__APPLE__) #if !defined(_WIN32)
// Makes stylesheets load if using AppImage or installed to /usr/bin // Makes stylesheets load if using AppImage (App Bundle) or installed to /usr/bin
QDir linuxStylesheetDir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/GuiConfigs/"; #ifdef __APPLE__
res.append(gui::utils::get_dir_entries(linuxStylesheetDir, nameFilter)); QDir platformStylesheetDir = QCoreApplication::applicationDirPath() + "/../Resources/GuiConfigs/";
#else
QDir platformStylesheetDir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/GuiConfigs/";
#endif
res.append(gui::utils::get_dir_entries(platformStylesheetDir, nameFilter));
res.removeDuplicates(); res.removeDuplicates();
#endif #endif
res.sort(Qt::CaseInsensitive); res.sort(Qt::CaseInsensitive);