From b30c86ed7541574de9f71701d9a8831b71f8b9c4 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 10 Sep 2023 14:14:27 +1000 Subject: [PATCH] Build: Improve MacOS support --- CMakeLists.txt | 3 + dep/vixl/CMakeLists.txt | 9 +-- src/core/CMakeLists.txt | 31 +++++++-- src/core/system.cpp | 7 ++ src/duckstation-qt/CMakeLists.txt | 93 ++++++++++++--------------- src/duckstation-qt/qthost.cpp | 4 +- src/duckstation-qt/qttranslations.cpp | 7 +- src/util/CMakeLists.txt | 24 +++++-- 8 files changed, 109 insertions(+), 69 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d35c29521..0ce97fc15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,6 +46,9 @@ endif() if((LINUX OR FREEBSD) AND NOT ANDROID) option(USE_DBUS "Enable DBus support for screensaver inhibiting" ON) endif() +if(APPLE) + option(SKIP_POSTPROCESS_BUNDLE "Disable bundle post-processing, including Qt additions" OFF) +endif() if(ANDROID) if(CMAKE_BUILD_TYPE STREQUAL "Release") diff --git a/dep/vixl/CMakeLists.txt b/dep/vixl/CMakeLists.txt index d7e4655aa..4ec955642 100644 --- a/dep/vixl/CMakeLists.txt +++ b/dep/vixl/CMakeLists.txt @@ -88,7 +88,8 @@ if(${CPU_ARCH} STREQUAL "aarch64") ) endif() -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - message("Enabling vixl debug assertions") - target_compile_definitions(vixl PUBLIC VIXL_DEBUG) -endif() +# Currently disabled becuase the old rec sucks. +#if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") +# message("Enabling vixl debug assertions") +# target_compile_definitions(vixl PUBLIC VIXL_DEBUG) +#endif() diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a10a2c423..ad22b468d 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -167,7 +167,30 @@ if(ENABLE_DISCORD_PRESENCE) target_link_libraries(core PRIVATE discord-rpc) endif() -# Copy the provided data directory to the output directory. -add_custom_command(TARGET core POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" -) +# Copy the provided data directory to the output directory. Borrowed from PCSX2. +function(add_resources target path basedir) + get_filename_component(dir ${path} DIRECTORY) + file(RELATIVE_PATH subdir ${basedir} ${dir}) + if(APPLE) + target_sources(${target} PRIVATE ${path}) + set_source_files_properties(${path} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/${subdir}) + else() + add_custom_command(TARGET ${target} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E make_directory "$/resources/${subdir}" + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${path}" "$/resources/${subdir}") + endif() + source_group(Resources/${subdir} FILES ${path}) +endfunction() + +function(add_core_resources target) + add_util_resources(${target}) + + file(GLOB_RECURSE RESOURCE_FILES ${CMAKE_SOURCE_DIR}/data/resources/*) + foreach(path IN LISTS RESOURCE_FILES) + get_filename_component(file ${path} NAME) + if("${file}" MATCHES "^\\.") # Don't copy macOS garbage (mainly Finder's .DS_Store files) into application + continue() + endif() + add_resources(${target} ${path} ${CMAKE_SOURCE_DIR}/data/resources/) + endforeach() +endfunction() diff --git a/src/core/system.cpp b/src/core/system.cpp index eac7c2fad..dcbd6d6ab 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1904,6 +1904,13 @@ void System::Throttle() Common::Timer::SleepUntil(s_next_frame_time, false); #endif +#if 0 + Log_DevPrintf("Asked for %.2f ms, slept for %.2f ms, %.2f ms late", + Common::Timer::ConvertValueToMilliseconds(s_next_frame_time - current_time), + Common::Timer::ConvertValueToMilliseconds(Common::Timer::GetCurrentValue() - current_time), + Common::Timer::ConvertValueToMilliseconds(Common::Timer::GetCurrentValue() - s_next_frame_time)); +#endif + s_next_frame_time += s_frame_period; } diff --git a/src/duckstation-qt/CMakeLists.txt b/src/duckstation-qt/CMakeLists.txt index e06975cb4..3a066493f 100644 --- a/src/duckstation-qt/CMakeLists.txt +++ b/src/duckstation-qt/CMakeLists.txt @@ -164,14 +164,16 @@ set(TS_FILES translations/duckstation-qt_zh-cn.ts ) -set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations") -qt6_add_translation(QM_FILES ${TS_FILES}) - add_executable(duckstation-qt ${SRCS} ${QM_FILES}) target_precompile_headers(duckstation-qt PRIVATE "pch.h") target_include_directories(duckstation-qt PRIVATE "${Qt6Gui_PRIVATE_INCLUDE_DIRS}" "${CMAKE_CURRENT_SOURCE_DIR}") target_link_libraries(duckstation-qt PRIVATE core common imgui minizip scmversion Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network) +# Our Qt builds may have exceptions on, so force them off. +target_compile_definitions(duckstation-qt PRIVATE QT_NO_EXCEPTIONS) + +add_core_resources(duckstation-qt) + if(WIN32) target_sources(duckstation-qt PRIVATE duckstation-qt.rc) @@ -196,60 +198,45 @@ if(WIN32) add_custom_command(TARGET duckstation-qt POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qt.conf.win" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qt.conf" ) -endif() - -if(APPLE AND NOT CMAKE_GENERATOR MATCHES "Xcode") - 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 - ) - - # Use macdeployqt to inject Qt into the bundle. - get_target_property(MOC_EXECUTABLE_LOCATION Qt6::moc IMPORTED_LOCATION) - get_filename_component(QT_BINARY_DIRECTORY "${MOC_EXECUTABLE_LOCATION}" DIRECTORY) - find_program(MACDEPLOYQT_EXE macdeployqt HINTS "${QT_BINARY_DIRECTORY}") - add_custom_target(duckstation-postprocess-bundle ALL - COMMAND "${MACDEPLOYQT_EXE}" "${BUNDLE_PATH}" -no-strip - ) - add_dependencies(duckstation-postprocess-bundle duckstation-qt) + #set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations") +elseif(APPLE) + # Don't generate a bundle for XCode, it makes code signing fail... + if(NOT CMAKE_GENERATOR MATCHES "Xcode") + set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DuckStation.app) + set_target_properties(duckstation-qt PROPERTIES + MACOSX_BUNDLE true + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in + OUTPUT_NAME DuckStation + ) + + # Inject Qt Libraries into bundle. + if(NOT SKIP_POSTPROCESS_BUNDLE) + find_program(MACDEPLOYQT_EXE macdeployqt HINTS "${QT_BINARY_DIRECTORY}") + add_custom_target(duckstation-postprocess-bundle ALL + COMMAND "${MACDEPLOYQT_EXE}" "${BUNDLE_PATH}" -no-strip + ) + add_dependencies(duckstation-postprocess-bundle duckstation-qt) + endif() + endif() # 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 resources into the bundle - set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/data/resources") - file(GLOB_RECURSE resources RELATIVE "${CMAKE_SOURCE_DIR}/data/resources" "${CMAKE_SOURCE_DIR}/data/resources/*") - foreach(res ${resources}) - target_sources(duckstation-qt PRIVATE "${CMAKE_SOURCE_DIR}/data/resources/${res}") - get_filename_component(resdir "${res}" DIRECTORY) - set_source_files_properties("${CMAKE_SOURCE_DIR}/data/resources/${res}" PROPERTIES - MACOSX_PACKAGE_LOCATION "Resources/${resdir}") - source_group("Resources" FILES "${CMAKE_SOURCE_DIR}/data/resources/${res}") - endforeach() - - # Copy translations into the bundle - add_custom_command(TARGET duckstation-qt - POST_BUILD - COMMAND mkdir -p $/translations - COMMAND cp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations/*.qm $/translations) - - # Copy MoltenVK into the bundle - unset(MOLTENVK_PATH CACHE) - find_file(MOLTENVK_PATH NAMES - libMoltenVK.dylib - lib/libMoltenVK.dylib - ) - if (MOLTENVK_PATH) - target_sources(duckstation-qt PRIVATE "${MOLTENVK_PATH}") - set_source_files_properties("${MOLTENVK_PATH}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks) - message(STATUS "Using MoltenVK from ${MOLTENVK_PATH}") - else() - message(WARNING "MoltenVK not found in path, it will depend on the target system having it.") - endif() + # Translation setup + qt_add_lrelease(duckstation-qt TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES) + foreach (QM_FILE IN LISTS QM_FILES) + target_sources(duckstation-qt PRIVATE ${QM_FILE}) + set_source_files_properties(${QM_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/translations) + endforeach() +else() + # TODO: Copy base translations. + qt_add_lrelease(duckstation-qt TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES) + set(QM_OUTPUT_DIR "$/translations") + add_custom_command(TARGET duckstation-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E make_directory "${QM_OUTPUT_DIR}") + foreach (QM_FILE IN LISTS QM_FILES) + get_filename_component(QM_FILE_NAME ${QM_FILE} NAME) + add_custom_command(TARGET duckstation-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${QM_FILE}" "${QM_OUTPUT_DIR}/${QM_FILE_NAME}") + endforeach() endif() diff --git a/src/duckstation-qt/qthost.cpp b/src/duckstation-qt/qthost.cpp index 100e1c532..57f23f71a 100644 --- a/src/duckstation-qt/qthost.cpp +++ b/src/duckstation-qt/qthost.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin +// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "qthost.h" @@ -1939,7 +1939,7 @@ bool QtHost::ParseCommandLineParametersAndInitializeConfig(QApplication& app, { // NOTE: No point translating this, because no config means the language won't be loaded anyway. QMessageBox::critical(nullptr, QStringLiteral("Error"), QStringLiteral("Failed to initialize config.")); - return EXIT_FAILURE; + return false; } // Check the file we're starting actually exists. diff --git a/src/duckstation-qt/qttranslations.cpp b/src/duckstation-qt/qttranslations.cpp index 032891434..350cb2c8f 100644 --- a/src/duckstation-qt/qttranslations.cpp +++ b/src/duckstation-qt/qttranslations.cpp @@ -71,7 +71,12 @@ void QtHost::InstallTranslator() QString::fromStdString(Host::GetBaseStringSettingValue("Main", "Language", GetDefaultLanguage()))); // install the base qt translation first - const QString base_dir(QStringLiteral("%1/translations").arg(qApp->applicationDirPath())); +#ifndef __APPLE__ + const QString base_dir = QStringLiteral("%1/translations").arg(qApp->applicationDirPath()); +#else + const QString base_dir = QStringLiteral("%1/../Resources/translations").arg(qApp->applicationDirPath()); +#endif + QString base_path(QStringLiteral("%1/qtbase_%2.qm").arg(base_dir).arg(language)); bool has_base_ts = QFile::exists(base_path); if (!has_base_ts) diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 491149a27..cf61315f7 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -157,6 +157,7 @@ if(ENABLE_OPENGL) gl/context_agl.mm gl/context_agl.h ) + set_source_files_properties(gl/context_agl.mm PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE) endif() endif() @@ -191,11 +192,6 @@ if(ENABLE_VULKAN) vulkan_texture.h ) target_compile_definitions(util PUBLIC "WITH_VULKAN=1") - - if(APPLE) - # Needed for Vulkan Swap Chain. - target_link_libraries(util PRIVATE "objc") - endif() endif() if(USE_SDL2) @@ -287,3 +283,21 @@ elseif(NOT ANDROID) platform_misc_unix.cpp ) endif() + +function(add_util_resources target) + if(APPLE) + # Copy MoltenVK into the bundle + unset(MOLTENVK_PATH CACHE) + find_file(MOLTENVK_PATH NAMES + libMoltenVK.dylib + lib/libMoltenVK.dylib + ) + if (MOLTENVK_PATH) + target_sources(${target} PRIVATE "${MOLTENVK_PATH}") + set_source_files_properties("${MOLTENVK_PATH}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks) + message(STATUS "Using MoltenVK from ${MOLTENVK_PATH}") + else() + message(WARNING "MoltenVK not found in path, it will depend on the target system having it.") + endif() + endif() +endfunction()