Build: Improve MacOS support

This commit is contained in:
Stenzek 2023-09-10 14:14:27 +10:00
parent abb39e8a00
commit b30c86ed75
8 changed files with 108 additions and 68 deletions

View file

@ -46,6 +46,9 @@ endif()
if((LINUX OR FREEBSD) AND NOT ANDROID) if((LINUX OR FREEBSD) AND NOT ANDROID)
option(USE_DBUS "Enable DBus support for screensaver inhibiting" ON) option(USE_DBUS "Enable DBus support for screensaver inhibiting" ON)
endif() endif()
if(APPLE)
option(SKIP_POSTPROCESS_BUNDLE "Disable bundle post-processing, including Qt additions" OFF)
endif()
if(ANDROID) if(ANDROID)
if(CMAKE_BUILD_TYPE STREQUAL "Release") if(CMAKE_BUILD_TYPE STREQUAL "Release")

View file

@ -88,7 +88,8 @@ if(${CPU_ARCH} STREQUAL "aarch64")
) )
endif() endif()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") # Currently disabled becuase the old rec sucks.
message("Enabling vixl debug assertions") #if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
target_compile_definitions(vixl PUBLIC VIXL_DEBUG) # message("Enabling vixl debug assertions")
endif() # target_compile_definitions(vixl PUBLIC VIXL_DEBUG)
#endif()

View file

@ -167,7 +167,30 @@ if(ENABLE_DISCORD_PRESENCE)
target_link_libraries(core PRIVATE discord-rpc) target_link_libraries(core PRIVATE discord-rpc)
endif() endif()
# Copy the provided data directory to the output directory. # Copy the provided data directory to the output directory. Borrowed from PCSX2.
add_custom_command(TARGET core POST_BUILD function(add_resources target path basedir)
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" 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 "$<TARGET_FILE_DIR:${target}>/resources/${subdir}"
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${path}" "$<TARGET_FILE_DIR:${target}>/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()

View file

@ -1904,6 +1904,13 @@ void System::Throttle()
Common::Timer::SleepUntil(s_next_frame_time, false); Common::Timer::SleepUntil(s_next_frame_time, false);
#endif #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; s_next_frame_time += s_frame_period;
} }

View file

@ -164,14 +164,16 @@ set(TS_FILES
translations/duckstation-qt_zh-cn.ts 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}) add_executable(duckstation-qt ${SRCS} ${QM_FILES})
target_precompile_headers(duckstation-qt PRIVATE "pch.h") target_precompile_headers(duckstation-qt PRIVATE "pch.h")
target_include_directories(duckstation-qt PRIVATE "${Qt6Gui_PRIVATE_INCLUDE_DIRS}" "${CMAKE_CURRENT_SOURCE_DIR}") 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) 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) if(WIN32)
target_sources(duckstation-qt PRIVATE duckstation-qt.rc) target_sources(duckstation-qt PRIVATE duckstation-qt.rc)
@ -196,60 +198,45 @@ if(WIN32)
add_custom_command(TARGET duckstation-qt POST_BUILD 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" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/qt.conf.win" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qt.conf"
) )
endif() #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
)
if(APPLE AND NOT CMAKE_GENERATOR MATCHES "Xcode") # Inject Qt Libraries into bundle.
set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DuckStation.app) if(NOT SKIP_POSTPROCESS_BUNDLE)
find_program(MACDEPLOYQT_EXE macdeployqt HINTS "${QT_BINARY_DIRECTORY}")
# Ask for an application bundle. add_custom_target(duckstation-postprocess-bundle ALL
set_target_properties(duckstation-qt PROPERTIES COMMAND "${MACDEPLOYQT_EXE}" "${BUNDLE_PATH}" -no-strip
MACOSX_BUNDLE true )
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in add_dependencies(duckstation-postprocess-bundle duckstation-qt)
OUTPUT_NAME DuckStation endif()
) endif()
# 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)
# Copy icon into the bundle # Copy icon into the bundle
target_sources(duckstation-qt PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/DuckStation.icns") 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) set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/DuckStation.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
# Copy resources into the bundle # Translation setup
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/data/resources") qt_add_lrelease(duckstation-qt TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES)
file(GLOB_RECURSE resources RELATIVE "${CMAKE_SOURCE_DIR}/data/resources" "${CMAKE_SOURCE_DIR}/data/resources/*") foreach (QM_FILE IN LISTS QM_FILES)
foreach(res ${resources}) target_sources(duckstation-qt PRIVATE ${QM_FILE})
target_sources(duckstation-qt PRIVATE "${CMAKE_SOURCE_DIR}/data/resources/${res}") set_source_files_properties(${QM_FILE} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/translations)
get_filename_component(resdir "${res}" DIRECTORY) endforeach()
set_source_files_properties("${CMAKE_SOURCE_DIR}/data/resources/${res}" PROPERTIES else()
MACOSX_PACKAGE_LOCATION "Resources/${resdir}") # TODO: Copy base translations.
source_group("Resources" FILES "${CMAKE_SOURCE_DIR}/data/resources/${res}") qt_add_lrelease(duckstation-qt TS_FILES ${TS_FILES} QM_FILES_OUTPUT_VARIABLE QM_FILES)
endforeach() set(QM_OUTPUT_DIR "$<TARGET_FILE_DIR:duckstation-qt>/translations")
add_custom_command(TARGET duckstation-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E make_directory "${QM_OUTPUT_DIR}")
# Copy translations into the bundle foreach (QM_FILE IN LISTS QM_FILES)
add_custom_command(TARGET duckstation-qt get_filename_component(QM_FILE_NAME ${QM_FILE} NAME)
POST_BUILD add_custom_command(TARGET duckstation-qt POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${QM_FILE}" "${QM_OUTPUT_DIR}/${QM_FILE_NAME}")
COMMAND mkdir -p $<TARGET_FILE_DIR:duckstation-qt>/translations endforeach()
COMMAND cp ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations/*.qm $<TARGET_FILE_DIR:duckstation-qt>/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()
endif() endif()

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "qthost.h" #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. // 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.")); QMessageBox::critical(nullptr, QStringLiteral("Error"), QStringLiteral("Failed to initialize config."));
return EXIT_FAILURE; return false;
} }
// Check the file we're starting actually exists. // Check the file we're starting actually exists.

View file

@ -71,7 +71,12 @@ void QtHost::InstallTranslator()
QString::fromStdString(Host::GetBaseStringSettingValue("Main", "Language", GetDefaultLanguage()))); QString::fromStdString(Host::GetBaseStringSettingValue("Main", "Language", GetDefaultLanguage())));
// install the base qt translation first // 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)); QString base_path(QStringLiteral("%1/qtbase_%2.qm").arg(base_dir).arg(language));
bool has_base_ts = QFile::exists(base_path); bool has_base_ts = QFile::exists(base_path);
if (!has_base_ts) if (!has_base_ts)

View file

@ -157,6 +157,7 @@ if(ENABLE_OPENGL)
gl/context_agl.mm gl/context_agl.mm
gl/context_agl.h gl/context_agl.h
) )
set_source_files_properties(gl/context_agl.mm PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE)
endif() endif()
endif() endif()
@ -191,11 +192,6 @@ if(ENABLE_VULKAN)
vulkan_texture.h vulkan_texture.h
) )
target_compile_definitions(util PUBLIC "WITH_VULKAN=1") target_compile_definitions(util PUBLIC "WITH_VULKAN=1")
if(APPLE)
# Needed for Vulkan Swap Chain.
target_link_libraries(util PRIVATE "objc")
endif()
endif() endif()
if(USE_SDL2) if(USE_SDL2)
@ -287,3 +283,21 @@ elseif(NOT ANDROID)
platform_misc_unix.cpp platform_misc_unix.cpp
) )
endif() 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()