diff --git a/.github/workflows/ci-freebsd.yml b/.github/workflows/ci-freebsd.yml index f0bff9ed165..65af4adb940 100644 --- a/.github/workflows/ci-freebsd.yml +++ b/.github/workflows/ci-freebsd.yml @@ -107,7 +107,6 @@ jobs: devel/evdev-proto \ devel/git \ devel/libevdev \ - devel/libnotify \ devel/llvm${{ env.FREEBSD_CLANG_VERSION }} \ devel/ninja \ devel/pkgconf \ diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 7ec3b8c5c8a..4c2f04ee664 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -86,7 +86,9 @@ jobs: icu4c@78 \ miniupnpc \ openssl@3 \ - opus + opus \ + qtbase \ + qtsvg - name: Setup Python uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index 47271c0b020..dd6b118643e 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -108,6 +108,8 @@ jobs: "mingw-w64-${TOOLCHAIN}-openssl" "mingw-w64-${TOOLCHAIN}-opus" "mingw-w64-${TOOLCHAIN}-toolchain" + "mingw-w64-${TOOLCHAIN}-qt6-base" + "mingw-w64-${TOOLCHAIN}-qt6-svg" ) if [[ "${MATRIX_MSYSTEM}" == "ucrt64" ]]; then @@ -270,14 +272,23 @@ jobs: echo "${linkage}" echo "::endgroup::" - unexpected_for_binary="$(awk ' + binary_dir="$(dirname "${binary}")" + unexpected_for_binary="$(awk -v binary_dir="${binary_dir}" ' BEGIN { IGNORECASE = 1 } $1 == "zlib1.dll" { next } $1 ~ /^minhook-detours\..*\.dll$/ { next } $1 ~ /^api-ms-win-/ { next } $1 ~ /^ext-ms-win-/ { next } - $0 ~ /=>[[:space:]]+not found/ { print } - $0 ~ /=>[[:space:]]+\/(clangarm64|clang64|mingw32|mingw64|ucrt64)\/bin\// { print } + $0 ~ /=>[[:space:]]+not found/ { print; next } + $0 ~ /=>[[:space:]]+\/(clangarm64|clang64|mingw32|mingw64|ucrt64)\/bin\// { + deployed_dll = binary_dir "/" $1 + if ((getline _ < deployed_dll) >= 0) { + close(deployed_dll) + next + } + close(deployed_dll) + print + } ' <<< "${linkage}")" if [[ -n "${unexpected_for_binary}" ]]; then diff --git a/cmake/packaging/linux.cmake b/cmake/packaging/linux.cmake index 8f493b0757c..b3f675d295a 100644 --- a/cmake/packaging/linux.cmake +++ b/cmake/packaging/linux.cmake @@ -154,17 +154,6 @@ if(${SUNSHINE_TRAY} STREQUAL 1) # Icons used by the Qt tray backend are no longer installed to the hicolor icon theme, # because Qt6 will not allow icons not part of the theme... so we will use icons from our web directory instead - set(CPACK_DEBIAN_PACKAGE_DEPENDS "\ - ${CPACK_DEBIAN_PACKAGE_DEPENDS}, \ - libnotify4" - ) - set(CPACK_RPM_PACKAGE_REQUIRES "\ - ${CPACK_RPM_PACKAGE_REQUIRES}, \ - libnotify >= 0.8.0" - ) - list(APPEND CPACK_FREEBSD_PACKAGE_DEPS - devel/libnotify - ) if(TRAY_QT_VERSION EQUAL 6) set(CPACK_DEBIAN_PACKAGE_DEPENDS "\ ${CPACK_DEBIAN_PACKAGE_DEPENDS}, \ diff --git a/cmake/packaging/macos.cmake b/cmake/packaging/macos.cmake index 623541043d1..dc772d343e2 100644 --- a/cmake/packaging/macos.cmake +++ b/cmake/packaging/macos.cmake @@ -37,14 +37,34 @@ else() PATTERN ".DS_Store" EXCLUDE PATTERN "._*" EXCLUDE) + set(SUNSHINE_BUNDLE_FIXUP_DIRS "") + set(SUNSHINE_MACDEPLOYQT_CODE "") + if(SUNSHINE_ENABLE_TRAY) + include("${CMAKE_MODULE_PATH}/packaging/qt.cmake") + sunshine_require_qt_tool(macdeployqt SUNSHINE_MACDEPLOYQT_EXECUTABLE) + sunshine_collect_qt_library_dirs(SUNSHINE_BUNDLE_FIXUP_DIRS) + set(SUNSHINE_MACDEPLOYQT_CODE " + message(STATUS \"Running macdeployqt for: \${_app}\") + execute_process( + COMMAND \"${SUNSHINE_MACDEPLOYQT_EXECUTABLE}\" \"\${_app}\" -no-strip + RESULT_VARIABLE _macdeployqt_result + ) + if(NOT _macdeployqt_result EQUAL 0) + message(FATAL_ERROR \"macdeployqt failed: \${_macdeployqt_result}\") + endif() +") + endif() + # Pull in non-system dylibs for a self-contained .app install(CODE " set(_app \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_PROJECT_NAME}.app\") + set(_bundle_fixup_dirs \"${SUNSHINE_BUNDLE_FIXUP_DIRS}\") +${SUNSHINE_MACDEPLOYQT_CODE} message(STATUS \"Running fixup_bundle for: \${_app}\") include(BundleUtilities) set(BU_CHMOD_BUNDLE_ITEMS TRUE) - fixup_bundle(\"\${_app}\" \"\" \"\") + fixup_bundle(\"\${_app}\" \"\" \"\${_bundle_fixup_dirs}\") # Remove Finder/resource-fork metadata that breaks codesign. execute_process(COMMAND /usr/bin/xattr -rc \"\${_app}\") diff --git a/cmake/packaging/qt.cmake b/cmake/packaging/qt.cmake new file mode 100644 index 00000000000..b0485769bf4 --- /dev/null +++ b/cmake/packaging/qt.cmake @@ -0,0 +1,89 @@ +# Qt packaging helpers + +function(sunshine_find_qt_tool tool_name out_var) + foreach(qt_major IN ITEMS 6 5) + if(TARGET Qt${qt_major}::${tool_name}) + get_target_property(_qt_tool Qt${qt_major}::${tool_name} IMPORTED_LOCATION) + if(_qt_tool) + set(${out_var} "${_qt_tool}" PARENT_SCOPE) + return() + endif() + endif() + endforeach() + + set(_qt_tool_names "${tool_name}" "${tool_name}6" "${tool_name}5") + string(TOUPPER "${tool_name}" _qt_tool_name) + set(_qt_tool_var "SUNSHINE_${_qt_tool_name}_EXECUTABLE") + find_program(${_qt_tool_var} NAMES ${_qt_tool_names}) + set(${out_var} "${${_qt_tool_var}}" PARENT_SCOPE) +endfunction() + +function(sunshine_require_qt_tool tool_name out_var) + sunshine_find_qt_tool("${tool_name}" _qt_tool) + if(NOT _qt_tool) + message(FATAL_ERROR + "${tool_name} is required to package Sunshine with the Qt tray backend") + endif() + + set(${out_var} "${_qt_tool}" PARENT_SCOPE) +endfunction() + +function(sunshine_deploy_qt_runtime target_name deploy_tool) + if(NOT TARGET "${target_name}") + return() + endif() + + add_custom_command(TARGET "${target_name}" POST_BUILD + COMMAND "${deploy_tool}" + ${ARGN} + --dir "$" + "$" + COMMAND "${CMAKE_COMMAND}" + "-DSUNSHINE_RUNTIME_TARGET=$" + "-DSUNSHINE_RUNTIME_OUTPUT_DIR=$" + -P "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/windows_runtime_deps.cmake" + COMMENT "Deploying Qt runtime for ${target_name}" + VERBATIM) +endfunction() + +function(sunshine_collect_qt_library_dirs out_var) + set(_qt_dirs "") + foreach(qt_major IN ITEMS 6 5) + foreach(qt_component IN ITEMS Core Gui Widgets Svg DBus) + if(TARGET Qt${qt_major}::${qt_component}) + set(_qt_location "") + foreach(_qt_property IN ITEMS + IMPORTED_LOCATION_RELEASE + IMPORTED_LOCATION_RELWITHDEBINFO + IMPORTED_LOCATION) + get_target_property(_qt_property_location Qt${qt_major}::${qt_component} ${_qt_property}) + if(_qt_property_location) + set(_qt_location "${_qt_property_location}") + break() + endif() + endforeach() + + if(_qt_location) + get_filename_component(_qt_dir "${_qt_location}" DIRECTORY) + foreach(_qt_depth RANGE 1 8) + if(NOT _qt_dir) + break() + endif() + + list(APPEND _qt_dirs "${_qt_dir}") + get_filename_component(_qt_parent "${_qt_dir}" DIRECTORY) + if(_qt_parent STREQUAL _qt_dir) + break() + endif() + set(_qt_dir "${_qt_parent}") + endforeach() + endif() + endif() + endforeach() + endforeach() + + if(_qt_dirs) + list(REMOVE_DUPLICATES _qt_dirs) + endif() + set(${out_var} "${_qt_dirs}" PARENT_SCOPE) +endfunction() diff --git a/cmake/packaging/windows.cmake b/cmake/packaging/windows.cmake index 69830da6b9a..4ec461cce0e 100644 --- a/cmake/packaging/windows.cmake +++ b/cmake/packaging/windows.cmake @@ -9,6 +9,48 @@ if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64" AND DEFINED _MINHOOK_DLL) install(FILES "${_MINHOOK_DLL}" DESTINATION "." COMPONENT application) endif() +if(SUNSHINE_ENABLE_TRAY) + include("${CMAKE_MODULE_PATH}/packaging/qt.cmake") + sunshine_require_qt_tool(windeployqt SUNSHINE_WINDEPLOYQT_EXECUTABLE) + + set(SUNSHINE_WINDEPLOYQT_OPTIONS + --no-opengl-sw + --no-quick-import + --no-system-d3d-compiler + --no-translations) + + sunshine_deploy_qt_runtime( + sunshine + "${SUNSHINE_WINDEPLOYQT_EXECUTABLE}" + ${SUNSHINE_WINDEPLOYQT_OPTIONS}) + + install(CODE " + set(_qt_deploy_dir \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}\") + set(_qt_deploy_options ${SUNSHINE_WINDEPLOYQT_OPTIONS}) + execute_process( + COMMAND \"${SUNSHINE_WINDEPLOYQT_EXECUTABLE}\" + \${_qt_deploy_options} + --dir \"\${_qt_deploy_dir}\" + \"\${_qt_deploy_dir}/sunshine.exe\" + RESULT_VARIABLE _qt_deploy_result + ) + if(NOT _qt_deploy_result EQUAL 0) + message(FATAL_ERROR \"windeployqt failed: \${_qt_deploy_result}\") + endif() + + execute_process( + COMMAND \"${CMAKE_COMMAND}\" + \"-DSUNSHINE_RUNTIME_TARGET=\${_qt_deploy_dir}/sunshine.exe\" + \"-DSUNSHINE_RUNTIME_OUTPUT_DIR=\${_qt_deploy_dir}\" + -P \"${CMAKE_MODULE_PATH}/packaging/windows_runtime_deps.cmake\" + RESULT_VARIABLE _runtime_deploy_result + ) + if(NOT _runtime_deploy_result EQUAL 0) + message(FATAL_ERROR \"Runtime dependency deployment failed: \${_runtime_deploy_result}\") + endif() + " COMPONENT application) +endif() + # ViGEmBus installer set(SUNSHINE_THIRD_PARTY_DIR "third-party") set(VIGEMBUS_INSTALLER "${CMAKE_BINARY_DIR}/${SUNSHINE_THIRD_PARTY_DIR}/vigembus_installer.exe") diff --git a/cmake/packaging/windows_runtime_deps.cmake b/cmake/packaging/windows_runtime_deps.cmake new file mode 100644 index 00000000000..6f8f2c09f90 --- /dev/null +++ b/cmake/packaging/windows_runtime_deps.cmake @@ -0,0 +1,98 @@ +# Deploy MSYS2 runtime DLLs that are reported by ldd for a Windows binary. + +if(NOT DEFINED SUNSHINE_RUNTIME_TARGET) + message(FATAL_ERROR "SUNSHINE_RUNTIME_TARGET is required") +endif() + +if(NOT DEFINED SUNSHINE_RUNTIME_OUTPUT_DIR) + message(FATAL_ERROR "SUNSHINE_RUNTIME_OUTPUT_DIR is required") +endif() + +string(REGEX REPLACE "^\"|\"$" "" SUNSHINE_RUNTIME_TARGET "${SUNSHINE_RUNTIME_TARGET}") +string(REGEX REPLACE "^\"|\"$" "" SUNSHINE_RUNTIME_OUTPUT_DIR "${SUNSHINE_RUNTIME_OUTPUT_DIR}") + +find_program(SUNSHINE_LDD_EXECUTABLE ldd) +if(NOT SUNSHINE_LDD_EXECUTABLE) + message(FATAL_ERROR "ldd is required to deploy MSYS2 runtime dependencies") +endif() + +find_program(SUNSHINE_CYGPATH_EXECUTABLE cygpath) +if(NOT SUNSHINE_CYGPATH_EXECUTABLE) + message(FATAL_ERROR "cygpath is required to deploy MSYS2 runtime dependencies") +endif() + +function(sunshine_msys_path_to_cmake msys_path out_var) + execute_process( + COMMAND "${SUNSHINE_CYGPATH_EXECUTABLE}" -m "${msys_path}" + OUTPUT_VARIABLE _cmake_path + ERROR_VARIABLE _cygpath_error + RESULT_VARIABLE _cygpath_result + OUTPUT_STRIP_TRAILING_WHITESPACE) + if(NOT _cygpath_result EQUAL 0) + message(FATAL_ERROR "cygpath failed for ${msys_path}: ${_cygpath_error}") + endif() + + set(${out_var} "${_cmake_path}" PARENT_SCOPE) +endfunction() + +function(sunshine_copy_msys_dependency msys_path output_dir out_path) + sunshine_msys_path_to_cmake("${msys_path}" _source_path) + get_filename_component(_dll_name "${_source_path}" NAME) + set(_deployed_path "${output_dir}/${_dll_name}") + + if(NOT EXISTS "${_deployed_path}") + execute_process( + COMMAND "${CMAKE_COMMAND}" -E copy_if_different + "${_source_path}" + "${_deployed_path}" + ERROR_VARIABLE _copy_error + RESULT_VARIABLE _copy_result) + if(NOT _copy_result EQUAL 0) + message(FATAL_ERROR "Failed to copy ${_source_path}: ${_copy_error}") + endif() + endif() + + set(${out_path} "${_deployed_path}" PARENT_SCOPE) +endfunction() + +file(GLOB_RECURSE _deployed_dlls + LIST_DIRECTORIES false + "${SUNSHINE_RUNTIME_OUTPUT_DIR}/*.dll") + +set(_pending "${SUNSHINE_RUNTIME_TARGET}" ${_deployed_dlls}) +set(_processed "") + +while(_pending) + list(POP_FRONT _pending _runtime_binary) + list(FIND _processed "${_runtime_binary}" _processed_index) + if(NOT _processed_index EQUAL -1) + continue() + endif() + + list(APPEND _processed "${_runtime_binary}") + + execute_process( + COMMAND "${SUNSHINE_LDD_EXECUTABLE}" "${_runtime_binary}" + OUTPUT_VARIABLE _ldd_output + ERROR_VARIABLE _ldd_error + RESULT_VARIABLE _ldd_result) + if(NOT _ldd_result EQUAL 0) + message(FATAL_ERROR "ldd failed for ${_runtime_binary}: ${_ldd_error}") + endif() + + string(REGEX MATCHALL "[^\r\n]+" _ldd_lines "${_ldd_output}") + foreach(_ldd_line IN LISTS _ldd_lines) + if(_ldd_line MATCHES "=>[ \t]+not[ \t]+found") + message(FATAL_ERROR "Runtime dependency not found: ${_ldd_line}") + endif() + + if(_ldd_line MATCHES "=>[ \t]+(/(clangarm64|clang64|mingw32|mingw64|ucrt64)/bin/[^ \t\r\n]+\\.dll)") + sunshine_copy_msys_dependency("${CMAKE_MATCH_1}" "${SUNSHINE_RUNTIME_OUTPUT_DIR}" _deployed_dll) + list(FIND _processed "${_deployed_dll}" _deployed_processed_index) + list(FIND _pending "${_deployed_dll}" _deployed_pending_index) + if(_deployed_processed_index EQUAL -1 AND _deployed_pending_index EQUAL -1) + list(APPEND _pending "${_deployed_dll}") + endif() + endif() + endforeach() +endwhile() \ No newline at end of file diff --git a/docker/clion-toolchain.dockerfile b/docker/clion-toolchain.dockerfile index e08a2db5025..c2a468736a5 100644 --- a/docker/clion-toolchain.dockerfile +++ b/docker/clion-toolchain.dockerfile @@ -39,7 +39,6 @@ apt-get install -y --no-install-recommends \ libevdev-dev \ libgbm-dev \ libminiupnpc-dev \ - libnotify-dev \ libnuma-dev \ libopus-dev \ libpulse-dev \ diff --git a/docs/building.md b/docs/building.md index 8b80ce2efad..9dc2a7804b0 100644 --- a/docs/building.md +++ b/docs/building.md @@ -27,7 +27,6 @@ pkg install -y \ devel/evdev-proto \ devel/git \ devel/libevdev \ - devel/libnotify \ devel/ninja \ devel/pkgconf \ devel/qt6-base \ @@ -94,6 +93,8 @@ dependencies=( "openssl@3" "opus" "pkg-config" + "qtbase" + "qtsvg" ) brew install "${dependencies[@]}" ``` @@ -122,6 +123,8 @@ dependencies=( "ninja" "npm9" "pkgconfig" + "qt6-qtbase" + "qt6-qtsvg" ) sudo port install "${dependencies[@]}" ``` @@ -166,6 +169,8 @@ dependencies=( "mingw-w64-${TOOLCHAIN}-openssl" "mingw-w64-${TOOLCHAIN}-opus" "mingw-w64-${TOOLCHAIN}-toolchain" + "mingw-w64-${TOOLCHAIN}-qt6-base" + "mingw-w64-${TOOLCHAIN}-qt6-svg" ) if [[ "${MSYSTEM}" == "UCRT64" ]]; then dependencies+=( diff --git a/packaging/linux/Arch/PKGBUILD b/packaging/linux/Arch/PKGBUILD index 00a934cd2ca..7e2c06682cd 100644 --- a/packaging/linux/Arch/PKGBUILD +++ b/packaging/linux/Arch/PKGBUILD @@ -35,7 +35,6 @@ depends=( 'libdrm' 'libevdev' 'libmfx' - 'libnotify' 'libpipewire' 'libpulse' 'libva' diff --git a/packaging/linux/copr/Sunshine.spec b/packaging/linux/copr/Sunshine.spec index f79c35d2b4c..85ee83c9f03 100644 --- a/packaging/linux/copr/Sunshine.spec +++ b/packaging/linux/copr/Sunshine.spec @@ -31,7 +31,6 @@ BuildRequires: libcap-devel BuildRequires: libcurl-devel BuildRequires: libdrm-devel BuildRequires: libevdev-devel -BuildRequires: libnotify-devel >= 0.8.0 BuildRequires: libva-devel BuildRequires: libX11-devel BuildRequires: libxcb-devel @@ -153,7 +152,6 @@ BuildRequires: libqt6-qtsvg-devel %global cuda_dir %{_builddir}/cuda # Common runtime requirements -Requires: libnotify >= 0.8.0 Requires: miniupnpc >= 2.2.4 Requires: which >= 2.21 diff --git a/packaging/sunshine.rb b/packaging/sunshine.rb index 3a88114fd34..cc35fb18301 100644 --- a/packaging/sunshine.rb +++ b/packaging/sunshine.rb @@ -55,6 +55,8 @@ class Sunshine < Formula depends_on "miniupnpc" depends_on "openssl@3" depends_on "opus" + depends_on "qtbase" + depends_on "qtsvg" on_macos do depends_on "llvm" => [:build, :test] @@ -74,7 +76,6 @@ class Sunshine < Formula depends_on "libcap" depends_on "libdrm" depends_on "libice" - depends_on "libnotify" depends_on "libsm" depends_on "libva" depends_on "libx11" @@ -91,8 +92,6 @@ class Sunshine < Formula depends_on "pango" depends_on "pipewire" depends_on "pulseaudio" - depends_on "qtbase" - depends_on "qtsvg" depends_on "shaderc" depends_on "systemd" depends_on "vulkan-loader" diff --git a/scripts/linux_build.sh b/scripts/linux_build.sh index 2c1011436b0..8afc1d343f3 100755 --- a/scripts/linux_build.sh +++ b/scripts/linux_build.sh @@ -283,7 +283,6 @@ function add_arch_deps() { 'libdrm' 'libevdev' 'libmfx' - 'libnotify' 'libpulse' 'libva' 'libx11' @@ -344,7 +343,6 @@ function add_debian_based_deps() { "libevdev-dev" "libgbm-dev" "libminiupnpc-dev" - "libnotify-dev" "libnuma-dev" "libopus-dev" "libpipewire-0.3-dev" @@ -450,7 +448,6 @@ function add_fedora_deps() { "libcurl-devel" "libdrm-devel" "libevdev-devel" - "libnotify-devel" "libX11-devel" # X11 "libxcb-devel" # X11 "libXcursor-devel" # X11 diff --git a/scripts/macos_build.sh b/scripts/macos_build.sh index 7c24209836d..5a27f2b78d6 100755 --- a/scripts/macos_build.sh +++ b/scripts/macos_build.sh @@ -37,6 +37,8 @@ required_formulas=( "openssl@3" "opus" "llvm" + "qtbase" + "qtsvg" ) function _usage() { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 984481f6010..b69d6f9d16d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -190,4 +190,18 @@ if (WIN32) VERBATIM ) endif() + + if(SUNSHINE_ENABLE_TRAY) + include("${CMAKE_MODULE_PATH}/packaging/qt.cmake") + sunshine_require_qt_tool(windeployqt SUNSHINE_WINDEPLOYQT_EXECUTABLE) + set(SUNSHINE_WINDEPLOYQT_OPTIONS + --no-opengl-sw + --no-quick-import + --no-system-d3d-compiler + --no-translations) + sunshine_deploy_qt_runtime( + ${PROJECT_NAME} + "${SUNSHINE_WINDEPLOYQT_EXECUTABLE}" + ${SUNSHINE_WINDEPLOYQT_OPTIONS}) + endif() endif () diff --git a/third-party/tray b/third-party/tray index df9af119085..c7bb9e515bb 160000 --- a/third-party/tray +++ b/third-party/tray @@ -1 +1 @@ -Subproject commit df9af119085e2cd3f1a9e88e4cc865963879d468 +Subproject commit c7bb9e515bb2de3bb56448b3b070f3e72138868f