Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support macOS bundling for binary distribution #5367

Merged
merged 2 commits into from
Dec 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .travis/build-mac.bash
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ unzip -: sdk-*.zip
mkdir vulkan-sdk
ln -s ${PWD}/Vulkan-Headers*/include vulkan-sdk/include
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

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
Expand Down
6 changes: 6 additions & 0 deletions Utilities/File.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1376,10 +1376,16 @@ const std::string& fs::get_config_dir()

dir.resize(dir.rfind('/') + 1);
#else

#ifdef __APPLE__
if (const char* home = ::getenv("HOME"))
dir = home + "/Library/Application Support"s;
#else
if (const char* home = ::getenv("XDG_CONFIG_HOME"))
dir = home;
else if (const char* home = ::getenv("HOME"))
dir = home + "/.config"s;
#endif
else // Just in case
dir = "./config";

Expand Down
22 changes: 20 additions & 2 deletions rpcs3/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@ file(GLOB RPCS3_SRC "*.cpp")

if(WIN32)
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()
add_executable(rpcs3 ${RPCS3_SRC})
endif()
Expand Down Expand Up @@ -84,8 +93,17 @@ set_target_properties(rpcs3 PROPERTIES

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
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons)
Expand Down
40 changes: 28 additions & 12 deletions rpcs3/Emu/RSX/Overlays/overlay_controls.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#include <libgen.h>
#endif

#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif

// STB_IMAGE_IMPLEMENTATION and STB_TRUETYPE_IMPLEMENTATION defined externally
#include <stb_image.h>
#include <stb_truetype.h>
Expand Down Expand Up @@ -505,32 +509,44 @@ namespace rsx
if (info->data == nullptr)
{
// 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
// 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)
{
char result[ PATH_MAX ];
#ifdef __linux__
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
#if defined(__APPLE__)
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
ssize_t count = readlink( "/proc/curproc/file", result, PATH_MAX );
bool success = readlink( "/proc/curproc/file", result, PATH_MAX ) >= 0;
#endif
std::string executablePath = dirname(result);
info = std::make_unique<image_info>((executablePath + "/../share/rpcs3/Icons/ui/" + res).c_str());

// Check if the icons are in the same directory as the executable (local builds)
if (info->data == nullptr)
if (success)
{
info = std::make_unique<image_info>((executablePath + "/Icons/ui/" + res).c_str());
std::string executablePath = dirname(result);
#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)
if (info->data == nullptr)
{
src = executablePath + "/Icons/ui/" + res;
info = std::make_unique<image_info>(src.c_str());
}
}
}
#endif
if (info->data != nullptr)
{
// Install the image to config dir
auto dst_dir = fs::get_config_dir() + "Icons/ui/";
auto src = "Icons/ui/" + res;
auto dst = dst_dir + res;

if (!fs::is_dir(dst_dir))
Expand Down
53 changes: 36 additions & 17 deletions rpcs3/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include <sys/resource.h>
#endif

#ifdef __APPLE__
#include <dispatch/dispatch.h>
#endif

#include "rpcs3_version.h"

inline std::string sstr(const QString& _in) { return _in.toStdString(); }
Expand Down Expand Up @@ -50,23 +54,38 @@ static semaphore<> s_qt_mutex{};
static QApplication app0{argc, argv};
}

QMessageBox msg;
msg.setWindowTitle(tr("RPCS3: Fatal Error"));
msg.setIcon(QMessageBox::Critical);
msg.setTextFormat(Qt::RichText);
msg.setText(QString(R"(
<p style="white-space: nowrap;">
%1<br>
%2<br>
<a href='https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support'>https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support</a><br>
%3<br>
</p>
)")
.arg(Qt::convertFromPlainText(QString::fromStdString(text)))
.arg(tr("HOW TO REPORT ERRORS:"))
.arg(tr("Please, don't send incorrect reports. Thanks for understanding.")));
msg.layout()->setSizeConstraint(QLayout::SetFixedSize);
msg.exec();
auto show_report = [](const std::string& text)
{
QMessageBox msg;
msg.setWindowTitle(tr("RPCS3: Fatal Error"));
msg.setIcon(QMessageBox::Critical);
msg.setTextFormat(Qt::RichText);
msg.setText(QString(R"(
<p style="white-space: nowrap;">
%1<br>
%2<br>
<a href='https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support'>https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support</a><br>
%3<br>
</p>
)")
.arg(Qt::convertFromPlainText(QString::fromStdString(text)))
.arg(tr("HOW TO REPORT ERRORS:"))
.arg(tr("Please, don't send incorrect reports. Thanks for understanding.")));
msg.layout()->setSizeConstraint(QLayout::SetFixedSize);
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();
}
Expand Down
Binary file added rpcs3/rpcs3.icns
Binary file not shown.
10 changes: 7 additions & 3 deletions rpcs3/rpcs3_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,9 +422,13 @@ void rpcs3_app::OnChangeStyleSheetRequest(const QString& path)

QFile file(path);

#if !defined(_WIN32) && !defined(__APPLE__)
// If we can't open the file, try the /share folder
// If we can't open the file, try the /share or /Resources folder
#if !defined(_WIN32)
#ifdef __APPLE__
QString share_dir = QCoreApplication::applicationDirPath() + "/../Resources/";
#else
QString share_dir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/";
#endif
QFile share_file(share_dir + "GuiConfigs/" + QFileInfo(file.fileName()).fileName());
#endif

Expand All @@ -451,7 +455,7 @@ void rpcs3_app::OnChangeStyleSheetRequest(const QString& path)
setStyleSheet(file.readAll());
file.close();
}
#if !defined(_WIN32) && !defined(__APPLE__)
#if !defined(_WIN32)
else if (share_file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QDir::setCurrent(share_dir);
Expand Down
1 change: 1 addition & 0 deletions rpcs3/rpcs3_version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ namespace rpcs3
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 };
}
12 changes: 8 additions & 4 deletions rpcs3/rpcs3qt/gui_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,14 @@ QStringList gui_settings::GetStylesheetEntries()
{
QStringList nameFilter = QStringList("*.qss");
QStringList res = gui::utils::get_dir_entries(m_settingsDir, nameFilter);
#if !defined(_WIN32) && !defined(__APPLE__)
// Makes stylesheets load if using AppImage or installed to /usr/bin
QDir linuxStylesheetDir = QCoreApplication::applicationDirPath() + "/../share/rpcs3/GuiConfigs/";
res.append(gui::utils::get_dir_entries(linuxStylesheetDir, nameFilter));
#if !defined(_WIN32)
// Makes stylesheets load if using AppImage (App Bundle) or installed to /usr/bin
#ifdef __APPLE__
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();
#endif
res.sort(Qt::CaseInsensitive);
Expand Down