Initial Commit
This commit is contained in:
58
CMakeModules/AndroidNdkModules.cmake
Normal file
58
CMakeModules/AndroidNdkModules.cmake
Normal file
@ -0,0 +1,58 @@
|
||||
# Copyright (c) 2014, Pavel Rojtberg
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from this
|
||||
# software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
macro(android_ndk_import_module_cpufeatures)
|
||||
if(ANDROID)
|
||||
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
|
||||
add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
|
||||
target_link_libraries(cpufeatures dl)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(android_ndk_import_module_native_app_glue)
|
||||
if(ANDROID)
|
||||
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
|
||||
add_library(native_app_glue ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
|
||||
target_link_libraries(native_app_glue log)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(android_ndk_import_module_ndk_helper)
|
||||
if(ANDROID)
|
||||
android_ndk_import_module_cpufeatures()
|
||||
android_ndk_import_module_native_app_glue()
|
||||
|
||||
include_directories(${ANDROID_NDK}/sources/android/ndk_helper)
|
||||
file(GLOB _NDK_HELPER_SRCS ${ANDROID_NDK}/sources/android/ndk_helper/*.cpp ${ANDROID_NDK}/sources/android/ndk_helper/gl3stub.c)
|
||||
add_library(ndk_helper ${_NDK_HELPER_SRCS})
|
||||
target_link_libraries(ndk_helper log android EGL GLESv2 cpufeatures native_app_glue)
|
||||
|
||||
unset(_NDK_HELPER_SRCS)
|
||||
endif()
|
||||
endmacro()
|
26
CMakeModules/BuildInstaller.cmake
Normal file
26
CMakeModules/BuildInstaller.cmake
Normal file
@ -0,0 +1,26 @@
|
||||
# To use this as a script, make sure you pass in the variables BASE_DIR, SRC_DIR, BUILD_DIR, and TARGET_FILE
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
if(WIN32)
|
||||
set(PLATFORM "windows")
|
||||
elseif(APPLE)
|
||||
set(PLATFORM "mac")
|
||||
elseif(UNIX)
|
||||
set(PLATFORM "linux")
|
||||
else()
|
||||
message(FATAL_ERROR "Cannot build installer for this unsupported platform")
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${BASE_DIR}/CMakeModules")
|
||||
include(DownloadExternals)
|
||||
download_qt(tools_ifw)
|
||||
get_external_prefix(qt QT_PREFIX)
|
||||
|
||||
file(GLOB_RECURSE INSTALLER_BASE "${QT_PREFIX}/**/installerbase*")
|
||||
file(GLOB_RECURSE BINARY_CREATOR "${QT_PREFIX}/**/binarycreator*")
|
||||
|
||||
set(CONFIG_FILE "${SRC_DIR}/config/config_${PLATFORM}.xml")
|
||||
set(PACKAGES_DIR "${BUILD_DIR}/packages")
|
||||
file(MAKE_DIRECTORY ${PACKAGES_DIR})
|
||||
|
||||
execute_process(COMMAND ${BINARY_CREATOR} -t ${INSTALLER_BASE} -n -c ${CONFIG_FILE} -p ${PACKAGES_DIR} ${TARGET_FILE})
|
374
CMakeModules/BundleTarget.cmake
Normal file
374
CMakeModules/BundleTarget.cmake
Normal file
@ -0,0 +1,374 @@
|
||||
|
||||
if (BUNDLE_TARGET_EXECUTE)
|
||||
# --- Bundling method logic ---
|
||||
|
||||
function(symlink_safe_copy from to)
|
||||
if (WIN32)
|
||||
# Use cmake copy for maximum compatibility.
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E copy "${from}" "${to}"
|
||||
RESULT_VARIABLE cp_result)
|
||||
else()
|
||||
# Use native copy to turn symlinks into normal files.
|
||||
execute_process(COMMAND cp -L "${from}" "${to}"
|
||||
RESULT_VARIABLE cp_result)
|
||||
endif()
|
||||
if (NOT cp_result EQUAL "0")
|
||||
message(FATAL_ERROR "cp \"${from}\" \"${to}\" failed: ${cp_result}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(bundle_qt executable_path)
|
||||
if (WIN32)
|
||||
# Perform standalone bundling first to copy over all used libraries, as windeployqt does not do this.
|
||||
bundle_standalone("${executable_path}" "${EXECUTABLE_PATH}" "${BUNDLE_LIBRARY_PATHS}")
|
||||
|
||||
get_filename_component(executable_parent_dir "${executable_path}" DIRECTORY)
|
||||
|
||||
# Create a qt.conf file pointing to the app directory.
|
||||
# This ensures Qt can find its plugins.
|
||||
file(WRITE "${executable_parent_dir}/qt.conf" "[Paths]\nPrefix = .")
|
||||
|
||||
find_program(windeployqt_executable windeployqt6 PATHS "${QT_HOST_PATH}/bin")
|
||||
find_program(qtpaths_executable qtpaths6 PATHS "${QT_HOST_PATH}/bin")
|
||||
|
||||
# TODO: Hack around windeployqt's poor cross-compilation support by
|
||||
# TODO: making a local copy with a prefix pointing to the target Qt.
|
||||
if (NOT "${QT_HOST_PATH}" STREQUAL "${QT_TARGET_PATH}")
|
||||
set(windeployqt_dir "${BINARY_PATH}/windeployqt_copy")
|
||||
file(MAKE_DIRECTORY "${windeployqt_dir}")
|
||||
symlink_safe_copy("${windeployqt_executable}" "${windeployqt_dir}/windeployqt.exe")
|
||||
symlink_safe_copy("${qtpaths_executable}" "${windeployqt_dir}/qtpaths.exe")
|
||||
symlink_safe_copy("${QT_HOST_PATH}/bin/Qt6Core.dll" "${windeployqt_dir}")
|
||||
|
||||
if (EXISTS "${QT_TARGET_PATH}/share")
|
||||
# Unix-style Qt; we need to wire up the paths manually.
|
||||
file(WRITE "${windeployqt_dir}/qt.conf" "\
|
||||
[Paths]\n
|
||||
Prefix = ${QT_TARGET_PATH}\n \
|
||||
ArchData = ${QT_TARGET_PATH}/share/qt6\n \
|
||||
Binaries = ${QT_TARGET_PATH}/bin\n \
|
||||
Data = ${QT_TARGET_PATH}/share/qt6\n \
|
||||
Documentation = ${QT_TARGET_PATH}/share/qt6/doc\n \
|
||||
Headers = ${QT_TARGET_PATH}/include/qt6\n \
|
||||
Libraries = ${QT_TARGET_PATH}/lib\n \
|
||||
LibraryExecutables = ${QT_TARGET_PATH}/share/qt6/bin\n \
|
||||
Plugins = ${QT_TARGET_PATH}/share/qt6/plugins\n \
|
||||
QmlImports = ${QT_TARGET_PATH}/share/qt6/qml\n \
|
||||
Translations = ${QT_TARGET_PATH}/share/qt6/translations\n \
|
||||
")
|
||||
else()
|
||||
# Windows-style Qt; the defaults should suffice.
|
||||
file(WRITE "${windeployqt_dir}/qt.conf" "[Paths]\nPrefix = ${QT_TARGET_PATH}")
|
||||
endif()
|
||||
|
||||
set(windeployqt_executable "${windeployqt_dir}/windeployqt.exe")
|
||||
set(qtpaths_executable "${windeployqt_dir}/qtpaths.exe")
|
||||
endif()
|
||||
|
||||
message(STATUS "Executing windeployqt for executable ${executable_path}")
|
||||
execute_process(COMMAND "${windeployqt_executable}" "${executable_path}"
|
||||
--qtpaths "${qtpaths_executable}"
|
||||
--no-compiler-runtime --no-system-d3d-compiler --no-opengl-sw --no-translations
|
||||
--plugindir "${executable_parent_dir}/plugins"
|
||||
RESULT_VARIABLE windeployqt_result)
|
||||
if (NOT windeployqt_result EQUAL "0")
|
||||
message(FATAL_ERROR "windeployqt failed: ${windeployqt_result}")
|
||||
endif()
|
||||
|
||||
# Remove the FFmpeg multimedia plugin as we don't include FFmpeg.
|
||||
# We want to use the Windows media plugin instead, which is also included.
|
||||
file(REMOVE "${executable_parent_dir}/plugins/multimedia/ffmpegmediaplugin.dll")
|
||||
elseif (APPLE)
|
||||
get_filename_component(executable_name "${executable_path}" NAME_WE)
|
||||
find_program(macdeployqt_executable macdeployqt6 PATHS "${QT_HOST_PATH}/bin")
|
||||
|
||||
message(STATUS "Executing macdeployqt at \"${macdeployqt_executable}\" for executable \"${executable_path}\"")
|
||||
execute_process(
|
||||
COMMAND "${macdeployqt_executable}"
|
||||
"${executable_path}"
|
||||
"-executable=${executable_path}/Contents/MacOS/${executable_name}"
|
||||
-always-overwrite
|
||||
RESULT_VARIABLE macdeployqt_result)
|
||||
if (NOT macdeployqt_result EQUAL "0")
|
||||
message(FATAL_ERROR "macdeployqt failed: ${macdeployqt_result}")
|
||||
endif()
|
||||
|
||||
# Bundling libraries can rewrite path information and break code signatures of system libraries.
|
||||
# Perform an ad-hoc re-signing on the whole app bundle to fix this.
|
||||
execute_process(COMMAND codesign --deep -fs - "${executable_path}"
|
||||
RESULT_VARIABLE codesign_result)
|
||||
if (NOT codesign_result EQUAL "0")
|
||||
message(FATAL_ERROR "codesign failed: ${codesign_result}")
|
||||
endif()
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported OS for Qt bundling.")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(bundle_appimage bundle_dir executable_path source_path binary_path linuxdeploy_executable enable_qt)
|
||||
get_filename_component(executable_name "${executable_path}" NAME_WE)
|
||||
set(appdir_path "${binary_path}/AppDir-${executable_name}")
|
||||
|
||||
if (enable_qt)
|
||||
# Find qmake to make sure the plugin uses the right version of Qt.
|
||||
find_program(qmake_executable qmake6 PATHS "${QT_HOST_PATH}/bin")
|
||||
|
||||
set(extra_linuxdeploy_env "QMAKE=${qmake_executable}")
|
||||
set(extra_linuxdeploy_args --plugin qt)
|
||||
endif()
|
||||
|
||||
message(STATUS "Creating AppDir for executable ${executable_path}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E env
|
||||
${extra_linuxdeploy_env}
|
||||
"${linuxdeploy_executable}"
|
||||
${extra_linuxdeploy_args}
|
||||
--plugin checkrt
|
||||
--executable "${executable_path}"
|
||||
--icon-file "${source_path}/dist/citra.svg"
|
||||
--desktop-file "${source_path}/dist/${executable_name}.desktop"
|
||||
--appdir "${appdir_path}"
|
||||
RESULT_VARIABLE linuxdeploy_appdir_result)
|
||||
if (NOT linuxdeploy_appdir_result EQUAL "0")
|
||||
message(FATAL_ERROR "linuxdeploy failed to create AppDir: ${linuxdeploy_appdir_result}")
|
||||
endif()
|
||||
|
||||
if (enable_qt)
|
||||
set(qt_hook_file "${appdir_path}/apprun-hooks/linuxdeploy-plugin-qt-hook.sh")
|
||||
file(READ "${qt_hook_file}" qt_hook_contents)
|
||||
# Add Cinnamon to list of DEs for GTK3 theming.
|
||||
string(REPLACE
|
||||
"*XFCE*"
|
||||
"*X-Cinnamon*|*XFCE*"
|
||||
qt_hook_contents "${qt_hook_contents}")
|
||||
# Wayland backend crashes due to changed schemas in Gnome 40.
|
||||
string(REPLACE
|
||||
"export QT_QPA_PLATFORMTHEME=gtk3"
|
||||
"export QT_QPA_PLATFORMTHEME=gtk3; export GDK_BACKEND=x11"
|
||||
qt_hook_contents "${qt_hook_contents}")
|
||||
file(WRITE "${qt_hook_file}" "${qt_hook_contents}")
|
||||
endif()
|
||||
|
||||
message(STATUS "Creating AppImage for executable ${executable_path}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E env
|
||||
"OUTPUT=${bundle_dir}/${executable_name}.AppImage"
|
||||
"${linuxdeploy_executable}"
|
||||
--output appimage
|
||||
--appdir "${appdir_path}"
|
||||
RESULT_VARIABLE linuxdeploy_appimage_result)
|
||||
if (NOT linuxdeploy_appimage_result EQUAL "0")
|
||||
message(FATAL_ERROR "linuxdeploy failed to create AppImage: ${linuxdeploy_appimage_result}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(bundle_standalone executable_path original_executable_path bundle_library_paths)
|
||||
get_filename_component(executable_parent_dir "${executable_path}" DIRECTORY)
|
||||
|
||||
# Resolve dependent library files if they were not passed in.
|
||||
message(STATUS "Determining runtime dependencies of ${executable_path} using library paths ${bundle_library_paths}")
|
||||
file(GET_RUNTIME_DEPENDENCIES
|
||||
EXECUTABLES ${original_executable_path}
|
||||
RESOLVED_DEPENDENCIES_VAR resolved_deps
|
||||
UNRESOLVED_DEPENDENCIES_VAR unresolved_deps
|
||||
DIRECTORIES ${bundle_library_paths}
|
||||
POST_EXCLUDE_REGEXES ".*system32.*")
|
||||
|
||||
if (WIN32)
|
||||
# Same directory since we don't have rpath.
|
||||
set(lib_dir "${executable_parent_dir}")
|
||||
else()
|
||||
set(lib_dir "${executable_parent_dir}/libs")
|
||||
endif()
|
||||
|
||||
# Copy files to bundled output.
|
||||
if (resolved_deps)
|
||||
file(MAKE_DIRECTORY ${lib_dir})
|
||||
foreach (lib_file IN LISTS resolved_deps)
|
||||
message(STATUS "Bundling library ${lib_file}")
|
||||
symlink_safe_copy("${lib_file}" "${lib_dir}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Add libs directory to executable rpath where applicable.
|
||||
if (APPLE)
|
||||
execute_process(COMMAND install_name_tool -add_rpath "@loader_path/libs" "${executable_path}"
|
||||
RESULT_VARIABLE install_name_tool_result)
|
||||
if (NOT install_name_tool_result EQUAL "0")
|
||||
message(FATAL_ERROR "install_name_tool failed: ${install_name_tool_result}")
|
||||
endif()
|
||||
elseif (UNIX)
|
||||
execute_process(COMMAND patchelf --set-rpath '$ORIGIN/../libs' "${executable_path}"
|
||||
RESULT_VARIABLE patchelf_result)
|
||||
if (NOT patchelf_result EQUAL "0")
|
||||
message(FATAL_ERROR "patchelf failed: ${patchelf_result}")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# --- Root bundling logic ---
|
||||
|
||||
set(bundle_dir ${BINARY_PATH}/bundle)
|
||||
|
||||
# On Linux, always bundle an AppImage.
|
||||
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
||||
if (IN_PLACE)
|
||||
message(FATAL_ERROR "Cannot bundle for Linux in-place.")
|
||||
endif()
|
||||
|
||||
bundle_appimage("${bundle_dir}" "${EXECUTABLE_PATH}" "${SOURCE_PATH}" "${BINARY_PATH}" "${LINUXDEPLOY}" ${BUNDLE_QT})
|
||||
else()
|
||||
if (IN_PLACE)
|
||||
message(STATUS "Bundling dependencies in-place")
|
||||
set(bundled_executable_path "${EXECUTABLE_PATH}")
|
||||
else()
|
||||
message(STATUS "Copying base executable ${EXECUTABLE_PATH} to output directory ${bundle_dir}")
|
||||
file(COPY ${EXECUTABLE_PATH} DESTINATION ${bundle_dir})
|
||||
get_filename_component(bundled_executable_name "${EXECUTABLE_PATH}" NAME)
|
||||
set(bundled_executable_path "${bundle_dir}/${bundled_executable_name}")
|
||||
endif()
|
||||
|
||||
if (BUNDLE_QT)
|
||||
bundle_qt("${bundled_executable_path}")
|
||||
else()
|
||||
bundle_standalone("${bundled_executable_path}" "${EXECUTABLE_PATH}" "${BUNDLE_LIBRARY_PATHS}")
|
||||
endif()
|
||||
endif()
|
||||
elseif (BUNDLE_TARGET_DOWNLOAD_LINUXDEPLOY)
|
||||
# --- linuxdeploy download logic ---
|
||||
|
||||
# Downloads and extracts a linuxdeploy component.
|
||||
function(download_linuxdeploy_component base_dir name executable_name)
|
||||
set(executable_file "${base_dir}/${executable_name}")
|
||||
if (NOT EXISTS "${executable_file}")
|
||||
message(STATUS "Downloading ${executable_name}")
|
||||
file(DOWNLOAD
|
||||
"https://github.com/${name}/releases/download/continuous/${executable_name}"
|
||||
"${executable_file}" SHOW_PROGRESS)
|
||||
file(CHMOD "${executable_file}" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
|
||||
|
||||
get_filename_component(executable_ext "${executable_file}" LAST_EXT)
|
||||
if (executable_ext STREQUAL ".AppImage")
|
||||
message(STATUS "Extracting ${executable_name}")
|
||||
execute_process(
|
||||
COMMAND "${executable_file}" --appimage-extract
|
||||
WORKING_DIRECTORY "${base_dir}"
|
||||
RESULT_VARIABLE extract_result)
|
||||
if (NOT extract_result EQUAL "0")
|
||||
message(FATAL_ERROR "AppImage extract failed: ${extract_result}")
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Copying ${executable_name}")
|
||||
file(COPY "${executable_file}" DESTINATION "${base_dir}/squashfs-root/usr/bin/")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Download plugins first so they don't overwrite linuxdeploy's AppRun file.
|
||||
download_linuxdeploy_component("${LINUXDEPLOY_PATH}" "linuxdeploy/linuxdeploy-plugin-qt" "linuxdeploy-plugin-qt-${LINUXDEPLOY_ARCH}.AppImage")
|
||||
download_linuxdeploy_component("${LINUXDEPLOY_PATH}" "darealshinji/linuxdeploy-plugin-checkrt" "linuxdeploy-plugin-checkrt.sh")
|
||||
download_linuxdeploy_component("${LINUXDEPLOY_PATH}" "linuxdeploy/linuxdeploy" "linuxdeploy-${LINUXDEPLOY_ARCH}.AppImage")
|
||||
else()
|
||||
# --- Bundling target creation logic ---
|
||||
|
||||
# Creates the base bundle target with common files and pre-bundle steps.
|
||||
function(create_base_bundle_target)
|
||||
message(STATUS "Creating base bundle target")
|
||||
|
||||
add_custom_target(bundle)
|
||||
add_custom_command(
|
||||
TARGET bundle
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/")
|
||||
add_custom_command(
|
||||
TARGET bundle
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/bundle/dist/")
|
||||
add_custom_command(
|
||||
TARGET bundle
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/dist/icon.png" "${CMAKE_BINARY_DIR}/bundle/dist/citra.png")
|
||||
add_custom_command(
|
||||
TARGET bundle
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/license.txt" "${CMAKE_BINARY_DIR}/bundle/")
|
||||
add_custom_command(
|
||||
TARGET bundle
|
||||
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_SOURCE_DIR}/README.md" "${CMAKE_BINARY_DIR}/bundle/")
|
||||
add_custom_command(
|
||||
TARGET bundle
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/dist/scripting" "${CMAKE_BINARY_DIR}/bundle/scripting")
|
||||
|
||||
# On Linux, add a command to prepare linuxdeploy and any required plugins before any bundling occurs.
|
||||
if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
|
||||
add_custom_command(
|
||||
TARGET bundle
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DBUNDLE_TARGET_DOWNLOAD_LINUXDEPLOY=1"
|
||||
"-DLINUXDEPLOY_PATH=${CMAKE_BINARY_DIR}/externals/linuxdeploy"
|
||||
"-DLINUXDEPLOY_ARCH=${CMAKE_HOST_SYSTEM_PROCESSOR}"
|
||||
-P "${CMAKE_SOURCE_DIR}/CMakeModules/BundleTarget.cmake"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Adds a target to the bundle target, packing in required libraries.
|
||||
# If in_place is true, the bundling will be done in-place as part of the specified target.
|
||||
function(bundle_target_internal target_name in_place)
|
||||
# Create base bundle target if it does not exist.
|
||||
if (NOT in_place AND NOT TARGET bundle)
|
||||
create_base_bundle_target()
|
||||
endif()
|
||||
|
||||
set(bundle_executable_path "$<TARGET_FILE:${target_name}>")
|
||||
if (target_name MATCHES ".*qt")
|
||||
set(bundle_qt ON)
|
||||
if (APPLE)
|
||||
# For Qt targets on Apple, expect an app bundle.
|
||||
set(bundle_executable_path "$<TARGET_BUNDLE_DIR:${target_name}>")
|
||||
endif()
|
||||
else()
|
||||
set(bundle_qt OFF)
|
||||
endif()
|
||||
|
||||
# Build a list of library search paths from prefix paths.
|
||||
foreach(prefix_path IN LISTS CMAKE_FIND_ROOT_PATH CMAKE_PREFIX_PATH CMAKE_SYSTEM_PREFIX_PATH)
|
||||
if (WIN32)
|
||||
list(APPEND bundle_library_paths "${prefix_path}/bin")
|
||||
endif()
|
||||
list(APPEND bundle_library_paths "${prefix_path}/lib")
|
||||
endforeach()
|
||||
foreach(library_path IN LISTS CMAKE_SYSTEM_LIBRARY_PATH)
|
||||
list(APPEND bundle_library_paths "${library_path}")
|
||||
endforeach()
|
||||
|
||||
if (in_place)
|
||||
message(STATUS "Adding in-place bundling to ${target_name}")
|
||||
set(dest_target ${target_name})
|
||||
else()
|
||||
message(STATUS "Adding ${target_name} to bundle target")
|
||||
set(dest_target bundle)
|
||||
add_dependencies(bundle ${target_name})
|
||||
endif()
|
||||
|
||||
add_custom_command(TARGET ${dest_target} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-DQT_HOST_PATH=\"${QT_HOST_PATH}\""
|
||||
"-DQT_TARGET_PATH=\"${QT_TARGET_PATH}\""
|
||||
"-DBUNDLE_TARGET_EXECUTE=1"
|
||||
"-DTARGET=${target_name}"
|
||||
"-DSOURCE_PATH=${CMAKE_SOURCE_DIR}"
|
||||
"-DBINARY_PATH=${CMAKE_BINARY_DIR}"
|
||||
"-DEXECUTABLE_PATH=${bundle_executable_path}"
|
||||
"-DBUNDLE_LIBRARY_PATHS=\"${bundle_library_paths}\""
|
||||
"-DBUNDLE_QT=${bundle_qt}"
|
||||
"-DIN_PLACE=${in_place}"
|
||||
"-DLINUXDEPLOY=${CMAKE_BINARY_DIR}/externals/linuxdeploy/squashfs-root/AppRun"
|
||||
-P "${CMAKE_SOURCE_DIR}/CMakeModules/BundleTarget.cmake"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
endfunction()
|
||||
|
||||
# Adds a target to the bundle target, packing in required libraries.
|
||||
function(bundle_target target_name)
|
||||
bundle_target_internal("${target_name}" OFF)
|
||||
endfunction()
|
||||
|
||||
# Bundles the target in-place, packing in required libraries.
|
||||
function(bundle_target_in_place target_name)
|
||||
bundle_target_internal("${target_name}" ON)
|
||||
endfunction()
|
||||
endif()
|
198
CMakeModules/DownloadExternals.cmake
Normal file
198
CMakeModules/DownloadExternals.cmake
Normal file
@ -0,0 +1,198 @@
|
||||
|
||||
set(CURRENT_MODULE_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Determines parameters based on the host and target for downloading the right Qt binaries.
|
||||
function(determine_qt_parameters target host_out type_out arch_out arch_path_out host_type_out host_arch_out host_arch_path_out)
|
||||
if (target MATCHES "tools_.*")
|
||||
set(tool ON)
|
||||
else()
|
||||
set(tool OFF)
|
||||
endif()
|
||||
|
||||
# Determine installation parameters for OS, architecture, and compiler
|
||||
if (WIN32)
|
||||
set(host "windows")
|
||||
set(type "desktop")
|
||||
|
||||
if (NOT tool)
|
||||
if (MINGW)
|
||||
set(arch "win64_mingw")
|
||||
set(arch_path "mingw_64")
|
||||
elseif (MSVC)
|
||||
if ("arm64" IN_LIST ARCHITECTURE)
|
||||
set(arch_path "msvc2019_arm64")
|
||||
elseif ("x86_64" IN_LIST ARCHITECTURE)
|
||||
set(arch_path "msvc2019_64")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported bundled Qt architecture. Enable USE_SYSTEM_QT and provide your own.")
|
||||
endif()
|
||||
set(arch "win64_${arch_path}")
|
||||
|
||||
# In case we're cross-compiling, prepare to also fetch the correct host Qt tools.
|
||||
if (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "AMD64")
|
||||
set(host_arch_path "msvc2019_64")
|
||||
elseif (CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
# TODO: msvc2019_arm64 doesn't include some of the required tools for some reason,
|
||||
# TODO: so until it does, just use msvc2019_64 under x86_64 emulation.
|
||||
# set(host_arch_path "msvc2019_arm64")
|
||||
set(host_arch_path "msvc2019_64")
|
||||
endif()
|
||||
set(host_arch "win64_${host_arch_path}")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported bundled Qt toolchain. Enable USE_SYSTEM_QT and provide your own.")
|
||||
endif()
|
||||
endif()
|
||||
elseif (APPLE)
|
||||
set(host "mac")
|
||||
set(type "desktop")
|
||||
set(arch "clang_64")
|
||||
set(arch_path "macos")
|
||||
|
||||
if (IOS AND NOT tool)
|
||||
set(host_type "${type}")
|
||||
set(host_arch "${arch}")
|
||||
set(host_arch_path "${arch_path}")
|
||||
|
||||
set(type "ios")
|
||||
set(arch "ios")
|
||||
set(arch_path "ios")
|
||||
endif()
|
||||
else()
|
||||
set(host "linux")
|
||||
set(type "desktop")
|
||||
set(arch "gcc_64")
|
||||
set(arch_path "linux")
|
||||
endif()
|
||||
|
||||
set(${host_out} "${host}" PARENT_SCOPE)
|
||||
set(${type_out} "${type}" PARENT_SCOPE)
|
||||
set(${arch_out} "${arch}" PARENT_SCOPE)
|
||||
set(${arch_path_out} "${arch_path}" PARENT_SCOPE)
|
||||
if (DEFINED host_type)
|
||||
set(${host_type_out} "${host_type}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${host_type_out} "${type}" PARENT_SCOPE)
|
||||
endif()
|
||||
if (DEFINED host_arch)
|
||||
set(${host_arch_out} "${host_arch}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${host_arch_out} "${arch}" PARENT_SCOPE)
|
||||
endif()
|
||||
if (DEFINED host_arch_path)
|
||||
set(${host_arch_path_out} "${host_arch_path}" PARENT_SCOPE)
|
||||
else()
|
||||
set(${host_arch_path_out} "${arch_path}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Download Qt binaries for a specifc configuration.
|
||||
function(download_qt_configuration prefix_out target host type arch arch_path base_path)
|
||||
if (target MATCHES "tools_.*")
|
||||
set(tool ON)
|
||||
else()
|
||||
set(tool OFF)
|
||||
endif()
|
||||
|
||||
set(install_args -c "${CURRENT_MODULE_DIR}/aqt_config.ini")
|
||||
if (tool)
|
||||
set(prefix "${base_path}/Tools")
|
||||
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
|
||||
else()
|
||||
set(prefix "${base_path}/${target}/${arch_path}")
|
||||
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch}
|
||||
-m qtmultimedia --archives qttranslations qttools qtsvg qtbase)
|
||||
endif()
|
||||
|
||||
if (NOT EXISTS "${prefix}")
|
||||
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
|
||||
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.1.9")
|
||||
if (WIN32)
|
||||
set(aqt_path "${base_path}/aqt.exe")
|
||||
if (NOT EXISTS "${aqt_path}")
|
||||
file(DOWNLOAD
|
||||
${AQT_PREBUILD_BASE_URL}/aqt.exe
|
||||
${aqt_path} SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND ${aqt_path} ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
elseif (APPLE)
|
||||
set(aqt_path "${base_path}/aqt-macos")
|
||||
if (NOT EXISTS "${aqt_path}")
|
||||
file(DOWNLOAD
|
||||
${AQT_PREBUILD_BASE_URL}/aqt-macos
|
||||
${aqt_path} SHOW_PROGRESS)
|
||||
endif()
|
||||
execute_process(COMMAND chmod +x ${aqt_path})
|
||||
execute_process(COMMAND ${aqt_path} ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
else()
|
||||
# aqt does not offer binary releases for other platforms, so download and run from pip.
|
||||
set(aqt_install_path "${base_path}/aqt")
|
||||
file(MAKE_DIRECTORY "${aqt_install_path}")
|
||||
|
||||
execute_process(COMMAND python3 -m pip install --target=${aqt_install_path} aqtinstall
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${aqt_install_path} python3 -m aqt ${install_args}
|
||||
WORKING_DIRECTORY ${base_path})
|
||||
endif()
|
||||
|
||||
message(STATUS "Downloaded Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path} to ${prefix}")
|
||||
endif()
|
||||
|
||||
set(${prefix_out} "${prefix}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# This function downloads Qt using aqt.
|
||||
# The path of the downloaded content will be added to the CMAKE_PREFIX_PATH.
|
||||
# QT_TARGET_PATH is set to the Qt for the compile target platform.
|
||||
# QT_HOST_PATH is set to a host-compatible Qt, for running tools.
|
||||
# Params:
|
||||
# target: Qt dependency to install. Specify a version number to download Qt, or "tools_(name)" for a specific build tool.
|
||||
function(download_qt target)
|
||||
determine_qt_parameters("${target}" host type arch arch_path host_type host_arch host_arch_path)
|
||||
|
||||
get_external_prefix(qt base_path)
|
||||
file(MAKE_DIRECTORY "${base_path}")
|
||||
|
||||
download_qt_configuration(prefix "${target}" "${host}" "${type}" "${arch}" "${arch_path}" "${base_path}")
|
||||
if (DEFINED host_arch_path AND NOT "${host_arch_path}" STREQUAL "${arch_path}")
|
||||
download_qt_configuration(host_prefix "${target}" "${host}" "${host_type}" "${host_arch}" "${host_arch_path}" "${base_path}")
|
||||
else()
|
||||
set(host_prefix "${prefix}")
|
||||
endif()
|
||||
|
||||
set(QT_TARGET_PATH "${prefix}" CACHE STRING "")
|
||||
set(QT_HOST_PATH "${host_prefix}" CACHE STRING "")
|
||||
|
||||
# Add the target Qt prefix path so CMake can locate it.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${prefix}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(download_moltenvk)
|
||||
if (IOS)
|
||||
set(MOLTENVK_PLATFORM "iOS")
|
||||
else()
|
||||
set(MOLTENVK_PLATFORM "macOS")
|
||||
endif()
|
||||
|
||||
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
|
||||
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
|
||||
if (NOT EXISTS ${MOLTENVK_DIR})
|
||||
if (NOT EXISTS ${MOLTENVK_TAR})
|
||||
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.7-rc2/MoltenVK-all.tar
|
||||
${MOLTENVK_TAR} SHOW_PROGRESS)
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
|
||||
endif()
|
||||
|
||||
# Add the MoltenVK library path to the prefix so find_library can locate it.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${MOLTENVK_PLATFORM}")
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(get_external_prefix lib_name prefix_var)
|
||||
set(${prefix_var} "${CMAKE_BINARY_DIR}/externals/${lib_name}" PARENT_SCOPE)
|
||||
endfunction()
|
65
CMakeModules/GenerateBuildInfo.cmake
Normal file
65
CMakeModules/GenerateBuildInfo.cmake
Normal file
@ -0,0 +1,65 @@
|
||||
# Gets a UTC timstamp and sets the provided variable to it
|
||||
function(get_timestamp _var)
|
||||
string(TIMESTAMP timestamp UTC)
|
||||
set(${_var} "${timestamp}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
get_timestamp(BUILD_DATE)
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/externals/cmake-modules")
|
||||
|
||||
if (EXISTS "${SRC_DIR}/.git/objects")
|
||||
# Find the package here with the known path so that the GetGit commands can find it as well
|
||||
find_package(Git QUIET PATHS "${GIT_EXECUTABLE}")
|
||||
|
||||
# only use Git to check revision info when source is obtained via Git
|
||||
include(GetGitRevisionDescription)
|
||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
elseif (EXISTS "${SRC_DIR}/GIT-COMMIT" AND EXISTS "${SRC_DIR}/GIT-TAG")
|
||||
# unified source archive
|
||||
file(READ "${SRC_DIR}/GIT-COMMIT" GIT_REV_RAW LIMIT 64)
|
||||
string(STRIP "${GIT_REV_RAW}" GIT_REV)
|
||||
string(SUBSTRING "${GIT_REV_RAW}" 0 9 GIT_DESC)
|
||||
set(GIT_BRANCH "HEAD")
|
||||
else()
|
||||
# self-packed archive?
|
||||
set(GIT_REV "UNKNOWN")
|
||||
set(GIT_DESC "UNKNOWN")
|
||||
set(GIT_BRANCH "UNKNOWN")
|
||||
endif()
|
||||
string(SUBSTRING "${GIT_REV}" 0 7 GIT_SHORT_REV)
|
||||
|
||||
# Generate cpp with Git revision from template
|
||||
# Also if this is a CI build, add the build name (ie: Nightly, Canary) to the scm_rev file as well
|
||||
set(REPO_NAME "")
|
||||
set(BUILD_VERSION "0")
|
||||
set(BUILD_FULLNAME "${GIT_SHORT_REV}")
|
||||
if (DEFINED ENV{CI})
|
||||
if (DEFINED ENV{GITHUB_ACTIONS})
|
||||
set(BUILD_REPOSITORY $ENV{GITHUB_REPOSITORY})
|
||||
set(BUILD_TAG $ENV{GITHUB_REF_NAME})
|
||||
endif()
|
||||
|
||||
# regex capture the string nightly or canary into CMAKE_MATCH_1
|
||||
string(REGEX MATCH "citra-emu/citra-?(.*)" OUTVAR ${BUILD_REPOSITORY})
|
||||
if ("${CMAKE_MATCH_COUNT}" GREATER 0)
|
||||
# capitalize the first letter of each word in the repo name.
|
||||
string(REPLACE "-" ";" REPO_NAME_LIST ${CMAKE_MATCH_1})
|
||||
foreach(WORD ${REPO_NAME_LIST})
|
||||
string(SUBSTRING ${WORD} 0 1 FIRST_LETTER)
|
||||
string(SUBSTRING ${WORD} 1 -1 REMAINDER)
|
||||
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
|
||||
set(REPO_NAME "${REPO_NAME}${FIRST_LETTER}${REMAINDER}")
|
||||
endforeach()
|
||||
string(REGEX MATCH "${CMAKE_MATCH_1}-([0-9]+)" OUTVAR ${BUILD_TAG})
|
||||
if (${CMAKE_MATCH_COUNT} GREATER 0)
|
||||
set(BUILD_VERSION ${CMAKE_MATCH_1})
|
||||
endif()
|
||||
if (BUILD_VERSION)
|
||||
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION}")
|
||||
else()
|
||||
set(BUILD_FULLNAME "")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
44
CMakeModules/GenerateSCMRev.cmake
Normal file
44
CMakeModules/GenerateSCMRev.cmake
Normal file
@ -0,0 +1,44 @@
|
||||
list(APPEND CMAKE_MODULE_PATH "${SRC_DIR}/CMakeModules")
|
||||
include(GenerateBuildInfo)
|
||||
|
||||
# The variable SRC_DIR must be passed into the script (since it uses the current build directory for all values of CMAKE_*_DIR)
|
||||
set(VIDEO_CORE "${SRC_DIR}/src/video_core")
|
||||
set(HASH_FILES
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_disk_cache.h"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.cpp"
|
||||
"${VIDEO_CORE}/renderer_opengl/gl_shader_util.h"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.cpp"
|
||||
"${VIDEO_CORE}/renderer_vulkan/vk_shader_util.h"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_fs_shader_gen.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_fs_shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_shader_decompiler.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_shader_decompiler.h"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_shader_gen.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/glsl_shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/generator/pica_fs_config.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/pica_fs_config.h"
|
||||
"${VIDEO_CORE}/shader/generator/shader_gen.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/generator/shader_uniforms.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/shader_uniforms.h"
|
||||
"${VIDEO_CORE}/shader/generator/spv_fs_shader_gen.cpp"
|
||||
"${VIDEO_CORE}/shader/generator/spv_fs_shader_gen.h"
|
||||
"${VIDEO_CORE}/shader/shader.cpp"
|
||||
"${VIDEO_CORE}/shader/shader.h"
|
||||
"${VIDEO_CORE}/pica/regs_framebuffer.h"
|
||||
"${VIDEO_CORE}/pica/regs_lighting.h"
|
||||
"${VIDEO_CORE}/pica/regs_pipeline.h"
|
||||
"${VIDEO_CORE}/pica/regs_rasterizer.h"
|
||||
"${VIDEO_CORE}/pica/regs_shader.h"
|
||||
"${VIDEO_CORE}/pica/regs_texturing.h"
|
||||
"${VIDEO_CORE}/pica/regs_internal.cpp"
|
||||
"${VIDEO_CORE}/pica/regs_internal.h"
|
||||
)
|
||||
set(COMBINED "")
|
||||
foreach (F IN LISTS HASH_FILES)
|
||||
file(READ ${F} TMP)
|
||||
set(COMBINED "${COMBINED}${TMP}")
|
||||
endforeach()
|
||||
string(MD5 SHADER_CACHE_VERSION "${COMBINED}")
|
||||
configure_file("${SRC_DIR}/src/common/scm_rev.cpp.in" "scm_rev.cpp" @ONLY)
|
29
CMakeModules/aqt_config.ini
Normal file
29
CMakeModules/aqt_config.ini
Normal file
@ -0,0 +1,29 @@
|
||||
[aqt]
|
||||
concurrency: 2
|
||||
|
||||
[mirrors]
|
||||
trusted_mirrors:
|
||||
https://download.qt.io
|
||||
blacklist:
|
||||
https://qt.mirror.constant.com
|
||||
https://mirrors.ocf.berkeley.edu
|
||||
https://mirrors.ustc.edu.cn
|
||||
https://mirrors.tuna.tsinghua.edu.cn
|
||||
https://mirrors.geekpie.club
|
||||
https://mirrors-wan.geekpie.club
|
||||
https://mirrors.sjtug.sjtu.edu.cn
|
||||
fallbacks:
|
||||
https://qtproject.mirror.liquidtelecom.com/
|
||||
https://mirrors.aliyun.com/qt/
|
||||
https://ftp.jaist.ac.jp/pub/qtproject/
|
||||
https://ftp.yz.yamagata-u.ac.jp/pub/qtproject/
|
||||
https://qt-mirror.dannhauer.de/
|
||||
https://ftp.fau.de/qtproject/
|
||||
https://mirror.netcologne.de/qtproject/
|
||||
https://mirrors.dotsrc.org/qtproject/
|
||||
https://www.nic.funet.fi/pub/mirrors/download.qt-project.org/
|
||||
https://master.qt.io/
|
||||
https://mirrors.ukfast.co.uk/sites/qt.io/
|
||||
https://ftp2.nluug.nl/languages/qt/
|
||||
https://ftp1.nluug.nl/languages/qt/
|
||||
|
Reference in New Issue
Block a user