From b852e1894f3f107f4b30adbbb6f01867dddcbd97 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 27 Apr 2024 16:38:22 +0000 Subject: [PATCH] Begin adding GitHub actions and Windows build scripts Adds back Windows support, also adds a GitHub action to build it and more. May not work 100% yet, but it's a good start. --- .github/workflows/main.yml | 256 +++++++++++++++++++++++ .gitignore | 5 +- .gitmodules | 2 +- CMakeLists.txt | 37 ++-- external/CMakeLists.txt | 18 +- external/libcotp | 2 +- launcher/CMakeLists.txt | 44 +++- launcher/include/launchercore.h | 2 + launcher/src/launchercore.cpp | 9 + launcher/src/main.cpp | 20 +- launcher/src/profilemanager.cpp | 6 +- launcher/ui/Pages/NewsPage.qml | 23 +- launcher/ui/Settings/ProfileSettings.qml | 5 + launcher/ui/Settings/SettingsPage.qml | 1 + resources/16-astra.png | Bin 0 -> 689 bytes resources/256-astra.png | Bin 0 -> 17294 bytes resources/32-astra.png | Bin 0 -> 1540 bytes resources/48-astra.png | Bin 0 -> 2483 bytes resources/zone.xiv.astra.png | Bin 0 -> 689 bytes scripts/windows-build.ps1 | 22 ++ scripts/windows-setup.ps1 | 145 +++++++++++++ 21 files changed, 559 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/main.yml create mode 100644 resources/16-astra.png create mode 100644 resources/256-astra.png create mode 100644 resources/32-astra.png create mode 100644 resources/48-astra.png create mode 100644 resources/zone.xiv.astra.png create mode 100644 scripts/windows-build.ps1 create mode 100644 scripts/windows-setup.ps1 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..2d1a4be --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,256 @@ +name: Main + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CMAKE_BUILD_PARALLEL_LEVEL: 2 + MAKEFLAGS: '-j 2' + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [windows-latest, ubuntu-latest] + build_type: [Release] + c_compiler: [gcc, cl] + include: + - os: windows-latest + c_compiler: cl + cpp_compiler: cl + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + exclude: + - os: windows-latest + c_compiler: gcc + - os: ubuntu-latest + c_compiler: cl + + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + version: "6.6.*" + cache: true + modules: 'qtshadertools' + + - name: Set reusable strings + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + echo "prefix-dir=${{ github.workspace }}/prefix" >> "$GITHUB_OUTPUT" + + - name: Setup Linux dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install \ + gettext \ + gamemode-dev \ + libunshield-dev \ + + - name: Cache Prefix + id: cache-prefix-restore + uses: actions/cache/restore@v4 + with: + path: ${{ steps.strings.outputs.prefix-dir }} + key: ${{ runner.os }}-prefix + + - name: Setup Windows dependencies + if: (runner.os == 'Windows') && (steps.cache-prefix-restore.outputs.cache-hit != 'true') + shell: powershell + run: | + $ProgressPreference = 'SilentlyContinue' + + Invoke-WebRequest https://xiv.zone/distrib/dependencies/gettext.zip -OutFile gettext.zip + unzip gettext.zip -d ${{ steps.strings.outputs.prefix-dir }} + + Invoke-WebRequest https://xiv.zone/distrib/dependencies/iconv.zip -OutFile iconv.zip + unzip iconv.zip -d ${{ steps.strings.outputs.prefix-dir }} + + Invoke-WebRequest https://xiv.zone/distrib/dependencies/gcrypt.zip -OutFile gcrypt.zip + unzip gcrypt.zip -d ${{ steps.strings.outputs.prefix-dir }} + + Invoke-WebRequest https://xiv.zone/distrib/dependencies/gpg-error.zip -OutFile gpg-error.zip + unzip gpg-error.zip -d ${{ steps.strings.outputs.prefix-dir }} + + Invoke-WebRequest https://xiv.zone/distrib/dependencies/icoutils.zip -OutFile icoutils.zip + unzip icoutils.zip -d ${{ steps.strings.outputs.prefix-dir }} + + Invoke-WebRequest https://xiv.zone/distrib/dependencies/libwinpthread.zip -OutFile libwinpthread.zip + unzip libwinpthread.zip -d ${{ steps.strings.outputs.prefix-dir }}/bin + + Invoke-WebRequest https://xiv.zone/distrib/dependencies/libcrypto.zip -OutFile libcrypto.zip + unzip libcrypto.zip -d ${{ steps.strings.outputs.prefix-dir }}/bin + + - name: Build zlib + if: (runner.os == 'Windows') && (steps.cache-prefix-restore.outputs.cache-hit != 'true') + run: | + git clone https://github.com/madler/zlib.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-zlib -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S zlib -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-zlib --config ${{ matrix.build_type }} --target install + + - name: Build Extra CMake Modules + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://invent.kde.org/frameworks/extra-cmake-modules.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-ECM -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S extra-cmake-modules -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-ECM --config ${{ matrix.build_type }} --target install + cmake --install ${{ steps.strings.outputs.build-output-dir }}-ECM --config ${{ matrix.build_type }} + + - name: Configure KI18n + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://invent.kde.org/frameworks/ki18n.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-ki18n -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S ki18n -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + + - name: Windows KI18n workaround + if: (runner.os == 'Windows') && (steps.cache-prefix-restore.outputs.cache-hit != 'true') + run: | + (Get-Content -ReadCount 0 ${{ steps.strings.outputs.build-output-dir }}-ki18n/cmake/build-pofiles.cmake) -replace 'FATAL_ERROR', 'WARNING' | Set-Content ${{ steps.strings.outputs.build-output-dir }}-ki18n/cmake/build-pofiles.cmake + + - name: Build KI18n + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + cmake --build ${{ steps.strings.outputs.build-output-dir }}-ki18n --config ${{ matrix.build_type }} --target install + + - name: Build KCoreAddons + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://invent.kde.org/frameworks/kcoreaddons.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-kca -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S kcoreaddons -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-kca --config ${{ matrix.build_type }} --target install + + - name: Build KConfig + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://invent.kde.org/frameworks/kconfig.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-kconfig -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S kconfig -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-kconfig --config ${{ matrix.build_type }} --target install + + - name: Build KArchive + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://invent.kde.org/frameworks/karchive.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-karchive -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S karchive -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF -DWITH_BZIP2=OFF -DWITH_LIBLZMA=OFF -DWITH_LIBZSTD=OFF # TODO: enable bzip which we need later + cmake --build ${{ steps.strings.outputs.build-output-dir }}-karchive --config ${{ matrix.build_type }} --target install + + - name: Build Kirigami + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://invent.kde.org/frameworks/kirigami.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-kirigami -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S kirigami -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-kirigami --config ${{ matrix.build_type }} --target install + + - name: Build Kirigami Add-ons + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://invent.kde.org/libraries/kirigami-addons.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-kirigami-addons -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S kirigami-addons -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-kirigami-addons --config ${{ matrix.build_type }} --target install + + - name: Build Breeze Icons + if: (runner.os == 'Windows') && (steps.cache-prefix-restore.outputs.cache-hit != 'true') + continue-on-error: true + run: | + git clone https://invent.kde.org/frameworks/breeze-icons.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-breeze-icons -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S breeze-icons -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DICONS_LIBRARY=ON -DSKIP_INSTALL_ICONS=ON + cmake --build ${{ steps.strings.outputs.build-output-dir }}-breeze-icons --config ${{ matrix.build_type }} --target install + cmake --build ${{ steps.strings.outputs.build-output-dir }}-breeze-icons --config ${{ matrix.build_type }} --target install + + - name: Build Corrosion + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://github.com/corrosion-rs/corrosion.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-corrosion -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S corrosion -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DCORROSION_BUILD_TESTS=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-corrosion --config ${{ matrix.build_type }} --target install + + - name: Build QCoro + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://github.com/danvratil/qcoro.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-qcoro -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S qcoro -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF -DQCORO_WITH_QTWEBSOCKETS=OFF -DQCORO_BUILD_EXAMPLES=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-qcoro --config ${{ matrix.build_type }} --target install + + - name: Build QtKeychain + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://github.com/redstrate/qtkeychain.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-qtkeychain -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S qtkeychain -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF -DBUILD_WITH_QT6=ON -DQTKEYCHAIN_TARGET_NAME=keychain + cmake --build ${{ steps.strings.outputs.build-output-dir }}-qtkeychain --config ${{ matrix.build_type }} --target install + + - name: Build unshield + if: steps.cache-prefix-restore.outputs.cache-hit != 'true' + run: | + git clone https://github.com/twogood/unshield.git + cmake -B ${{ steps.strings.outputs.build-output-dir }}-unshield -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -S unshield -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.prefix-dir }} -DBUILD_TESTING=OFF + cmake --build ${{ steps.strings.outputs.build-output-dir }}-unshield --config ${{ matrix.build_type }} --target install + + - name: Save Prefix + id: cache-prefix-save + uses: actions/cache/save@v4 + with: + path: ${{ steps.strings.outputs.prefix-dir }} + key: ${{ steps.cache-prefix-restore.outputs.cache-primary-key }} + + - name: Configure + run: > + cmake -B ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DCMAKE_PREFIX_PATH=${{ steps.strings.outputs.prefix-dir }} + -DCMAKE_INSTALL_PREFIX=${{ steps.strings.outputs.build-output-dir }}/bin + -S ${{ github.workspace }} + + - name: Build + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} --target install + + - name: Copy required DLLs + if: runner.os == 'Windows' + run: | + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/intl-8.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/iconv.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/zlib.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/q6keychain.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KF6I18n.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KF6ConfigGui.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KF6CoreAddons.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KF6Archive.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/unshield.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/libgcrypt-20.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KF6ConfigCore.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/libgpg-error6-0.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/zlib.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/libwinpthread-1.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/libcrypto-1_1-x64.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KF6BreezeIcons.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/Kirigami.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KirigamiDelegates.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/bin/KirigamiPlatform.dll -Destination ${{ steps.strings.outputs.build-output-dir }}/bin/bin + + Copy-Item -Path ${{ steps.strings.outputs.prefix-dir }}/lib/qml/* -Destination ${{ steps.strings.outputs.build-output-dir }}/qml/ -Recurse + + - name: Remove extra files + if: runner.os == 'Windows' + run: | + Remove-Item -Path ${{ steps.strings.outputs.build-output-dir }}/bin/bin/opengl32sw.dll + + - name: Archive artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ runner.os }}-package + path: ${{ steps.strings.outputs.build-output-dir }}/bin \ No newline at end of file diff --git a/.gitignore b/.gitignore index e06e316..54f53e1 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,7 @@ .directory *.flatpak export/ -.clang-format \ No newline at end of file +.clang-format +# Windows +local/ +prefix/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 05dc619..d9ed198 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "external/libcotp"] path = external/libcotp - url = https://github.com/paolostivanin/libcotp.git + url = https://github.com/redstrate/libcotp.git [submodule "external/libphysis"] path = external/libphysis url = ../libphysis diff --git a/CMakeLists.txt b/CMakeLists.txt index b5d30f2..e1ae3ac 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,9 +6,12 @@ project(Astra VERSION 0.6.0 LANGUAGES CXX) # build options used for distributors option(BUILD_FLATPAK "Build for Flatpak." OFF) +option(BUILD_WEBVIEW "Build support for the integrated web browser. Only used on the Steam Deck." OFF) # options for features you may want or need -option(ENABLE_GAMEMODE "Build with Feral GameMode support, requires the daemon to be installed." ON) +if (NOT WIN32 AND NOT APPLE) + option(ENABLE_GAMEMODE "Build with Feral GameMode support, requires the daemon to be installed." ON) +endif() set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -27,6 +30,7 @@ include(KDEGitCommitHooks) include(KDEClangFormat) include(ECMAddTests) include(ECMQtDeclareLoggingCategory) +include(ECMAddAppIcon) ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX ASTRA @@ -38,22 +42,29 @@ find_package(Qt6 ${QT_MIN_VERSION} REQUIRED COMPONENTS Widgets Network QuickControls2 - WebView Concurrent Test) +if (BUILD_WEBVIEW) + find_package(Qt6WebView ${QT_MIN_VERSION} REQUIRED) +endif () find_package(KF6 ${KF_MIN_VERSION} REQUIRED COMPONENTS Kirigami I18n Config CoreAddons Archive) -find_package(PkgConfig REQUIRED) find_package(QCoro6 REQUIRED COMPONENTS Core Network Qml) qcoro_enable_coroutines() qt_policy(SET QTP0001 NEW) if (ENABLE_GAMEMODE) + find_package(PkgConfig REQUIRED) pkg_search_module(GAMEMODE REQUIRED gamemode) endif () find_package(Qt6Keychain REQUIRED) +# TODO: we should really do this on all platforms anyway +if (WIN32) + find_package(KF6BreezeIcons REQUIRED) +endif () + add_subdirectory(external) add_subdirectory(launcher) @@ -61,18 +72,20 @@ if (BUILD_TESTING) add_subdirectory(autotests) endif() -install(FILES zone.xiv.astra.desktop DESTINATION ${KDE_INSTALL_APPDIR}) -install(FILES zone.xiv.astra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) -install(FILES zone.xiv.astra.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps) +if (NOT WIN32) + install(FILES zone.xiv.astra.desktop DESTINATION ${KDE_INSTALL_APPDIR}) + install(FILES zone.xiv.astra.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) + install(FILES zone.xiv.astra.svg DESTINATION ${KDE_INSTALL_FULL_ICONDIR}/hicolor/scalable/apps) + + ecm_qt_install_logging_categories( + EXPORT ASTRA + FILE astra.categories + SORT DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} + ) +endif() feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) -ecm_qt_install_logging_categories( - EXPORT ASTRA - FILE astra.categories - SORT DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR} -) - file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES src/*.cpp src/*.h) kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES}) diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index bcb8793..3ecc9fe 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -16,12 +16,20 @@ corrosion_import_crate(MANIFEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libphysis/Cargo FEATURES game_install visual_data) # FIXME: split visual_data? we only need texture decompression add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libphysis/logger EXCLUDE_FROM_ALL) -find_package(PkgConfig REQUIRED) -pkg_check_modules(UNSHIELD REQUIRED IMPORTED_TARGET libunshield) - target_include_directories(physis INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/libphysis/target/public) -target_link_libraries(physis INTERFACE ${UNSHIELD_LIBRARIES} z) -target_link_directories(physis INTERFACE ${UNSHIELD_LIBRARY_DIRS}) + +# We should use the CMake module everywhere once distros update their packages +if (WIN32) + # FIXME: unshield should include zlib in their upstream cmake + find_package(ZLIB REQUIRED) + find_package(unshield REQUIRED) + target_link_libraries(physis INTERFACE unshield::libunshield) +else() + find_package(PkgConfig REQUIRED) + pkg_check_modules(UNSHIELD REQUIRED IMPORTED_TARGET libunshield) + target_link_directories(physis INTERFACE ${UNSHIELD_LIBRARY_DIRS}) + target_link_libraries(physis INTERFACE ${UNSHIELD_LIBRARIES}) +endif() set(KDSingleApplication_QT6 ON) set(KDSingleApplication_STATIC ON) diff --git a/external/libcotp b/external/libcotp index 60461cd..9136e0a 160000 --- a/external/libcotp +++ b/external/libcotp @@ -1 +1 @@ -Subproject commit 60461cd28c297eed476ff93d9b1123c3855c7053 +Subproject commit 9136e0a94f1b4d9afe2d8aa79bfdaf1d1699f265 diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index ae3c9d7..b45195d 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -138,7 +138,6 @@ target_link_libraries(astra PRIVATE Qt6::Widgets Qt6::Quick Qt6::QuickControls2 - Qt6::WebView Qt6::Concurrent KF6::Kirigami KF6::I18n @@ -149,7 +148,22 @@ target_link_libraries(astra PRIVATE QCoro::Core QCoro::Network QCoro::Qml) -target_compile_options(astra PRIVATE -fexceptions) +if (BUILD_WEBVIEW) + target_link_libraries(astra PRIVATE + Qt6::WebView + ) + target_compile_definitions(astra PRIVATE HAVE_WEBVIEW) +endif () + +if (WIN32) + target_link_libraries(astra PRIVATE + KF6::BreezeIcons + ) +endif () + +if (NOT MSVC) + target_compile_options(astra PRIVATE -fexceptions) +endif () if (BUILD_FLATPAK) target_compile_definitions(astra PRIVATE FLATPAK) @@ -160,4 +174,28 @@ if (ENABLE_GAMEMODE) target_compile_definitions(astra PRIVATE ENABLE_GAMEMODE) endif () -install(TARGETS astra ${KF6_INSTALL_TARGETS_DEFAULT_ARGS}) \ No newline at end of file +if (WIN32) + set_target_properties(astra PROPERTIES + WIN32_EXECUTABLE TRUE + OUTPUT_NAME "Astra") +endif () + +install(TARGETS astra ${KF6_INSTALL_TARGETS_DEFAULT_ARGS}) + +ecm_add_app_icon(astra + ICONS + ${CMAKE_SOURCE_DIR}/zone.xiv.astra.svg + ${CMAKE_SOURCE_DIR}/resources/16-astra.png + ${CMAKE_SOURCE_DIR}/resources/32-astra.png + ${CMAKE_SOURCE_DIR}/resources/48-astra.png + ${CMAKE_SOURCE_DIR}/resources/256-astra.png +) + +qt_finalize_target(astra) + +qt_generate_deploy_qml_app_script( + TARGET astra + OUTPUT_SCRIPT deploy_script + NO_UNSUPPORTED_PLATFORM_ERROR +) +install(SCRIPT ${deploy_script}) \ No newline at end of file diff --git a/launcher/include/launchercore.h b/launcher/include/launchercore.h index f55d53b..cea0b8f 100755 --- a/launcher/include/launchercore.h +++ b/launcher/include/launchercore.h @@ -62,6 +62,7 @@ class LauncherCore : public QObject Q_PROPERTY(bool loadingFinished READ isLoadingFinished NOTIFY loadingFinished) Q_PROPERTY(bool isSteam READ isSteam CONSTANT) Q_PROPERTY(bool isSteamDeck READ isSteamDeck CONSTANT) + Q_PROPERTY(bool isWindows READ isWindows CONSTANT) Q_PROPERTY(LauncherSettings *settings READ settings CONSTANT) Q_PROPERTY(ProfileManager *profileManager READ profileManager CONSTANT) Q_PROPERTY(AccountManager *accountManager READ accountManager CONSTANT) @@ -110,6 +111,7 @@ public: [[nodiscard]] bool isLoadingFinished() const; [[nodiscard]] bool isSteam() const; [[nodiscard]] bool isSteamDeck() const; + [[nodiscard]] bool isWindows() const; [[nodiscard]] Q_INVOKABLE bool isPatching() const; [[nodiscard]] QNetworkAccessManager *mgr(); diff --git a/launcher/src/launchercore.cpp b/launcher/src/launchercore.cpp index de2a340..0213344 100755 --- a/launcher/src/launchercore.cpp +++ b/launcher/src/launchercore.cpp @@ -302,6 +302,15 @@ bool LauncherCore::isSteamDeck() const } } +bool LauncherCore::isWindows() const +{ +#if defined(Q_OS_WIN) + return true; +#else + return false; +#endif +} + bool LauncherCore::isPatching() const { return m_isPatching; diff --git a/launcher/src/main.cpp b/launcher/src/main.cpp index 079e085..8945646 100755 --- a/launcher/src/main.cpp +++ b/launcher/src/main.cpp @@ -8,10 +8,13 @@ #include #include #include -#include #include #include +#ifdef HAVE_WEBVIEW +#include +#endif + #include "astra-version.h" #include "compatibilitytoolinstaller.h" #include "gameinstaller.h" @@ -20,18 +23,29 @@ #include "physis_logger.h" #include "sapphirelogin.h" +#ifdef Q_OS_WIN +#include +#endif + using namespace Qt::StringLiterals; int main(int argc, char *argv[]) { +#ifdef HAVE_WEBVIEW QtWebView::initialize(); +#endif + +#ifdef Q_OS_WIN + BreezeIcons::initIcons(); + QIcon::setThemeName(QStringLiteral("Breeze")); +#endif if (qEnvironmentVariable("SteamDeck") == QStringLiteral("1")) { qputenv("QT_SCALE_FACTOR", "1.25"); qputenv("QT_QUICK_CONTROLS_MOBILE", "1"); } - QApplication app(argc, argv); + QGuiApplication app(argc, argv); KDSingleApplication singleApplication; if (!singleApplication.isPrimaryInstance()) { @@ -124,6 +138,7 @@ int main(int argc, char *argv[]) } } +#if defined(Q_OS_LINUX) // Default to org.kde.desktop style unless the user forces another style if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) { if (isSteamDeck) { @@ -132,6 +147,7 @@ int main(int argc, char *argv[]) QQuickStyle::setStyle(QStringLiteral("org.kde.desktop")); } } +#endif QCoro::Qml::registerTypes(); diff --git a/launcher/src/profilemanager.cpp b/launcher/src/profilemanager.cpp index 3b0ebab..adda7de 100644 --- a/launcher/src/profilemanager.cpp +++ b/launcher/src/profilemanager.cpp @@ -67,13 +67,13 @@ void ProfileManager::deleteProfile(Profile *profile) QString ProfileManager::getDefaultGamePath(const QString &uuid) { #if defined(Q_OS_WIN) - return "C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn"; + return QStringLiteral("C:\\Program Files (x86)\\SquareEnix\\FINAL FANTASY XIV - A Realm Reborn"); #endif #if defined(Q_OS_MAC) return QDir::homePath() + - "/Library/Application Support/FINAL FANTASY XIV ONLINE/Bottles/published_Final_Fantasy/drive_c/Program " - "Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn"; + QStringLiteral("/Library/Application Support/FINAL FANTASY XIV ONLINE/Bottles/published_Final_Fantasy/drive_c/Program " + "Files (x86)/SquareEnix/FINAL FANTASY XIV - A Realm Reborn"); #endif #if defined(Q_OS_LINUX) diff --git a/launcher/ui/Pages/NewsPage.qml b/launcher/ui/Pages/NewsPage.qml index a574b03..c7bb078 100644 --- a/launcher/ui/Pages/NewsPage.qml +++ b/launcher/ui/Pages/NewsPage.qml @@ -6,7 +6,7 @@ pragma ComponentBehavior: Bound import QtQuick import QtQuick.Controls as QQC2 import QtQuick.Layouts -import Qt5Compat.GraphicalEffects +import QtQuick.Effects import org.kde.kirigami as Kirigami import org.kde.kirigamiaddons.formcard as FormCard @@ -101,15 +101,18 @@ QQC2.Control { } layer.enabled: !(bannerImage.width < layout.maximumWidth) - layer.effect: OpacityMask { - maskSource: Item { - width: bannerImage.width - height: bannerImage.height - Rectangle { - anchors.centerIn: parent - width: bannerImage.width - height: bannerImage.height - radius: Kirigami.Units.smallSpacing + layer.effect: MultiEffect { + id: root + + maskEnabled: true + maskSpreadAtMax: 1 + maskSpreadAtMin: 1 + maskThresholdMin: 0.5 + maskSource: ShaderEffectSource { + sourceItem: Rectangle { + width: root.width + height: root.height + radius: Kirigami.Units.mediumSpacing } } } diff --git a/launcher/ui/Settings/ProfileSettings.qml b/launcher/ui/Settings/ProfileSettings.qml index 597bf7c..1f4b983 100644 --- a/launcher/ui/Settings/ProfileSettings.qml +++ b/launcher/ui/Settings/ProfileSettings.qml @@ -90,6 +90,8 @@ FormCard.FormCardPage { } FormCard.FormCard { + visible: !LauncherCore.isWindows + Layout.fillWidth: true FormCard.FormComboBoxDelegate { @@ -139,9 +141,12 @@ FormCard.FormCardPage { FormCard.FormHeader { title: i18n("Tools") + visible: !LauncherCore.isWindows } FormCard.FormCard { + visible: !LauncherCore.isWindows + Layout.fillWidth: true FormCard.FormCheckDelegate { diff --git a/launcher/ui/Settings/SettingsPage.qml b/launcher/ui/Settings/SettingsPage.qml index 74ef56a..7ca1591 100644 --- a/launcher/ui/Settings/SettingsPage.qml +++ b/launcher/ui/Settings/SettingsPage.qml @@ -51,6 +51,7 @@ KirigamiSettings.CategorizedSettings { text: i18n("Compatibility Tool") icon.name: "system-run" page: Qt.resolvedUrl("/qt/qml/zone/xiv/astra/ui/Settings/CompatibilityToolSetup.qml") + visible: !LauncherCore.isWindows }, KirigamiSettings.SettingAction { actionName: "devtool" diff --git a/resources/16-astra.png b/resources/16-astra.png new file mode 100644 index 0000000000000000000000000000000000000000..dabb7472ce4052462b2f4d84f467f5d9102c21f6 GIT binary patch literal 689 zcmV;i0#5yjP)<8YCGOeO$VDFetG)6hvfD;i+2$gtv|!|cxNG&}3gJe_t^S&8s}d|!S)p8xZ{jEJz6 za9g6+3X;j>cEd2n6-DU)z&0fqW49P<9c8Qo0NkZ>K@cwae7-Yox4Rm^z((!?V`5!< z{RrQ+qd$@{U$3O}VE_OTfruc>azi$oy{u{4Q6j=!z)M7!06dSIYj1oW=w5hruqAQd z<7p}}LI3a_AD5;-%`8lstIlL^EM`Ze(Zae4rA$ad z@1DcW*IXP|<>p->&da&J#h1UNQ`v&(_e4%479xQ_U@Vu*T^9u5<+@iG7q{(f>#o1! zzz*BIQ_CHwav6FaVy(B4K+0*^xGG6f!m_Ms+qM@0{H-v`n9#g8{5G`9-^qns@b2?M zpVDBfwzHH_p2WVYeZxe~#)-=nf{nsG@wm{*?dAahnOO~{nlGf|>I?I`)?W!O3vM&k z)^x6}&k7e|{mg+(g89@m((f}xUTId(p~ zI+9MO1yxm#1%ttdn+l3GPEh})gOc>ynzrApCX0hZMDvQG^!WY$n>^1q>bibN6vYb_ z1vFDUY0MP&JHU@2qWRLLBuVcq%L0I)<2cVMO;GV8t&J?pM*w`_IIcPr3dR3h@UQ#< XN)`;)rEef;00000NkvXXu0mjf%-}r! literal 0 HcmV?d00001 diff --git a/resources/256-astra.png b/resources/256-astra.png new file mode 100644 index 0000000000000000000000000000000000000000..a5b1033fa6c50475179d1e8dfa71c02c45e5b75b GIT binary patch literal 17294 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 qc13gz literal 0 HcmV?d00001 diff --git a/resources/48-astra.png b/resources/48-astra.png new file mode 100644 index 0000000000000000000000000000000000000000..3afac01245111a4381a194e2f3795b7d55330971 GIT binary patch literal 2483 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 XN)`;)rEef;00000NkvXXu0mjf%-}r! literal 0 HcmV?d00001 diff --git a/scripts/windows-build.ps1 b/scripts/windows-build.ps1 new file mode 100644 index 0000000..7b7adfb --- /dev/null +++ b/scripts/windows-build.ps1 @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2024 NotNite +# SPDX-License-Identifier: CC0-1.0 + +$ErrorActionPreference = "Stop" +$PSNativeCommandUseErrorActionPreference = $true + +$LocalDir = "./local" +$BuildDir = "./build" +$PrefixDir = (Get-Location).Path + "/prefix" + +cmake -B "$BuildDir" "-DCMAKE_PREFIX_PATH=$PrefixDir" "-DCMAKE_CXX_COMPILER=cl" "-DCMAKE_C_COMPILER=cl" "-DCMAKE_BUILD_TYPE=Debug" "-S" . "-DCMAKE_INSTALL_PREFIX=$BuildDir" +cmake --build "$BuildDir" --config Debug --target install + +Copy-Item -Path "$PrefixDir/bin/KF6ItemViews.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$PrefixDir/bin/KF6IconWidgets.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$PrefixDir/bin/KF6GuiAddons.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$PrefixDir/bin/KF6ColorScheme.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$PrefixDir/bin/intl-8.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$PrefixDir/bin/KF6IconThemes.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$PrefixDir/bin/iconv.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$PrefixDir/bin/zlibd.dll" -Destination "$BuildDir/bin" +Copy-Item -Path "$env:QTDIR/bin/Qt6PrintSupportd.dll" -Destination "$BuildDir/bin" diff --git a/scripts/windows-setup.ps1 b/scripts/windows-setup.ps1 new file mode 100644 index 0000000..6620ffd --- /dev/null +++ b/scripts/windows-setup.ps1 @@ -0,0 +1,145 @@ +# SPDX-FileCopyrightText: 2024 NotNite +# SPDX-License-Identifier: CC0-1.0 + +$ErrorActionPreference = "Stop" +$PSNativeCommandUseErrorActionPreference = $true + +$LocalDir = "./local" +$BuildDir = "$LocalDir/build" +$PrefixDir = (Get-Location).Path + "/prefix" + +$NumCores = [Environment]::ProcessorCount + +function Configure($Name, $ExtraArgs = "") { + $Command = "cmake -B $BuildDir-$Name -DCMAKE_PREFIX_PATH=$PrefixDir -DCMAKE_CXX_COMPILER=cl -DCMAKE_C_COMPILER=cl -DCMAKE_BUILD_TYPE=Debug -S $LocalDir/$Name -DCMAKE_INSTALL_PREFIX=$PrefixDir $ExtraArgs" + Write-Output "Running $Command" + Invoke-Expression $Command + if ($LASTEXITCODE -ne 0) { + throw "Failed to configure $Name" + } +} + +function Clone($Name, $Url) { + if (Test-Path "$LocalDir/$Name") { + Write-Information "Skipping clone of $Name because it's source directory already exists" + } else { + git clone --depth=1 $Url "$LocalDir/$Name" + + if ($LASTEXITCODE -ne 0) { + throw "Failed to clone $Name from $Url" + } + } +} + +function CheckCompileResult($Name) { + if ($LASTEXITCODE -ne 0) { + throw "Failed to build $Name!" + } +} + +if (!(Test-Path $LocalDir)) { + New-Item -ItemType Directory -Path $LocalDir +} + +# Setup Windows dependencies +Invoke-WebRequest https://xiv.zone/distrib/dependencies/gettext.zip -OutFile "$LocalDir/gettext.zip" +Expand-Archive -Path "$LocalDir/gettext.zip" -DestinationPath $PrefixDir -Force + +Invoke-WebRequest https://xiv.zone/distrib/dependencies/iconv.zip -OutFile "$LocalDir/iconv.zip" +Expand-Archive -Path "$LocalDir/iconv.zip" -DestinationPath $PrefixDir -Force + +Invoke-WebRequest https://xiv.zone/distrib/dependencies/icoutils.zip -OutFile "$LocalDir/icoutils.zip" +Expand-Archive -Path "$LocalDir/icoutils.zip" -DestinationPath $PrefixDir -Force + +Invoke-WebRequest https://xiv.zone/distrib/dependencies/gcrypt.zip -OutFile "$LocalDir/gcrypt.zip" +Expand-Archive -Path "$LocalDir/gcrypt.zip" -DestinationPath $PrefixDir -Force + +Invoke-WebRequest https://xiv.zone/distrib/dependencies/gpg-error.zip -OutFile "$LocalDir/gpg-error.zip" +Expand-Archive -Path "$LocalDir/gpg-error.zip" -DestinationPath $PrefixDir -Force + +Invoke-WebRequest https://xiv.zone/distrib/dependencies/libwinpthread.zip -OutFile "$LocalDir/libwinpthread.zip" +Expand-Archive -Path "$LocalDir/libwinpthread.zip" -DestinationPath $PrefixDir -Force + +# Build zlib +Clone "zlib" "https://github.com/madler/zlib.git" +Configure "zlib" "-DBUILD_TESTING=OFF" +cmake --build "$BuildDir-zlib" --config Debug --target install +CheckCompileResult "zlib" + +# Build Extra CMake Modules +Clone "extra-cmake-modules" "https://invent.kde.org/frameworks/extra-cmake-modules.git" +Configure "extra-cmake-modules" "-DBUILD_TESTING=OFF" +cmake --build "$BuildDir-extra-cmake-modules" --config Debug --target install --parallel $NumCores +cmake --install "$BuildDir-extra-cmake-modules" --config Debug +CheckCompileResult "extra-cmake-modules" + +# Build KI18n +Clone "ki18n" "https://invent.kde.org/frameworks/ki18n.git" +# Workaround for Windows +Configure "ki18n" "-DBUILD_TESTING=OFF" + +(Get-Content -ReadCount 0 "$BuildDir-ki18n/cmake/build-pofiles.cmake") -replace 'FATAL_ERROR', 'WARNING' | Set-Content "$BuildDir-ki18n/cmake/build-pofiles.cmake" +cmake --build "$BuildDir-ki18n" --config Debug --target install --parallel $NumCores +CheckCompileResult "ki18n" + +# Build KCoreAddons +Clone "kcoreaddons" "https://invent.kde.org/frameworks/kcoreaddons.git" +Configure "kcoreaddons" "-DBUILD_TESTING=OFF" +cmake --build "$BuildDir-kcoreaddons" --config Debug --target install --parallel $NumCores +CheckCompileResult "kcoreaddons" + +# Build KConfig +Clone "kconfig" "https://invent.kde.org/frameworks/kconfig.git" +Configure "kconfig" "-DBUILD_TESTING=OFF" +cmake --build "$BuildDir-kconfig" --config Debug --target install --parallel $NumCores +CheckCompileResult "kconfig" + +# Build KArchive +Clone "karchive" "https://invent.kde.org/frameworks/karchive.git" +Configure "karchive" "-DBUILD_TESTING=OFF -DWITH_BZIP2=OFF -DWITH_LIBLZMA=OFF -DWITH_LIBZSTD=OFF" +cmake --build "$BuildDir-karchive" --config Debug --target install --parallel $NumCores +CheckCompileResult "karchive" + +# Build Kirigami +Clone "kirigami" "https://invent.kde.org/frameworks/kirigami.git" +Configure "kirigami" "-DBUILD_TESTING=OFF" +cmake --build "$BuildDir-kirigami" --config Debug --target install --parallel $NumCores +CheckCompileResult "kirigami" + +# Build Kirigami Add-ons +Clone "kirigami-addons" "https://invent.kde.org/libraries/kirigami-addons.git" +Configure "kirigami-addons" "-DBUILD_TESTING=OFF" +cmake --build "$BuildDir-kirigami-addons" --config Debug --target install --parallel $NumCores +CheckCompileResult "kirigami-addons" + +# Build Corrosion +Clone "corrosion" "https://github.com/corrosion-rs/corrosion.git" +Configure "corrosion" "-DCORROSION_BUILD_TESTS=OFF" +cmake --build "$BuildDir-corrosion" --config Debug --target install --parallel $NumCores +CheckCompileResult "corrosion" + +# Build QCoro +Clone "qcoro" "https://github.com/danvratil/qcoro.git" +Configure "qcoro" "-DBUILD_TESTING=OFF -DQCORO_WITH_QTWEBSOCKETS=OFF -DQCORO_BUILD_EXAMPLES=OFF" +cmake --build "$BuildDir-qcoro" --config Debug --target install --parallel $NumCores +CheckCompileResult "qcoro" + +# Build QtKeychain +Clone "qtkeychain" "https://github.com/redstrate/qtkeychain.git" +Configure "qtkeychain" "-DBUILD_TESTING=OFF -DBUILD_WITH_QT6=ON" +cmake --build "$BuildDir-qtkeychain" --config Debug --target install --parallel $NumCores +CheckCompileResult "qtkeychain" + +# Build unshield +Clone "unshield" "https://github.com/twogood/unshield.git" +Configure "unshield" "-DBUILD_TESTING=OFF" +cmake --build "$BuildDir-unshield" --config Debug --target install --parallel $NumCores +CheckCompileResult "unshield" + +# Build breeze icons +Clone "breeze-icons" "https://invent.kde.org/frameworks/breeze-icons.git" +Configure "breeze-icons" "-DICONS_LIBRARY=ON -DSKIP_INSTALL_ICONS=ON" +# Building it twice is intentional, the first time will always fail +cmake --build "$BuildDir-breeze-icons" --config Debug --target install --parallel $NumCores +cmake --build "$BuildDir-breeze-icons" --config Debug --target install --parallel $NumCores +CheckCompileResult "breeze-icons" \ No newline at end of file