From e9e1da4b5c68368f82b4019926ac6fed52fe6704 Mon Sep 17 00:00:00 2001 From: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Thu, 1 May 2025 14:41:53 +0200 Subject: [PATCH 01/27] Added Windows arm64 platform --- .github/workflows/qt5_6.yml | 66 ++++++++------ CMakeLists.txt | 18 +++- CMakePresets.json | 31 +++++++ cmake/FindDebBuilder.cmake | 23 ----- cmake/FindRpmBuilder.cmake | 23 ----- cmake/FindTurboJPEG.cmake | 18 ++-- cmake/FindWindowsSDK.cmake | 10 +- cmake/GitVersion.cmake | 2 + cmake/HelperFunctions.cmake | 2 + cmake/HelperMacros.cmake | 2 + cmake/Packaging.cmake | 127 ++++++++++++++------------ cmake/windows/BundleWindows.cmake.in | 21 ++--- include/effectengine/EffectModule.h | 10 -- include/python/PythonInit.h | 10 -- include/python/PythonProgram.h | 10 -- include/python/PythonUtils.h | 10 -- libsrc/effectengine/EffectEngine.cpp | 10 -- libsrc/grabber/video/CMakeLists.txt | 32 ++++--- libsrc/utils/SysInfo.cpp | 11 --- src/hyperiond/CMakeLists.txt | 132 ++++++++++----------------- 20 files changed, 248 insertions(+), 320 deletions(-) delete mode 100644 cmake/FindDebBuilder.cmake delete mode 100644 cmake/FindRpmBuilder.cmake diff --git a/.github/workflows/qt5_6.yml b/.github/workflows/qt5_6.yml index 79390fd81..82ff5020d 100644 --- a/.github/workflows/qt5_6.yml +++ b/.github/workflows/qt5_6.yml @@ -131,7 +131,7 @@ jobs: - name: 📥 Install dependencies uses: tecolicom/actions-use-homebrew-tools@v1 with: - tools: qt@${{ inputs.qt_version }} vulkan-headers coreutils + tools: qt@${{ inputs.qt_version }} coreutils key: ${{ runner.os }}-${{ matrix.architecture }}-homebrew-packages-${{ inputs.qt_version }} - name: 💾 Download Pre-Build Dependencies @@ -183,10 +183,20 @@ jobs: ###################### windows: - name: 🪟 Windows x64 - runs-on: windows-2022 + name: 🪟 Windows ${{ matrix.architecture }} + runs-on: ${{ matrix.architecture == 'arm64' && 'windows-11-arm' || 'windows-2022' }} env: - LIBJPEG_TURBO_VERSION: 3.0.1 + LIBJPEG_TURBO_VERSION: 3.1.0 + strategy: + fail-fast: false + matrix: + architecture: [ arm64, x64 ] + isQt5: + - ${{ inputs.qt_version == '5' }} + exclude: + - isQt5: true + architecture: arm64 + steps: - name: ⬇ Checkout uses: actions/checkout@v4 @@ -198,55 +208,53 @@ jobs: shell: bash run: tr -d '\n' < .version > temp && mv temp .version && echo -n "+PR${{ inputs.pull_request_number }}" >> .version - - name: 💾 Restore DirectX SDK (if available) + - name: 💾 Restore DirectX SDK (x64) + if: matrix.architecture == 'x64' uses: ethanjli/cached-download-action@v0.1.2 with: url: https://download.microsoft.com/download/A/E/7/AE743F1F-632B-4809-87A9-AA1BB3458E31/DXSDK_Jun10.exe destination: .\installer\dxsdk-jun10.exe cache-key: dxsdk-jun10 - - name: 💾 Restore libjpeg-turbo (if available) - uses: ethanjli/cached-download-action@v0.1.2 - with: - url: https://sourceforge.net/projects/libjpeg-turbo/files/${{ env.LIBJPEG_TURBO_VERSION }}/libjpeg-turbo-${{ env.LIBJPEG_TURBO_VERSION }}-vc64.exe - destination: .\installer\libjpeg-turbo.exe - cache-key: libjpeg-turbo - - - name: 📥 Extract DirectX SDK & libjpeg-turbo + - name: 📥 Extract DirectX SDK (x64) + if: matrix.architecture == 'x64' run: | 7z x -aoa .\installer\dxsdk-jun10.exe DXSDK/Include DXSDK/Lib -oC:\ echo "DXSDK_DIR=C:\DXSDK" | Out-File -FilePath $env:GITHUB_ENV -Append - 7z x -aoa .\installer\libjpeg-turbo.exe bin include lib -oC:\turbojpeg - echo "TURBOJPEG_DIR=C:\turbojpeg" | Out-File -FilePath $env:GITHUB_ENV -Append - - - name: 📥 Install Vulkan SDK - if: ${{ inputs.qt_version == '6' }} - uses: jakoch/install-vulkan-sdk-action@v1 - with: - install_runtime: false - cache: true - stripdown: true - name: 📥 Install Qt - uses: jurplel/install-qt-action@v4 + # If the following PR is merged, you can switch back to jurplel/install-qt-action + # https://github.com/jurplel/install-qt-action/pull/273 + uses: jdpurcell/install-qt-action@v5 with: - version: ${{ inputs.qt_version == '6' && '6.8' || '5.15.*' }} + version: ${{ inputs.qt_version == '6' && '6.8.*' || '5.15.*' }} target: 'desktop' modules: ${{ inputs.qt_version == '6' && 'qtserialport qtwebsockets' || '' }} cache: 'true' cache-key-prefix: 'cache-qt-windows' + - name: 📥 Install Python + uses: actions/setup-python@v5 + with: + python-version: 3.13 + architecture: ${{ matrix.architecture }} + + - name: 📥 Install latest CMake and Ninja + uses: lukka/get-cmake@latest + - name: 🛠️ Setup MSVC uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.architecture }} - name: 💾 Download Pre-Build Dependencies id: dependencies uses: ./.github/actions/download-pre-built-deps with: os: 'windows' - architecture: 'x64' + architecture: ${{ matrix.architecture }} qt_version: ${{ inputs.qt_version }} - build_type: ${{ inputs.event_name == 'pull_request' && 'debug' || 'release' }} + build_type: ${{ inputs.event_name != 'pull_request' && 'relwithdebinfo' || 'release' }} - name: 👷 Build ${{ env.HINT }} shell: cmd @@ -254,7 +262,7 @@ jobs: cmake --preset windows-${{ env.BUILD_TYPE }} ${{ steps.dependencies.outputs.cmakeArgs }} cmake --build --preset windows-${{ env.BUILD_TYPE }} --target package env: - BUILD_TYPE: ${{ inputs.event_name == 'pull_request' && 'debug' || 'release' }} + BUILD_TYPE: ${{ inputs.event_name != 'pull_request' && 'relwithdebinfo' || 'release' }} HINT: ${{ steps.dependencies.outputs.cmakeArgs != '' && '(with pre-built dependencies)' || '(full build)' }} - name: 📦 Upload @@ -264,7 +272,7 @@ jobs: name: ${{ inputs.event_name == 'pull_request' && env.NAME || format('artifact-{0}', env.NAME) }} path: ${{ inputs.event_name == 'pull_request' && 'build/*.exe' || 'build/Hyperion-*' }} env: - NAME: ${{ inputs.qt_version == '6' && 'windows_x64_qt6' || 'windows_x64' }} + NAME: ${{ inputs.qt_version == '6' && format('windows_{0}_qt6', matrix.architecture) || format('windows_{0}', matrix.architecture) }} ##################################### ###### Publish GitHub Releases ###### diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c3a7bf47..cee0134cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -170,7 +170,6 @@ if(${CMAKE_SYSTEM} MATCHES "Linux") set(DEFAULT_DEV_TINKERFORGE ON) set(DEFAULT_CEC ON) elseif (WIN32) - set(DEFAULT_DX ON) set(DEFAULT_DDA ON) set(DEFAULT_MF ON) else() @@ -204,6 +203,10 @@ if("${PLATFORM}" MATCHES "osx") set(DEFAULT_OSX ON) set(DEFAULT_AUDIO OFF) +elseif ("${PLATFORM}" MATCHES "windows") + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386|i686|amd64|x86_64|AMD64") + set(DEFAULT_DX ON) + endif() elseif ("${PLATFORM}" MATCHES "rpi") set(DEFAULT_DISPMANX ON) set(DEFAULT_DEV_WS281XPWM ON) @@ -576,7 +579,7 @@ endif() # Search for Windows SDK if(MSVC) find_package(WindowsSDK REQUIRED) - message(STATUS "WINDOWS SDK: ${WINDOWSSDK_LATEST_DIR} ${WINDOWSSDK_LATEST_NAME}") + message(STATUS "WINDOWS SDK: ${WINDOWSSDK_LATEST_DIR} (${WINDOWSSDK_LATEST_NAME})") message(STATUS "MSVC VERSION: ${MSVC_VERSION}") endif() @@ -605,7 +608,11 @@ if(NOT DEFINED QTDIR) if(MSVC) FIRSTSUBDIR(SUBDIRQT "C:/Qt") if(NOT ${SUBDIRQT} STREQUAL "") - set(QTDIR "${SUBDIRQT}/msvc2019_64") + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64|ARM64|arm64") + set(QTDIR "${SUBDIRQT}/msvc2019_arm64") + else() + set(QTDIR "${SUBDIRQT}/msvc2019_64") + endif() endif() elseif ("${PLATFORM}" MATCHES "osx") foreach(QT_VERSION 6 5) @@ -651,6 +658,11 @@ if("${QT_VERSION}" VERSION_LESS "${QT_MIN_VERSION}") message(FATAL_ERROR "Your Qt version is to old! Minimum required ${QT_MIN_VERSION}") endif() +# Pseydo target WrapVulkanHeaders::WrapVulkanHeaders for Qt6 +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6 AND NOT TARGET WrapVulkanHeaders::WrapVulkanHeaders) + add_library(WrapVulkanHeaders::WrapVulkanHeaders INTERFACE IMPORTED) +endif() + find_package(Qt${QT_VERSION_MAJOR} ${QT_VERSION} COMPONENTS Core Gui Network Sql Widgets REQUIRED) message(STATUS "Qt version used: ${QT_VERSION}") diff --git a/CMakePresets.json b/CMakePresets.json index 5a4fbe6d3..0a16af660 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -98,6 +98,13 @@ "CMAKE_BUILD_TYPE": "Release" } }, + { + "name": "relwithdebinfo", + "hidden": true, + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo" + } + }, { "name": "ninja-base", "hidden": true, @@ -166,6 +173,17 @@ "rhs": "Windows" } }, + { + "name": "windows-relwithdebinfo", + "displayName": "Windows (RelWithDebInfo) (msvc)", + "description": "Build with MSVC's CL as Release with Debug Symbols", + "inherits": [ "base", "relwithdebinfo", "msvc" ], + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, { "name": "windows-debug", "displayName": "Windows (debug) (msvc)", @@ -238,6 +256,19 @@ "rhs": "Windows" } }, + { + "name": "windows-relwithdebinfo", + "displayName": "Windows (RelWithDebInfo) (msvc)", + "description": "Build with MSVC's CL as Release with Debug Symbols", + "configuration": "RelWithDebInfo", + "targets": "all", + "configurePreset": "windows-relwithdebinfo", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, { "name": "windows-debug", "displayName": "Windows (debug) (msvc)", diff --git a/cmake/FindDebBuilder.cmake b/cmake/FindDebBuilder.cmake deleted file mode 100644 index e2f2c9ac0..000000000 --- a/cmake/FindDebBuilder.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# - Find package for .deb building -# Find the .deb building executable and extract the version number -# -# OUTPUT Variables -# -# DEB_BUILDER_FOUND -# True if the deb builder package was found -# DEB_BUILDER_EXECUTABLE -# The deb builder executable location -# DEB_BUILDER_VERSION -# A string denoting the version of deb builder that has been found - -find_program ( DEB_BUILDER_EXECUTABLE dpkg-deb ) - -if ( DEB_BUILDER_EXECUTABLE ) - SET( DEB_BUILDER_FOUND TRUE ) - execute_process ( COMMAND ${DEB_BUILDER_EXECUTABLE} --version OUTPUT_VARIABLE DEB_VERSION_RAW ERROR_QUIET ) - if (DEB_VERSION_RAW) - string ( REGEX REPLACE "^RPM-Version ([0-9]+.[0-9]+.[0-9]+),.*" "\\1" DEB_BUILDER_VERSION ${DEB_VERSION_RAW}) - else () - set ( DEB_BUILDER_VERSION "unknown" ) - endif() -endif () diff --git a/cmake/FindRpmBuilder.cmake b/cmake/FindRpmBuilder.cmake deleted file mode 100644 index 07a22468a..000000000 --- a/cmake/FindRpmBuilder.cmake +++ /dev/null @@ -1,23 +0,0 @@ -# - Find package for .rpm building -# Find the .rpm building executable and extract the version number -# -# OUTPUT Variables -# -# RPM_BUILDER_FOUND -# True if the rpm package was found -# RPM_BUILDER_EXECUTABLE -# The rpm executable location -# RPM_BUILDER_VERSION -# A string denoting the version of rpm that has been found - -find_program ( RPM_BUILDER_EXECUTABLE rpm ) - -if ( RPM_BUILDER_EXECUTABLE ) - SET( RPM_BUILDER_FOUND TRUE ) - execute_process ( COMMAND ${RPM_BUILDER_EXECUTABLE} --version OUTPUT_VARIABLE RPM_VERSION_RAW ERROR_QUIET ) - if (RPM_VERSION_RAW) - string ( REGEX REPLACE "^RPM-Version ([0-9]+.[0-9]+.[0-9]+),.*" "\\1" RPM_BUILDER_VERSION ${RPM_VERSION_RAW}) - else () - set ( RPM_BUILDER_VERSION "unknown" ) - endif() -endif () diff --git a/cmake/FindTurboJPEG.cmake b/cmake/FindTurboJPEG.cmake index c2c250203..d6fc2eefa 100644 --- a/cmake/FindTurboJPEG.cmake +++ b/cmake/FindTurboJPEG.cmake @@ -3,27 +3,29 @@ # TurboJPEG_INCLUDE_DIR # TurboJPEG_LIBRARY -set(TurboJPEG_PATHS - "$ENV{TURBOJPEG_DIR}" - "C:/libjpeg-turbo64" -) +set(TURBOJPEG_ROOT_DIR "${TURBOJPEG_ROOT_DIR}" CACHE PATH "Root directory to search for TurboJPEG") find_path(TurboJPEG_INCLUDE_DIR NAMES turbojpeg.h PATHS - ${TurboJPEG_PATHS} + "C:/libjpeg-turbo64" + HINTS + ${TURBOJPEG_ROOT_DIR} PATH_SUFFIXES include ) find_library(TurboJPEG_LIBRARY NAMES - libturbojpeg - turbojpeg turbojpeg-static + turbojpeg + libturbojpeg-static + libturbojpeg PATHS - ${TurboJPEG_PATHS} + "C:/libjpeg-turbo64" + HINTS + ${TURBOJPEG_ROOT_DIR} PATH_SUFFIXES bin lib diff --git a/cmake/FindWindowsSDK.cmake b/cmake/FindWindowsSDK.cmake index 6db4225ef..2a44bf886 100644 --- a/cmake/FindWindowsSDK.cmake +++ b/cmake/FindWindowsSDK.cmake @@ -45,14 +45,16 @@ # FindPackageHandleStandardArgs (known included with CMake >=2.6.2) # # Original Author: -# 2012 Ryan Pavlik -# http://academic.cleardefinition.com +# 2012 Rylie Pavlik +# https://ryliepavlik.com/ # Iowa State University HCI Graduate Program/VRAC # # Copyright 2012, Iowa State University +# # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) +# # SPDX-License-Identifier: BSL-1.0 set(_preferred_sdk_dirs) # pre-output @@ -77,6 +79,8 @@ endmacro() # although version numbers listed on that page don't necessarily match the directory # used by the installer. set(_winsdk_win10vers + 10.0.26100.0 + 10.0.22621.0 10.0.22000.0 10.0.20348.0 10.0.19041.0 @@ -625,7 +629,7 @@ if(WINDOWSSDK_FOUND) set(_dirs) foreach(_sdkdir ${ARGN}) get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs) - if(_current_sdk_libdirs) + if(_current_sdk_incdirs) list(APPEND _dirs ${_current_sdk_incdirs}) endif() endforeach() diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 18f520e8a..3b86be478 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -1,3 +1,5 @@ +include_guard(GLOBAL) + execute_process( COMMAND git config --global --add safe.directory "*" ERROR_QUIET diff --git a/cmake/HelperFunctions.cmake b/cmake/HelperFunctions.cmake index a5b8367e2..618f971bf 100644 --- a/cmake/HelperFunctions.cmake +++ b/cmake/HelperFunctions.cmake @@ -1,3 +1,5 @@ +include_guard(GLOBAL) + # Extract Major.Minor.Patch.Pre version from string function(SetVersionNumber PREFIX VERSION_STRING) string(REGEX MATCHALL "[0-9]+|-([A-Za-z0-9_.]+)" VERSION_PARTS ${VERSION_STRING}) diff --git a/cmake/HelperMacros.cmake b/cmake/HelperMacros.cmake index 66158c523..734f02d99 100644 --- a/cmake/HelperMacros.cmake +++ b/cmake/HelperMacros.cmake @@ -1,3 +1,5 @@ +include_guard(GLOBAL) + macro(addIndent text) if(${CMAKE_VERSION} VERSION_GREATER "3.16.0") list(APPEND CMAKE_MESSAGE_INDENT ${text}) diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 246de8f93..74d50ba22 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -1,9 +1,11 @@ # cmake file for generating distribution packages +include_guard(GLOBAL) + # Default packages to build if(CMAKE_SYSTEM_NAME MATCHES "Darwin") set(CPACK_GENERATOR "DragNDrop") - set(CPACK_DMG_FORMAT "UDBZ" ) + set(CPACK_DMG_FORMAT "UDBZ") set(CMAKE_SYSTEM_NAME "macOS") elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") set(CPACK_GENERATOR "TGZ") @@ -12,18 +14,20 @@ elseif(WIN32) # Overwrite CMAKE_SYSTEM_PROCESSOR for Windows (visual) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64") set(CMAKE_SYSTEM_PROCESSOR "x64") + elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "ARM64") + set(CMAKE_SYSTEM_PROCESSOR "arm64") endif() endif() # Determine packages by found generator executables -find_package(RpmBuilder) -if(RPM_BUILDER_FOUND) +find_program(RPM_BUILDER rpm) +if(RPM_BUILDER) message(STATUS "CPACK: Found RPM builder") set(CPACK_GENERATOR ${CPACK_GENERATOR} "RPM") endif() -find_package(DebBuilder) -if(DEB_BUILDER_FOUND) +find_program(DEB_BUILDER dpkg-deb) +if(DEB_BUILDER) message(STATUS "CPACK: Found DEB builder") set(CPACK_GENERATOR ${CPACK_GENERATOR} "DEB") endif() @@ -36,9 +40,9 @@ endif() # Apply to all packages, some of these can be overwritten with generator specific content # https://cmake.org/cmake/help/v3.5/module/CPack.html -set(CPACK_PACKAGE_NAME "Hyperion" ) -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an open source ambient light implementation" ) -set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md" ) +set(CPACK_PACKAGE_NAME "Hyperion") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Hyperion is an open source ambient light implementation") +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/README.md") if(NOT CMAKE_VERSION VERSION_LESS "3.18") set(CPACK_ARCHIVE_THREADS 0) @@ -50,16 +54,16 @@ set(CPACK_PACKAGE_FILE_NAME "Hyperion-${HYPERION_PACKAGE_VERSION}-${CMAKE_SYSTEM set(CPACK_PACKAGE_CONTACT "packages@hyperion-project.org") set(CPACK_PACKAGE_VENDOR "hyperion-project") -set(CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion" ) -set(CPACK_PACKAGE_INSTALL_DIRECTORY "Hyperion" ) -set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-32px.png" ) +set(CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion") +set(CPACK_PACKAGE_INSTALL_DIRECTORY "Hyperion") +set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icons/hyperion-32px.png") set(CPACK_PACKAGE_VERSION_MAJOR "${HYPERION_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${HYPERION_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${HYPERION_VERSION_PATCH}") -set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE" ) -set(CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion" ) -set(CPACK_CREATE_DESKTOP_LINKS "hyperiond;Hyperion" ) +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") +set(CPACK_PACKAGE_EXECUTABLES "hyperiond;Hyperion") +set(CPACK_CREATE_DESKTOP_LINKS "hyperiond;Hyperion") # Append pre-release version to CPACK_PACKAGE_VERSION_PATCH ifexists if(NOT "${HYPERION_VERSION_PRE}" STREQUAL "") @@ -71,27 +75,31 @@ endif() # DEB (UNIX only) # https://cmake.org/cmake/help/latest/cpack_gen/deb.html -set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/preinst;${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/postinst;${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/prerm") -set(CPACK_DEBIAN_PACKAGE_DEPENDS "libcec6 | libcec4 | libcec (>= 4.0)" ) -set(CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous" ) +if(CPACK_GENERATOR MATCHES ".*DEB.*") + set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/preinst;${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/postinst;${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/prerm") + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libcec6 | libcec4 | libcec (>= 4.0)") + set(CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous") +endif() # RPM (Unix Only) # https://cmake.org/cmake/help/latest/cpack_gen/rpm.html -set(CPACK_RPM_PACKAGE_RELEASE 1 ) -set(CPACK_RPM_PACKAGE_LICENSE "MIT" ) -set(CPACK_RPM_PACKAGE_GROUP "Applications" ) -set(CPACK_RPM_PACKAGE_REQUIRES "libcec >= 4.0.0" ) -set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/preinst") -set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/postinst") -set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/prerm") +if(CPACK_GENERATOR MATCHES ".*RPM.*") + set(CPACK_RPM_PACKAGE_RELEASE 1) + set(CPACK_RPM_PACKAGE_LICENSE "MIT") + set(CPACK_RPM_PACKAGE_GROUP "Applications") + set(CPACK_RPM_PACKAGE_REQUIRES "libcec >= 4.0.0") + set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/preinst") + set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/postinst") + set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE "${CMAKE_SOURCE_DIR}/cmake/linux/package-scripts/prerm") +endif() # DragNDrop (macOS only) # https://cmake.org/cmake/help/latest/cpack_gen/dmg.html -if(CMAKE_SYSTEM_NAME MATCHES "Darwin") - set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/cmake/macos/PackageIcon.icns" ) - set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/LICENSE" ) - set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/cmake/macos/Background.png" ) - set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/macos/AppleScript.scpt" ) +if(CPACK_GENERATOR MATCHES "DragNDrop") + set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/cmake/macos/PackageIcon.icns") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/LICENSE") + set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/cmake/macos/Background.png") + set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/macos/AppleScript.scpt") endif() # NSIS (Windows only) @@ -112,13 +120,13 @@ if(WIN32) string(REGEX REPLACE "\\\\" "\\\\\\\\" NSIS_HYP_LOGO_VERT "${NSIS_HYP_LOGO_VERT}") string(REGEX REPLACE "\\\\" "\\\\\\\\" NSIS_HYP_LOGO_HORI "${NSIS_HYP_LOGO_HORI}") - set(CPACK_NSIS_MODIFY_PATH ON ) + set(CPACK_NSIS_MODIFY_PATH ON) set(CPACK_NSIS_MUI_ICON ${NSIS_HYP_ICO}) set(CPACK_NSIS_MUI_UNIICON ${NSIS_HYP_ICO}) - set(CPACK_NSIS_MUI_HEADERIMAGE ${NSIS_HYP_LOGO_HORI} ) + set(CPACK_NSIS_MUI_HEADERIMAGE ${NSIS_HYP_LOGO_HORI}) set(CPACK_NSIS_MUI_WELCOMEFINISHPAGE_BITMAP ${NSIS_HYP_LOGO_VERT}) set(CPACK_NSIS_DISPLAY_NAME "Hyperion Ambient Light") - set(CPACK_NSIS_PACKAGE_NAME "Hyperion" ) + set(CPACK_NSIS_PACKAGE_NAME "Hyperion") set(CPACK_NSIS_INSTALLED_ICON_NAME "bin\\\\hyperiond.exe") set(CPACK_NSIS_HELP_LINK "https://www.hyperion-project.org") set(CPACK_NSIS_URL_INFO_ABOUT "https://www.hyperion-project.org") @@ -139,55 +147,55 @@ endif() set(CPACK_COMPONENTS_GROUPING "ALL_COMPONENTS_IN_ONE") # Components base (All builds) -set(CPACK_COMPONENTS_ALL "Hyperion" ) +set(CPACK_COMPONENTS_ALL "Hyperion") # Optional compiled if(ENABLE_REMOTE_CTL) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_remote" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_remote") endif() # only include standalone grabber with build was with flatbuffer client if(ENABLE_FLATBUF_CONNECT) if(ENABLE_QT) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_qt" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_qt") endif() if(ENABLE_AMLOGIC) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_aml" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_aml") endif() if(ENABLE_V4L2) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_v4l2" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_v4l2") endif() if(ENABLE_AUDIO) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_audio" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_audio") endif() if(ENABLE_X11) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_x11" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_x11") endif() if(ENABLE_XCB) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_xcb" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_xcb") endif() if(ENABLE_DISPMANX) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_dispmanx" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_dispmanx") endif() if(ENABLE_FB) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_framebuffer" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_framebuffer") endif() if(ENABLE_OSX) - set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_osx" ) + set(CPACK_COMPONENTS_ALL ${CPACK_COMPONENTS_ALL} "hyperion_osx") endif() -endif(ENABLE_FLATBUF_CONNECT) +endif() # Only include Hyperion to macOS dmg package (without standalone programs) -if(CPACK_GENERATOR MATCHES "DragNDrop" ) - LIST ( REMOVE_ITEM CPACK_COMPONENTS_ALL "hyperion_remote" "hyperion_qt" "hyperion_osx" ) +if(CPACK_GENERATOR MATCHES "DragNDrop") + list(REMOVE_ITEM CPACK_COMPONENTS_ALL "hyperion_remote" "hyperion_qt" "hyperion_osx") endif() -set(CPACK_ARCHIVE_COMPONENT_INSTALL ON ) -set(CPACK_DEB_COMPONENT_INSTALL ON ) -set(CPACK_RPM_COMPONENT_INSTALL ON ) +set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) +set(CPACK_DEB_COMPONENT_INSTALL ON) +set(CPACK_RPM_COMPONENT_INSTALL ON) -set(CPACK_STRIP_FILES ON ) +set(CPACK_STRIP_FILES ON) # no code after following line! include(CPack) @@ -206,16 +214,15 @@ cpack_add_component(Hyperion ) # optional components - if(ENABLE_REMOTE_CTL) -cpack_add_component_group(Remote DESCRIPTION "hyperion-remote commandline tool") -cpack_add_component(hyperion_remote - DISPLAY_NAME "Hyperion Remote" - DESCRIPTION "Hyperion remote cli tool" - INSTALL_TYPES Full - GROUP Remote - DEPENDS Hyperion -) + cpack_add_component_group(Remote DESCRIPTION "hyperion-remote commandline tool") + cpack_add_component(hyperion_remote + DISPLAY_NAME "Hyperion Remote" + DESCRIPTION "Hyperion remote cli tool" + INSTALL_TYPES Full + GROUP Remote + DEPENDS Hyperion + ) endif() # only include standalone grabber with build was with flatbuffer client @@ -293,4 +300,4 @@ if(ENABLE_FLATBUF_CONNECT) DEPENDS Hyperion ) endif() -endif(ENABLE_FLATBUF_CONNECT) +endif() diff --git a/cmake/windows/BundleWindows.cmake.in b/cmake/windows/BundleWindows.cmake.in index 35cb072ad..6227a54e8 100644 --- a/cmake/windows/BundleWindows.cmake.in +++ b/cmake/windows/BundleWindows.cmake.in @@ -54,25 +54,18 @@ if(EXISTS @CMAKE_BINARY_DIR@/bin/@PROJECT_NAME@@CMAKE_EXECUTABLE_SUFFIX@) # Create a qt.conf file in 'bin' to override hard-coded search paths in Qt plugins file(WRITE "${CMAKE_INSTALL_PREFIX}/bin/qt.conf" "[Paths]\nPlugins=../lib/\n") - # Copy libjpeg-turbo to 'hyperion' + # Copy turbojpeg to 'hyperion' if(ENABLE_MF AND NOT TurboJPEG_INCLUDE_DIR STREQUAL "") get_filename_component(TURBOJPEG_DIR "${TurboJPEG_INCLUDE_DIR}" DIRECTORY) - foreach(comp "turbojpeg" "jpeg62") - find_file(${comp} - NAMES - "${comp}.dll" - PATHS - ${TURBOJPEG_DIR} - PATH_SUFFIXES - bin - ) - - file(INSTALL FILES ${${comp}} DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") - endforeach() + find_file(TURBOJPEG_SHARED NAMES "turbojpeg.dll" PATHS ${TURBOJPEG_DIR} PATH_SUFFIXES bin) + if(TURBOJPEG_SHARED) + file(INSTALL FILES ${TURBOJPEG_SHARED} DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") + endif() endif() if(NOT PYTHON_VERSION STREQUAL "") - set(PYTHON_EMBED_URL "https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-embed-amd64.zip") + string(TOLOWER "@CMAKE_SYSTEM_PROCESSOR@" PYTHON_ARCH) + set(PYTHON_EMBED_URL "https://www.python.org/ftp/python/${PYTHON_VERSION}/python-${PYTHON_VERSION}-embed-${PYTHON_ARCH}.zip") get_filename_component(PYTHON_EMBED_ARCHIVE ${PYTHON_EMBED_URL} NAME) # Download embed python package (release build only) diff --git a/include/effectengine/EffectModule.h b/include/effectengine/EffectModule.h index d7c68de8d..3f7b9749e 100644 --- a/include/effectengine/EffectModule.h +++ b/include/effectengine/EffectModule.h @@ -1,17 +1,7 @@ #pragma once #undef slots -// Don't use debug Python APIs on Windows (GitHub Actions only) -#if defined(GITHUB_ACTIONS) && defined(_MSC_VER) && defined(_DEBUG) -#if _MSC_VER >= 1930 -#include -#endif -#undef _DEBUG #include -#define _DEBUG -#else -#include -#endif #define slots Q_SLOTS #include diff --git a/include/python/PythonInit.h b/include/python/PythonInit.h index 30fcb32d5..316d84642 100644 --- a/include/python/PythonInit.h +++ b/include/python/PythonInit.h @@ -1,17 +1,7 @@ #pragma once #undef slots -// Don't use debug Python APIs on Windows (GitHub Actions only) -#if defined(GITHUB_ACTIONS) && defined(_MSC_VER) && defined(_DEBUG) -#if _MSC_VER >= 1930 -#include -#endif -#undef _DEBUG -#include -#define _DEBUG -#else #include -#endif #define slots Q_SLOTS /// diff --git a/include/python/PythonProgram.h b/include/python/PythonProgram.h index 6fa71a85a..cf0a8a587 100644 --- a/include/python/PythonProgram.h +++ b/include/python/PythonProgram.h @@ -4,17 +4,7 @@ #include #undef slots -// Don't use debug Python APIs on Windows (GitHub Actions only) -#if defined(GITHUB_ACTIONS) && defined(_MSC_VER) && defined(_DEBUG) -#if _MSC_VER >= 1930 -#include -#endif -#undef _DEBUG #include -#define _DEBUG -#else -#include -#endif #define slots Q_SLOTS #include diff --git a/include/python/PythonUtils.h b/include/python/PythonUtils.h index 651aa752d..10574fc11 100644 --- a/include/python/PythonUtils.h +++ b/include/python/PythonUtils.h @@ -1,17 +1,7 @@ #pragma once #undef slots -// Don't use debug Python APIs on Windows (GitHub Actions only) -#if defined(GITHUB_ACTIONS) && defined(_MSC_VER) && defined(_DEBUG) -#if _MSC_VER >= 1930 -#include -#endif -#undef _DEBUG -#include -#define _DEBUG -#else #include -#endif #define slots Q_SLOTS // decl diff --git a/libsrc/effectengine/EffectEngine.cpp b/libsrc/effectengine/EffectEngine.cpp index 06ace054f..d6060ddb4 100644 --- a/libsrc/effectengine/EffectEngine.cpp +++ b/libsrc/effectengine/EffectEngine.cpp @@ -1,14 +1,4 @@ -// Don't use debug Python APIs on Windows (GitHub Actions only) -#if defined(GITHUB_ACTIONS) && defined(_MSC_VER) && defined(_DEBUG) -#if _MSC_VER >= 1930 -#include -#endif -#undef _DEBUG #include -#define _DEBUG -#else -#include -#endif #undef B0 // Qt includes diff --git a/libsrc/grabber/video/CMakeLists.txt b/libsrc/grabber/video/CMakeLists.txt index ec365f4a3..88f6d3cdb 100644 --- a/libsrc/grabber/video/CMakeLists.txt +++ b/libsrc/grabber/video/CMakeLists.txt @@ -12,25 +12,29 @@ elseif(ENABLE_V4L2) set(grabber_project V4L2) endif() -add_library(${PROJECT_NAME} - ${CMAKE_SOURCE_DIR}/include/grabber/video/EncoderThread.h - ${CMAKE_SOURCE_DIR}/include/grabber/video/VideoWrapper.h - ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/EncoderThread.cpp - ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/VideoWrapper.cpp - ${CMAKE_SOURCE_DIR}/include/grabber/video/${${grabber_project}-grabber}/${grabber_project}Grabber.h - ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/${${grabber_project}-grabber}/${grabber_project}Grabber.cpp - ${MediaFoundationSourceReaderCallBack} -) +if(ENABLE_V4L2 OR ENABLE_MF) + add_library(${PROJECT_NAME} + ${CMAKE_SOURCE_DIR}/include/grabber/video/EncoderThread.h + ${CMAKE_SOURCE_DIR}/include/grabber/video/VideoWrapper.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/EncoderThread.cpp + ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/VideoWrapper.cpp + ${CMAKE_SOURCE_DIR}/include/grabber/video/${${grabber_project}-grabber}/${grabber_project}Grabber.h + ${CMAKE_SOURCE_DIR}/libsrc/grabber/video/${${grabber_project}-grabber}/${grabber_project}Grabber.cpp + ${MediaFoundationSourceReaderCallBack} + ) -target_link_libraries(${PROJECT_NAME} hyperion) + target_link_libraries(${PROJECT_NAME} hyperion) + + if(ENABLE_MF AND USE_PRE_BUILT_DEPS) + set(TURBOJPEG_ROOT_DIR ${PRE_BUILT_DEPS_DIR}) + endif() -# Add Turbo JPEG library -if(ENABLE_V4L2 OR ENABLE_MF) find_package(TurboJPEG) - if(TURBOJPEG_FOUND) + if(TURBOJPEG_FOUND AND TARGET turbojpeg) target_compile_definitions(${PROJECT_NAME} PRIVATE HAVE_TURBO_JPEG) target_link_libraries(${PROJECT_NAME} turbojpeg) else () - message(STATUS "Turbo JPEG library not found, MJPEG camera format won't work.") + message(STATUS "TurboJPEG library not found, MJPEG camera format won't work.") endif() endif() + diff --git a/libsrc/utils/SysInfo.cpp b/libsrc/utils/SysInfo.cpp index d206b0c76..0dc2cbdf0 100644 --- a/libsrc/utils/SysInfo.cpp +++ b/libsrc/utils/SysInfo.cpp @@ -1,19 +1,8 @@ #include "HyperionConfig.h" #if defined(ENABLE_EFFECTENGINE) -// Don't use debug Python APIs on Windows (GitHub Actions only) -#if defined(GITHUB_ACTIONS) && defined(_MSC_VER) && defined(_DEBUG) -#if _MSC_VER >= 1930 -#include -#endif -#undef _DEBUG -#include -#define _DEBUG -#else #include #endif -#endif - #include "utils/SysInfo.h" #include "utils/FileUtils.h" diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index b4064bd9c..aa304e4f8 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -28,7 +28,9 @@ if(WIN32) message(WARNING "Cannot find the windeployqt tool.") endif() endif() -elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Darwin") # include resource files for macos bundle (copy LICENSE file and correct line breaks) configure_file(${CMAKE_SOURCE_DIR}/LICENSE ${CMAKE_BINARY_DIR}/LICENSE COPYONLY) execute_process(COMMAND bash -c "perl -pi -e 's/\n/\r/g' ${CMAKE_BINARY_DIR}/LICENSE") @@ -53,6 +55,7 @@ add_executable(${PROJECT_NAME} ${MACOS_BUNDLE_RESOURCE_FILES} ) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS DBus QUIET) target_link_libraries(${PROJECT_NAME} commandline hyperion @@ -62,97 +65,44 @@ target_link_libraries(${PROJECT_NAME} database resources events + # Qt Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Network Qt${QT_VERSION_MAJOR}::Widgets + $<$:Qt${QT_VERSION_MAJOR}::DBus> + # Grabber + $<$:dispmanx-grabber> + $<$:framebuffer-grabber> + $<$:osx-grabber> + $<$:v4l2-grabber> + $<$:mf-grabber> + $<$:audio-grabber> + $<$:amlogic-grabber> + $<$:x11-grabber> + $<$:xcb-grabber> + $<$:qt-grabber> + $<$:directx-grabber> + $<$:dda-grabber> + # Input + $<$:flatbufserver> + $<$:protoserver> + $<$:cechandler> + # Services + $<$:effectengine python> + $<$:mdns> ) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS DBus QUIET) -if(Qt${QT_VERSION_MAJOR}DBus_FOUND) - target_link_libraries(${PROJECT_NAME} "Qt${QT_VERSION_MAJOR}::DBus") -endif() +##################################### +########### Install steps ########### +##################################### if(ENABLE_EFFECTENGINE AND TARGET python) - target_link_libraries(${PROJECT_NAME} effectengine python) get_target_property(PYTHON_VERSION python PYTHON_VERSION_PROPERTY) get_target_property(PYTHON_MODULES_DIR python PYTHON_STDLIB_LOCATION_PROPERTY) endif() -if(ENABLE_FLATBUF_SERVER) - target_link_libraries(${PROJECT_NAME} flatbufserver) -endif() - -if(ENABLE_PROTOBUF_SERVER) - target_link_libraries(${PROJECT_NAME} protoserver) -endif() - -if(ENABLE_DISPMANX) - target_link_libraries(${PROJECT_NAME} dispmanx-grabber) -endif() - -if(ENABLE_FB) - target_link_libraries(${PROJECT_NAME} framebuffer-grabber) -endif() - -if(ENABLE_OSX) - target_link_libraries(${PROJECT_NAME} osx-grabber) -endif() - -if(ENABLE_V4L2) - target_link_libraries(${PROJECT_NAME} v4l2-grabber) -endif() - -if(ENABLE_MF) - target_link_libraries(${PROJECT_NAME} mf-grabber) - if(TARGET turbojpeg) - get_target_property(TurboJPEG_INCLUDE_DIR turbojpeg INTERFACE_INCLUDE_DIRECTORIES) - endif() -endif() - -if(ENABLE_AUDIO) - target_link_libraries(hyperiond audio-grabber) -endif() - -if(ENABLE_AMLOGIC) - target_link_libraries(${PROJECT_NAME} amlogic-grabber) -endif() - -if(ENABLE_X11) - if(CMAKE_SYSTEM_NAME MATCHES "Darwin") - include_directories("/opt/X11/include") - endif() - target_link_libraries(${PROJECT_NAME} x11-grabber) -endif() - -if(ENABLE_XCB) - target_link_libraries(${PROJECT_NAME} xcb-grabber) -endif() - -if(ENABLE_QT) - target_link_libraries(${PROJECT_NAME} qt-grabber) -endif() - -if(ENABLE_DX) - target_link_libraries(${PROJECT_NAME} directx-grabber) -endif() - -if(ENABLE_DDA) - target_link_libraries(${PROJECT_NAME} dda-grabber) -endif() - -if(ENABLE_CEC) - target_link_libraries(${PROJECT_NAME} cechandler) -endif() - -if(ENABLE_MDNS) - target_link_libraries(${PROJECT_NAME} mdns) -endif() - -##################################### -########### Install steps ########### -##################################### - +# MacOS if(CMAKE_SYSTEM_NAME MATCHES "Darwin") # set bundle information set(MAC_BUNDLE_NAME "Hyperion") @@ -173,7 +123,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin") install(TARGETS ${PROJECT_NAME} BUNDLE DESTINATION . COMPONENT "Hyperion") configure_file("${CMAKE_SOURCE_DIR}/cmake/macos/BundleMacOS.cmake.in" "${PROJECT_BINARY_DIR}/BundleMacOS.cmake" @ONLY) install(SCRIPT "${PROJECT_BINARY_DIR}/BundleMacOS.cmake" COMPONENT "Hyperion") -elseif(NOT WIN32) +endif() + +# Linux +if(CMAKE_SYSTEM_NAME MATCHES "Linux") # install Hyperion/service files/effect folder install(TARGETS ${PROJECT_NAME} DESTINATION "share/hyperion/bin" COMPONENT "Hyperion") install(DIRECTORY ${CMAKE_SOURCE_DIR}/bin/service DESTINATION "share/hyperion" COMPONENT "Hyperion") @@ -201,14 +154,29 @@ elseif(NOT WIN32) configure_file("${CMAKE_SOURCE_DIR}/cmake/linux/BundleLinux.cmake.in" "${PROJECT_BINARY_DIR}/BundleLinux.cmake" @ONLY) install(SCRIPT "${PROJECT_BINARY_DIR}/BundleLinux.cmake" COMPONENT "Hyperion") endif() -else() +endif() + +# Windows +if(WIN32) install(TARGETS ${PROJECT_NAME} DESTINATION "bin" COMPONENT "Hyperion" OPTIONAL) install(FILES ${CMAKE_SOURCE_DIR}/effects/readme.txt DESTINATION "effects" COMPONENT "Hyperion") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP true) + set(CMAKE_INSTALL_UCRT_LIBRARIES true) + set(CMAKE_INSTALL_DEBUG_LIBRARIES true) + set(CMAKE_INSTALL_DEBUG_LIBRARIES_ONLY true) + include (InstallRequiredSystemLibraries) + endif() + if(TARGET Qt${QT_VERSION_MAJOR}::windeployqt) get_target_property(WINDEPLOYQT_EXECUTABLE Qt${QT_VERSION_MAJOR}::windeployqt IMPORTED_LOCATION) endif() + if(ENABLE_MF AND TARGET turbojpeg) + get_target_property(TurboJPEG_INCLUDE_DIR turbojpeg INTERFACE_INCLUDE_DIRECTORIES) + endif() + configure_file("${CMAKE_SOURCE_DIR}/cmake/windows/BundleWindows.cmake.in" "${PROJECT_BINARY_DIR}/BundleWindows.cmake" @ONLY) install(SCRIPT "${PROJECT_BINARY_DIR}/BundleWindows.cmake" COMPONENT "Hyperion") endif() From 9b5a0bb80f12981ff7f440ccaade8debbd7cccfd Mon Sep 17 00:00:00 2001 From: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Fri, 16 May 2025 17:23:40 +0200 Subject: [PATCH 02/27] test run --- .github/workflows/qt5_6.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/qt5_6.yml b/.github/workflows/qt5_6.yml index 82ff5020d..86fd1a6d9 100644 --- a/.github/workflows/qt5_6.yml +++ b/.github/workflows/qt5_6.yml @@ -146,12 +146,10 @@ jobs: - name: 👷 Build ${{ env.HINT }} shell: bash run: | - # Remove once issue with Homebrew cache action is fixed - brew reinstall --formula cmake - # Build cmake --preset macos-${{ env.BUILD_TYPE }} ${{ steps.dependencies.outputs.cmakeArgs }} cmake --build --preset macos-${{ env.BUILD_TYPE }} + # CPack workaround for macOS 13 attempt=0 max_attempts=5 From 9f2e080da5f71b60fd7e30ef5df50f4d382bfd50 Mon Sep 17 00:00:00 2001 From: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Fri, 16 May 2025 18:01:22 +0200 Subject: [PATCH 03/27] Added XProtect race condition workaround --- .github/workflows/qt5_6.yml | 16 +--------------- cmake/Packaging.cmake | 1 + cmake/macos/hdiutilwrap.sh | 24 ++++++++++++++++++++++++ 3 files changed, 26 insertions(+), 15 deletions(-) create mode 100755 cmake/macos/hdiutilwrap.sh diff --git a/.github/workflows/qt5_6.yml b/.github/workflows/qt5_6.yml index 86fd1a6d9..3212a002e 100644 --- a/.github/workflows/qt5_6.yml +++ b/.github/workflows/qt5_6.yml @@ -148,21 +148,7 @@ jobs: run: | # Build cmake --preset macos-${{ env.BUILD_TYPE }} ${{ steps.dependencies.outputs.cmakeArgs }} - cmake --build --preset macos-${{ env.BUILD_TYPE }} - - # CPack workaround for macOS 13 - attempt=0 - max_attempts=5 - while [ $attempt -lt $max_attempts ]; do - if cd build && cpack; then - echo "Package created successfully" - break - else - echo "Failed to create package, retrying..." - sleep 10 - fi - attempt=$((attempt + 1)) - done + cmake --build --preset macos-${{ env.BUILD_TYPE }} --target package env: BUILD_TYPE: ${{ inputs.event_name == 'pull_request' && 'debug' || 'release' }} HINT: ${{ steps.dependencies.outputs.cmakeArgs != '' && '(with pre-built dependencies)' || '(full build)' }} diff --git a/cmake/Packaging.cmake b/cmake/Packaging.cmake index 74d50ba22..e3affc8f6 100644 --- a/cmake/Packaging.cmake +++ b/cmake/Packaging.cmake @@ -100,6 +100,7 @@ if(CPACK_GENERATOR MATCHES "DragNDrop") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/LICENSE") set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_SOURCE_DIR}/cmake/macos/Background.png") set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_SOURCE_DIR}/cmake/macos/AppleScript.scpt") + set(CPACK_COMMAND_HDIUTIL "${CMAKE_SOURCE_DIR}/cmake/macos/hdiutilwrap.sh") endif() # NSIS (Windows only) diff --git a/cmake/macos/hdiutilwrap.sh b/cmake/macos/hdiutilwrap.sh new file mode 100755 index 000000000..dae7d47b2 --- /dev/null +++ b/cmake/macos/hdiutilwrap.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# Copied from https://github.com/HEXRD/hexrdgui/blob/master/packaging/hdiutil_repeat.sh +# Workaround XProtect race condition for "hdiutil create" for MacOS 13 + + set -e + + if [ "$1" != "create" ]; then + # If it isn't an `hdiutil create` command, just run and exit normally + hdiutil "$@" + exit 0 + fi + + # For an `hdiutil create` command, try repeatedly, up to 10 times + # This prevents spurious errors caused by a race condition with XProtect + # See https://github.com/actions/runner-images/issues/7522 + i=0 + until + hdiutil "$@" + do + if [ $i -eq 10 ]; then exit 1; fi + i=$((i+1)) + sleep 1 + done From 997c338cd45761ec6e571b5d4e673e394a3ae55d Mon Sep 17 00:00:00 2001 From: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Fri, 16 May 2025 19:45:47 +0200 Subject: [PATCH 04/27] Update Changelog --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54437fc5b..f34eecf5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Systray: Support multiple instances - UI: Validate that key ports do not overlap across editors and pages - UI: Provide additional details in error dialogue -- UI: LED preview - show instance's name the preview is applicable to +- UI: LED preview - show instance's name the preview is applicable to - Http-Server: Support Cross-Origin Resource Sharing (CORS) (#1496) +- GitHub: Windows 11 (arm64) has been added to the Qt6 workflow build **JSON-API** - New subscription support for event updates, i.e. `Suspend, Resume, Idle, idleResume, Restart, Quit`. @@ -37,7 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Overview](https://github.com/hyperion-project/hyperion.ng/blob/API_Auth/doc/development/JSON-API%20_Commands_Overview.md) of API commands and subscription updates - Support to query for a dedicated set of configuration items for a set of instances - Support to save a dedicated set of configuration items for a set of instances -- Limit update emission frequency: Images (25Hz), raw LED-Colors (40Hz) & LED-Device data (200Hz) +- Limit update emission frequency: Images (25Hz), raw LED-Colors (40Hz) & LED-Device data (200Hz) - Support for requesting instance-data via JSON-API. Implemented requesting the current image in different formats or led colors. ### Changed @@ -72,7 +73,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed Last update of an effect event is not removed in sources overview - Fixed Removed stale _logger object - Fixed Smoothing (#1863) -- UI: Instance listings are sorted, enabled instances are high-lighted in drop-downs +- UI: Instance listings are sorted, enabled instances are high-lighted in drop-downs +- GitHub: For Windows, Pull request artifacts are now built with RelWithDebInfo (#1865 ) **JSON-API** - Refactored JSON-API to ensure consistent authorization behaviour across sessions and single requests with token authorization. From 93427d37798d0c8b7d156c08d639645c78ab08f1 Mon Sep 17 00:00:00 2001 From: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Fri, 16 May 2025 19:58:04 +0200 Subject: [PATCH 05/27] typo --- .github/workflows/qt5_6.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qt5_6.yml b/.github/workflows/qt5_6.yml index 3212a002e..b7f30e11a 100644 --- a/.github/workflows/qt5_6.yml +++ b/.github/workflows/qt5_6.yml @@ -238,7 +238,7 @@ jobs: os: 'windows' architecture: ${{ matrix.architecture }} qt_version: ${{ inputs.qt_version }} - build_type: ${{ inputs.event_name != 'pull_request' && 'relwithdebinfo' || 'release' }} + build_type: ${{ inputs.event_name == 'pull_request' && 'relwithdebinfo' || 'release' }} - name: 👷 Build ${{ env.HINT }} shell: cmd @@ -246,7 +246,7 @@ jobs: cmake --preset windows-${{ env.BUILD_TYPE }} ${{ steps.dependencies.outputs.cmakeArgs }} cmake --build --preset windows-${{ env.BUILD_TYPE }} --target package env: - BUILD_TYPE: ${{ inputs.event_name != 'pull_request' && 'relwithdebinfo' || 'release' }} + BUILD_TYPE: ${{ inputs.event_name == 'pull_request' && 'relwithdebinfo' || 'release' }} HINT: ${{ steps.dependencies.outputs.cmakeArgs != '' && '(with pre-built dependencies)' || '(full build)' }} - name: 📦 Upload From 53f8412568efa12cb3f31678db3268210bad5204 Mon Sep 17 00:00:00 2001 From: Paulchen-Panther <16664240+Paulchen-Panther@users.noreply.github.com> Date: Sat, 24 May 2025 15:26:16 +0200 Subject: [PATCH 06/27] Collect the correct QT dlls on Windows --- cmake/windows/BundleWindows.cmake.in | 23 ++++++++++++++++------- src/hyperiond/CMakeLists.txt | 9 ++++++++- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/cmake/windows/BundleWindows.cmake.in b/cmake/windows/BundleWindows.cmake.in index 6227a54e8..042f1d112 100644 --- a/cmake/windows/BundleWindows.cmake.in +++ b/cmake/windows/BundleWindows.cmake.in @@ -7,20 +7,29 @@ set(CMAKE_SOURCE_DIR "@CMAKE_SOURCE_DIR@") set(CMAKE_CURRENT_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@") # Set windeployqt args -set(ARGS --dry-run --no-opengl-sw --list mapping) +set(QT5_ARGS) if(@QT_VERSION_MAJOR@ EQUAL 5) - set(EXTRA_ARGS --no-angle) + set(QT5_ARGS --no-angle) +endif() + +find_file(QT_PATHS "qtpaths.bat" PATHS @CMAKE_PREFIX_PATH@ PATH_SUFFIXES bin) +if(QT_PATHS) + set(QT_PATHS --qtpaths=${QT_PATHS}) +else() + set(QT_PATHS "") endif() if(EXISTS @CMAKE_BINARY_DIR@/bin/@PROJECT_NAME@@CMAKE_EXECUTABLE_SUFFIX@) # Collect the runtime libraries - get_filename_component(QT_BIN_DIR "${QMAKE_EXECUTABLE}" DIRECTORY) execute_process( - COMMAND "${CMAKE_COMMAND}" -E env "PATH=${QT_BIN_DIR}" "@WINDEPLOYQT_EXECUTABLE@" - ${ARGS} - ${EXTRA_ARGS} + COMMAND "${CMAKE_COMMAND}" -E env "PATH=@QT_BIN_DIR@" "@WINDEPLOYQT_EXECUTABLE@" + ${QT_PATHS} + --dry-run + --no-opengl-sw + ${QT5_ARGS} + --list mapping "@CMAKE_BINARY_DIR@/bin/@PROJECT_NAME@@CMAKE_EXECUTABLE_SUFFIX@" - WORKING_DIRECTORY "${QT_BIN_DIR}/.." + WORKING_DIRECTORY "@QT_BIN_DIR@/.." OUTPUT_VARIABLE DEPS OUTPUT_STRIP_TRAILING_WHITESPACE ) diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index aa304e4f8..c07a4ae0c 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -16,8 +16,8 @@ if(WIN32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup") # Search for windeployqt target (qt6 has the target natively) otherwise create it. + get_filename_component(QT_BIN_DIR ${QMAKE_EXECUTABLE} DIRECTORY) if(NOT TARGET Qt${QT_VERSION_MAJOR}::windeployqt) - get_filename_component(QT_BIN_DIR ${QMAKE_EXECUTABLE} DIRECTORY) find_program(WINDEPLOYQT_EXECUTABLE NAMES windeployqt HINTS ${QT_BIN_DIR}) if(EXISTS ${WINDEPLOYQT_EXECUTABLE}) add_executable(Qt${QT_VERSION_MAJOR}::windeployqt IMPORTED) @@ -190,6 +190,13 @@ endif() if(WIN32 AND NOT DEFINED ENV{GITHUB_ACTIONS}) if(TARGET Qt${QT_VERSION_MAJOR}::windeployqt) set(WINDEPLOYQT_PARAMS --verbose 0 --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler) + + get_target_property(QT_QTPATHS_EXECUTABLE Qt${QT_VERSION_MAJOR}::qtpaths IMPORTED_LOCATION) + find_file(QT_PATHS "qtpaths.bat" PATHS ${CMAKE_PREFIX_PATH} PATH_SUFFIXES bin) + if(QT_PATHS) + list(APPEND WINDEPLOYQT_PARAMS "--qtpaths=${QT_PATHS}") + endif() + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND Qt${QT_VERSION_MAJOR}::windeployqt ${WINDEPLOYQT_PARAMS} "$" ) From 4fa40770457d48580711f669b92b2d9b3a6d66a5 Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 08:07:31 +0200 Subject: [PATCH 07/27] Add SignalHandling to Windows --- libsrc/utils/CMakeLists.txt | 4 + libsrc/utils/DefaultSignalHandler.cpp | 316 ++++++++++++++------------ 2 files changed, 173 insertions(+), 147 deletions(-) diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index 3fc283e71..db984c583 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -103,6 +103,10 @@ target_link_libraries(hyperion-utils Qt${QT_VERSION_MAJOR}::Network ) +if(WIN32) + target_link_libraries(hyperion-utils dbghelp) +endif() + if(ENABLE_EFFECTENGINE) target_link_libraries(hyperion-utils python) endif() diff --git a/libsrc/utils/DefaultSignalHandler.cpp b/libsrc/utils/DefaultSignalHandler.cpp index 378099bcc..cb4d17e41 100644 --- a/libsrc/utils/DefaultSignalHandler.cpp +++ b/libsrc/utils/DefaultSignalHandler.cpp @@ -1,184 +1,206 @@ -#ifndef _WIN32 - #include #include +#include +#include +#include + +#include + +#ifdef _WIN32 +#include +#include +#include +#pragma comment(lib, "dbghelp.lib") +#else #include #include #include #include #include -#include -#include -#include +#endif -#include +namespace DefaultSignalHandler { -namespace DefaultSignalHandler -{ -struct Signal -{ - int number; - const char * name; -}; - -const Signal ALL_SIGNALS[] = { - { SIGABRT, "SIGABRT" }, - { SIGBUS, "SIGBUS" }, - { SIGFPE, "SIGFPE" }, - { SIGSEGV, "SIGSEGV" }, - { SIGTERM, "SIGTERM" }, - { SIGHUP, "SIGHUP" }, - { SIGINT, "SIGINT" }, - { SIGPIPE, "SIGPIPE" }, -}; - -void write_to_stderr(const char* data, size_t size) -{ - int res = write(STDERR_FILENO, data, size); - - Q_UNUSED(res); -} - -void write_to_stderr(const char* data) -{ - write_to_stderr(data, strlen(data)); -} - -std::string decipher_trace(const std::string &trace) -{ - std::string result; - - if(trace.empty()) - { - result += "??\n"; - return result; +#ifdef _WIN32 + void write_to_stderr(const char* data) { + DWORD written; + WriteFile(GetStdHandle(STD_ERROR_HANDLE), data, strlen(data), &written, NULL); } +#else + void write_to_stderr(const char* data, size_t size) { + int res = write(STDERR_FILENO, data, size); + Q_UNUSED(res); + } + + void write_to_stderr(const char* data) { + write_to_stderr(data, strlen(data)); + } +#endif + +#ifndef _WIN32 + std::string decipher_trace(const std::string& trace) { + std::string result; - auto* begin = strchr(trace.c_str(), '(') + 1; - auto* end = strchr(begin, '+'); + if (trace.empty()) { + result += "??\n"; + return result; + } - if(!end) - end = strchr(begin, ')'); + auto* begin = strchr(trace.c_str(), '(') + 1; + auto* end = strchr(begin, '+'); + if (!end) end = strchr(begin, ')'); - std::string mangled_name(begin, end); + std::string mangled_name(begin, end); + int status; + char* realname = abi::__cxa_demangle(mangled_name.c_str(), 0, 0, &status); - int status; - char * realname = abi::__cxa_demangle(mangled_name.c_str(), 0, 0, &status); - result.insert(result.end(), trace.c_str(), begin); + result.insert(result.end(), trace.c_str(), begin); + if (realname) result += realname; + else result.insert(result.end(), begin, end); + free(realname); + result.insert(result.size(), end); - if(realname) - result += realname; - else - result.insert(result.end(), begin, end); + return result; + } +#endif - free(realname); - result.insert(result.size(), end); + void print_trace() { + Logger* log = Logger::getInstance("CORE"); - return result; -} +#ifdef _WIN32 + void* stack[50]; + HANDLE process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); -void print_trace() -{ - const int MAX_SIZE = 50; - void * addresses[MAX_SIZE]; - int size = backtrace(addresses, MAX_SIZE); + USHORT frames = CaptureStackBackTrace(0, 50, stack, NULL); + SYMBOL_INFO* symbol = (SYMBOL_INFO*)malloc(sizeof(SYMBOL_INFO) + 256); + symbol->MaxNameLen = 255; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - if (!size) - return; + for (USHORT i = 2; i < frames; ++i) { + if (SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol)) { + Error(log, "\t%s\n", symbol->Name); + } + } - Logger* log = Logger::getInstance("CORE"); - char ** symbols = backtrace_symbols(addresses, size); + free(symbol); +#else + const int MAX_SIZE = 50; + void* addresses[MAX_SIZE]; + int size = backtrace(addresses, MAX_SIZE); - /* Skip first 2 frames as they are signal - * handler and print_trace functions. */ - for (int i = 2; i < size; ++i) - { - const std::string line = "\t" + decipher_trace(symbols[i]); - Error(log, "%s", line.c_str()); - } + if (!size) return; - free(symbols); -} - -void install_default_handler(int signum) -{ - struct sigaction action{}; - sigemptyset(&action.sa_mask); - action.sa_handler = SIG_DFL; - (void)sigaction(signum, &action, nullptr); -} - -/* Note that this signal handler is not async signal safe ! - * Ideally a signal handler should only flip a bit and defer - * heavy work to some kind of bottom-half processing. */ -void signal_handler(int signum, siginfo_t * /*info*/, void * /*context*/) -{ - const char * name = "UNKNOWN SIGNAL"; - - for (const auto& s : ALL_SIGNALS) { - if (s.number == signum) { - name = s.name; - break; + char** symbols = backtrace_symbols(addresses, size); + for (int i = 2; i < size; ++i) { + const std::string line = "\t" + decipher_trace(symbols[i]); + Error(log, "%s", line.c_str()); } + + free(symbols); +#endif } - write_to_stderr("\n"); - write_to_stderr(QCoreApplication::applicationName().toLocal8Bit()); - write_to_stderr(" caught signal :"); - write_to_stderr(name); - write_to_stderr("\n"); +#ifdef _WIN32 + void signal_handler(int signum) { + const char* name = "UNKNOWN SIGNAL"; + + switch (signum) { + case SIGABRT: name = "SIGABRT"; break; + case SIGFPE: name = "SIGFPE"; break; + case SIGSEGV: name = "SIGSEGV"; break; + case SIGINT: name = "SIGINT"; break; + case SIGTERM: name = "SIGTERM"; break; + } - /* Anything below here is unsafe ! */ + write_to_stderr("\n"); + write_to_stderr(QCoreApplication::applicationName().toLocal8Bit()); + write_to_stderr(" caught signal: "); + write_to_stderr(name); + write_to_stderr("\n"); - switch(signum) - { - case SIGBUS: - case SIGSEGV: - case SIGABRT: - case SIGFPE : print_trace(); - /* Don't catch our own signal */ - install_default_handler(signum); - - kill(getpid(), signum); - return; - case SIGINT : - case SIGTERM: - case SIGPIPE: - default: - /* If the signal_handler is hit before the event loop is started, - * following call will do nothing. So we queue the call. */ QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); - - // Reset signal handler to default (in case this handler is not capable of stopping) - install_default_handler(signum); } -} +#else + struct Signal { + int number; + const char* name; + }; + + const Signal ALL_SIGNALS[] = { + { SIGABRT, "SIGABRT" }, + { SIGBUS, "SIGBUS" }, + { SIGFPE, "SIGFPE" }, + { SIGSEGV, "SIGSEGV" }, + { SIGTERM, "SIGTERM" }, + { SIGHUP, "SIGHUP" }, + { SIGINT, "SIGINT" }, + { SIGPIPE, "SIGPIPE" }, + }; + + void install_default_handler(int signum) { + struct sigaction action {}; + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_DFL; + (void)sigaction(signum, &action, nullptr); + } -} // namespace DefaultSignalHandler -#endif // _WIN32 + void signal_handler(int signum, siginfo_t*, void*) { + const char* name = "UNKNOWN SIGNAL"; -namespace DefaultSignalHandler -{ -void install() -{ -#ifndef _WIN32 - Logger* log = Logger::getInstance("CORE"); - - struct sigaction action{}; - sigemptyset(&action.sa_mask); - action.sa_sigaction = signal_handler; - action.sa_flags |= SA_SIGINFO; - - for (const auto& s : ALL_SIGNALS) - { - if (sigaction(s.number, &action, nullptr)!= 0) - { - Error(log, "Failed to install handler for %s]\n", s.name); + for (const auto& s : ALL_SIGNALS) { + if (s.number == signum) { + name = s.name; + break; + } } + + write_to_stderr("\n"); + write_to_stderr(QCoreApplication::applicationName().toLocal8Bit()); + write_to_stderr(" caught signal: "); + write_to_stderr(name); + write_to_stderr("\n"); + + switch (signum) { + case SIGBUS: + case SIGSEGV: + case SIGABRT: + case SIGFPE: + print_trace(); + install_default_handler(signum); + kill(getpid(), signum); + return; + default: + QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection); + install_default_handler(signum); + } + } +#endif + + void install() { + Logger* log = Logger::getInstance("CORE"); + +#ifdef _WIN32 + signal(SIGABRT, signal_handler); + signal(SIGFPE, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); +#else + struct sigaction action {}; + sigemptyset(&action.sa_mask); + action.sa_sigaction = signal_handler; + action.sa_flags |= SA_SIGINFO; + + for (const auto& s : ALL_SIGNALS) { + if (sigaction(s.number, &action, nullptr) != 0) { + Error(log, "Failed to install handler for %s\n", s.name); + } + } +#endif } -#endif // _WIN32 -} + } // namespace DefaultSignalHandler From 883e22059665608128b18ea602327f36c9ff284b Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 09:13:07 +0200 Subject: [PATCH 08/27] Add missing ENABLE_MDNS --- include/forwarder/MessageForwarder.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/forwarder/MessageForwarder.h b/include/forwarder/MessageForwarder.h index cf97e5627..8fd1d927a 100644 --- a/include/forwarder/MessageForwarder.h +++ b/include/forwarder/MessageForwarder.h @@ -23,7 +23,9 @@ #include // Hyperion includes +#ifdef ENABLE_MDNS #include +#endif #include #include @@ -144,7 +146,9 @@ private slots: QSharedPointer _messageForwarderFlatBufHelper; +#ifdef ENABLE_MDNS QSharedPointer _mdnsBrowser = MdnsBrowser::getInstance(); +#endif }; class MessageForwarderFlatbufferClientsHelper : public QObject From dcd232a020ea5a656422886c7d8ca2f162480b19 Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 09:17:18 +0200 Subject: [PATCH 09/27] Windows console updates --- src/hyperiond/console.h | 23 ++++++++--------------- src/hyperiond/main.cpp | 6 ++---- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/hyperiond/console.h b/src/hyperiond/console.h index e61156aee..0ee2d3cb0 100644 --- a/src/hyperiond/console.h +++ b/src/hyperiond/console.h @@ -1,19 +1,12 @@ #include -// https://stackoverflow.com/a/57241985 -void CreateConsole() +void openConsole(bool isShowConsole) { - if (!AllocConsole()) { - // Add some error handling here. - // You can call GetLastError() to get more info about the error. - return; - } - - // std::cout, std::clog, std::cerr, std::cin - FILE* fDummy; - freopen_s(&fDummy, "CONOUT$", "w", stdout); - freopen_s(&fDummy, "CONOUT$", "w", stderr); - freopen_s(&fDummy, "CONIN$", "r", stdin); - SetConsoleTitle(TEXT("Hyperion")); - SetConsoleOutputCP(CP_UTF8); + if (AttachConsole(ATTACH_PARENT_PROCESS) || (isShowConsole && AllocConsole())) { + FILE* fp; + freopen_s(&fp, "CONOUT$", "w", stdout); + freopen_s(&fp, "CONOUT$", "w", stderr); + SetConsoleTitle(TEXT("Hyperion")); + SetConsoleOutputCP(CP_UTF8); + } } diff --git a/src/hyperiond/main.cpp b/src/hyperiond/main.cpp index 4808a0668..a144a0e36 100644 --- a/src/hyperiond/main.cpp +++ b/src/hyperiond/main.cpp @@ -156,10 +156,8 @@ int main(int argc, char** argv) parser.process(*qApp); #ifdef WIN32 - if (parser.isSet(consoleOption)) - { - CreateConsole(); - } + bool isShowConsole = parser.isSet(consoleOption); + openConsole(isShowConsole); #endif if (parser.isSet(versionOption)) From 7e1355d97130ac83e3617a5d68f9c0236b076533 Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 11:42:41 +0200 Subject: [PATCH 10/27] Clean-up --- src/hyperiond/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hyperiond/CMakeLists.txt b/src/hyperiond/CMakeLists.txt index c07a4ae0c..69d5095bc 100644 --- a/src/hyperiond/CMakeLists.txt +++ b/src/hyperiond/CMakeLists.txt @@ -191,7 +191,6 @@ if(WIN32 AND NOT DEFINED ENV{GITHUB_ACTIONS}) if(TARGET Qt${QT_VERSION_MAJOR}::windeployqt) set(WINDEPLOYQT_PARAMS --verbose 0 --no-compiler-runtime --no-opengl-sw --no-system-d3d-compiler) - get_target_property(QT_QTPATHS_EXECUTABLE Qt${QT_VERSION_MAJOR}::qtpaths IMPORTED_LOCATION) find_file(QT_PATHS "qtpaths.bat" PATHS ${CMAKE_PREFIX_PATH} PATH_SUFFIXES bin) if(QT_PATHS) list(APPEND WINDEPLOYQT_PARAMS "--qtpaths=${QT_PATHS}") From 865e101459ad473b812b200dbcdd14163eac254d Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 12:11:17 +0200 Subject: [PATCH 11/27] Add package build presets in preset template --- doc/development/CMakeUserPresets.json | 37 ++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/doc/development/CMakeUserPresets.json b/doc/development/CMakeUserPresets.json index f2ac433e5..691e24d98 100644 --- a/doc/development/CMakeUserPresets.json +++ b/doc/development/CMakeUserPresets.json @@ -70,7 +70,7 @@ }, "environment": { "LINUX_QT_ROOT_DIR": "$env{HOME}/Qt", - "LINUX_PRE_BUILT_DEPS_ROOT_DIR":"$env{HOME}/hyperion_prebuild_deps" + "LINUX_PRE_BUILT_DEPS_ROOT_DIR": "$env{HOME}/hyperion_prebuild_deps" } }, { @@ -83,8 +83,8 @@ "rhs": "Linux" }, "cacheVariables": { - "USE_PRE_BUILT_DEPS":"ON", - "PRE_BUILT_DEPS_DIR":"$env{LINUX_PRE_BUILT_DEPS_ROOT_DIR}/qt5" + "USE_PRE_BUILT_DEPS": "ON", + "PRE_BUILT_DEPS_DIR": "$env{LINUX_PRE_BUILT_DEPS_ROOT_DIR}/qt5" }, "environment": { } @@ -99,8 +99,8 @@ "rhs": "Linux" }, "cacheVariables": { - "USE_PRE_BUILT_DEPS":"ON", - "PRE_BUILT_DEPS_DIR":"$env{LINUX_PRE_BUILT_DEPS_ROOT_DIR}/qt6" + "USE_PRE_BUILT_DEPS": "ON", + "PRE_BUILT_DEPS_DIR": "$env{LINUX_PRE_BUILT_DEPS_ROOT_DIR}/qt6" }, "environment": { "QTDIR": "$env{LINUX_QT_ROOT_DIR}/6.9.0/gcc_64" @@ -218,6 +218,31 @@ "name": "release-qt6-all-linux", "inherits": [ "linux-release", "qt6-env-linux-wrapper" ] } + ], + "buildPresets": [ + { + "name": "package-qt5-all-windows", + "displayName": "Windows (package - Qt5)", + "configuration": "Release", + "targets": [ "package" ], + "configurePreset": "release-qt5-all-windows", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "package-qt6-all-windows", + "displayName": "Windows (package - Qt6)", + "configuration": "Release", + "targets": [ "package" ], + "configurePreset": "release-qt6-all-windows", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + } ] } - From 093761719fe219f8691183d1da704c20643dc21a Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 12:22:56 +0200 Subject: [PATCH 12/27] Disable DirectX grabber per default --- CHANGELOG.md | 1 + CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e03ca7dc2..a266919eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -147,6 +147,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed: `session-updates` subscription - Deprecated: `serverinfo/subscribe` - Use `subscribe` / `unsubscribe` subcommands instead +- Deprecated: DirectX grabber in favour of the new DXGI DDA grabber ## [2.0.16](https://github.com/hyperion-project/hyperion.ng/releases/tag/2.0.16) - 2024-01 diff --git a/CMakeLists.txt b/CMakeLists.txt index cee0134cd..3f23211c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,7 @@ if("${PLATFORM}" MATCHES "osx") elseif ("${PLATFORM}" MATCHES "windows") if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "i386|i686|amd64|x86_64|AMD64") - set(DEFAULT_DX ON) + set(DEFAULT_DX OFF) endif() elseif ("${PLATFORM}" MATCHES "rpi") set(DEFAULT_DISPMANX ON) From 7516d0b4250285676b4bb4ac0384648bcaa8e097 Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 15:02:52 +0200 Subject: [PATCH 13/27] Correct output position param --- src/hyperion-aml/hyperion-aml.cpp | 2 +- src/hyperion-dispmanx/hyperion-dispmanx.cpp | 2 +- src/hyperion-framebuffer/hyperion-framebuffer.cpp | 2 +- src/hyperion-osx/hyperion-osx.cpp | 2 +- src/hyperion-qt/hyperion-qt.cpp | 2 +- src/hyperion-v4l2/hyperion-v4l2.cpp | 2 +- src/hyperion-x11/hyperion-x11.cpp | 2 +- src/hyperion-xcb/hyperion-xcb.cpp | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hyperion-aml/hyperion-aml.cpp b/src/hyperion-aml/hyperion-aml.cpp index 1fdb3b02e..4a8670c51 100644 --- a/src/hyperion-aml/hyperion-aml.cpp +++ b/src/hyperion-aml/hyperion-aml.cpp @@ -146,7 +146,7 @@ int main(int argc, char ** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); diff --git a/src/hyperion-dispmanx/hyperion-dispmanx.cpp b/src/hyperion-dispmanx/hyperion-dispmanx.cpp index ceb27a046..4901ec85d 100644 --- a/src/hyperion-dispmanx/hyperion-dispmanx.cpp +++ b/src/hyperion-dispmanx/hyperion-dispmanx.cpp @@ -150,7 +150,7 @@ int main(int argc, char ** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); diff --git a/src/hyperion-framebuffer/hyperion-framebuffer.cpp b/src/hyperion-framebuffer/hyperion-framebuffer.cpp index f5dee1d3f..3dfa744b4 100644 --- a/src/hyperion-framebuffer/hyperion-framebuffer.cpp +++ b/src/hyperion-framebuffer/hyperion-framebuffer.cpp @@ -150,7 +150,7 @@ int main(int argc, char ** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); diff --git a/src/hyperion-osx/hyperion-osx.cpp b/src/hyperion-osx/hyperion-osx.cpp index 13a4d1eb9..57ebf7fad 100644 --- a/src/hyperion-osx/hyperion-osx.cpp +++ b/src/hyperion-osx/hyperion-osx.cpp @@ -150,7 +150,7 @@ int main(int argc, char ** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); diff --git a/src/hyperion-qt/hyperion-qt.cpp b/src/hyperion-qt/hyperion-qt.cpp index dad0ed2da..326d3ae11 100644 --- a/src/hyperion-qt/hyperion-qt.cpp +++ b/src/hyperion-qt/hyperion-qt.cpp @@ -150,7 +150,7 @@ int main(int argc, char ** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); diff --git a/src/hyperion-v4l2/hyperion-v4l2.cpp b/src/hyperion-v4l2/hyperion-v4l2.cpp index bd9e110cc..656c692b4 100644 --- a/src/hyperion-v4l2/hyperion-v4l2.cpp +++ b/src/hyperion-v4l2/hyperion-v4l2.cpp @@ -272,7 +272,7 @@ int main(int argc, char** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); diff --git a/src/hyperion-x11/hyperion-x11.cpp b/src/hyperion-x11/hyperion-x11.cpp index b2dd920bf..0a5faf702 100644 --- a/src/hyperion-x11/hyperion-x11.cpp +++ b/src/hyperion-x11/hyperion-x11.cpp @@ -149,7 +149,7 @@ int main(int argc, char ** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); diff --git a/src/hyperion-xcb/hyperion-xcb.cpp b/src/hyperion-xcb/hyperion-xcb.cpp index 731362194..ecc0b4f0f 100644 --- a/src/hyperion-xcb/hyperion-xcb.cpp +++ b/src/hyperion-xcb/hyperion-xcb.cpp @@ -149,7 +149,7 @@ int main(int argc, char ** argv) QHostAddress hostAddress; if (!NetUtils::resolveHostToAddress(log, hostname, hostAddress, port)) { - emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %2").arg(QSTRING_CSTR(hostAddress.toString()))); + emit errorManager.errorOccurred(QString("Address could not be resolved for hostname: %1").arg(QSTRING_CSTR(hostAddress.toString()))); return 1; } Info(log, "Connecting to Hyperion host: %s, port: %u", QSTRING_CSTR(hostAddress.toString()), port); From f3af98b6df84c1f84cf1a706a24edbf4fb60899b Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sun, 1 Jun 2025 15:55:53 +0200 Subject: [PATCH 14/27] Replaced exceptions by signaling errors in main program --- CHANGELOG.md | 1 + libsrc/utils/Logger.cpp | 4 +- src/hyperiond/detectProcess.h | 2 +- src/hyperiond/main.cpp | 358 ++++++++++++++++++---------------- 4 files changed, 190 insertions(+), 175 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a266919eb..f45db06e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -117,6 +117,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use of smart pointers - UI code streamlining - Improved `install_pr` script + - Replaced exceptions by signaling errors in main program and standalone grabbers - Enhanced resilience and error handling - **Build:** diff --git a/libsrc/utils/Logger.cpp b/libsrc/utils/Logger.cpp index 957659465..713352469 100644 --- a/libsrc/utils/Logger.cpp +++ b/libsrc/utils/Logger.cpp @@ -66,14 +66,14 @@ void Logger::deleteInstance(const QString & name, const QString & subName) if (name.isEmpty()) { for (auto *logger : std::as_const(LoggerMap)) { - delete logger; + logger->deleteLater(); } LoggerMap.clear(); } else { - delete LoggerMap.value(name + subName, nullptr); + LoggerMap.value(name + subName, nullptr)->deleteLater(); LoggerMap.remove(name + subName); } } diff --git a/src/hyperiond/detectProcess.h b/src/hyperiond/detectProcess.h index bda96df1b..16e092ebc 100644 --- a/src/hyperiond/detectProcess.h +++ b/src/hyperiond/detectProcess.h @@ -14,7 +14,7 @@ #include #endif -QStringList getProcessIdsByProcessName(const char *processName) +QStringList getProcessIdsByProcessName(const QString& processName) { QStringList listOfPids; diff --git a/src/hyperiond/main.cpp b/src/hyperiond/main.cpp index a144a0e36..0b55cabca 100644 --- a/src/hyperiond/main.cpp +++ b/src/hyperiond/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #if !defined(__APPLE__) && !defined(_WIN32) /* prctl is Linux only */ @@ -37,6 +38,8 @@ #include #include #include +#include + #include #include <../../include/db/AuthTable.h> @@ -54,7 +57,7 @@ using namespace commandline; #define PERM0664 (QFileDevice::ReadOwner | QFileDevice::ReadGroup | QFileDevice::ReadOther | QFileDevice::WriteOwner | QFileDevice::WriteGroup) -QCoreApplication* createApplication(int &argc, char *argv[]) +QCoreApplication* createApplication(int& argc, char* argv[]) { bool isGuiApp = false; bool forceNoGui = false; @@ -74,7 +77,7 @@ QCoreApplication* createApplication(int &argc, char *argv[]) // on osx/windows gui always available #if defined(__APPLE__) || defined(_WIN32) - isGuiApp = true && ! forceNoGui; + isGuiApp = true && !forceNoGui; #else if (!forceNoGui) { @@ -105,24 +108,29 @@ QCoreApplication* createApplication(int &argc, char *argv[]) int main(int argc, char** argv) { + ErrorManager errorManager; + DefaultSignalHandler::install(); + // initialize main logger and set global log level - Logger *log = Logger::getInstance("MAIN"); + Logger* log = Logger::getInstance("MAIN"); Logger::setLogLevel(Logger::WARNING); + // Initialising QCoreApplication + QScopedPointer app(createApplication(argc, argv)); + // check if we are running already an instance // TODO Allow one session per user + QString processName = QCoreApplication::applicationName(); #ifdef _WIN32 - const char* processName = "hyperiond.exe"; -#else - const char* processName = "hyperiond"; + processName.append(".exe"); #endif - // Initialising QCoreApplication - QScopedPointer app(createApplication(argc, argv)); - - bool isGuiApp = !(qobject_cast(app.data()) == nullptr) && QSystemTrayIcon::isSystemTrayAvailable(); + QObject::connect(&errorManager, &ErrorManager::errorOccurred, [&](const QString& error) { + Error(log, "Error occured: %s", QSTRING_CSTR(error)); + QTimer::singleShot(0, [&app]() { app.get()->quit(); }); + }); - DefaultSignalHandler::install(); + bool isGuiApp = !(qobject_cast(app.data()) == nullptr) && QSystemTrayIcon::isSystemTrayAvailable(); // force the locale setlocale(LC_ALL, "C"); @@ -131,27 +139,27 @@ int main(int argc, char** argv) Parser parser("Hyperion Daemon"); parser.addHelpOption(); - BooleanOption & versionOption = parser.add (0x0, "version", "Show version information"); - Option & userDataOption = parser.add