diff --git a/.github/actions/package/linux/action.yml b/.github/actions/package/linux/action.yml index 9a26fde79..d88400fde 100644 --- a/.github/actions/package/linux/action.yml +++ b/.github/actions/package/linux/action.yml @@ -37,14 +37,20 @@ runs: # Fixup architecture naming for AppImages dpkg_arch="$(dpkg-architecture -q DEB_HOST_ARCH_CPU)" case "$dpkg_arch" in - "amd64") + amd64) APPIMAGE_ARCH="x86_64" ;; - "arm64") + arm64) APPIMAGE_ARCH="aarch64" ;; + i386|i686) + APPIMAGE_ARCH="i386" + ;; + armhf|armv7l) + APPIMAGE_ARCH="armhf" + ;; *) - echo "# 🚨 The Debian architecture \"$deb_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY" + echo "# 🚨 The Debian architecture \"$dpkg_arch\" is not recognized!" >> "$GITHUB_STEP_SUMMARY" exit 1 ;; esac @@ -67,14 +73,91 @@ runs: mv ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.sogik.NMCLauncher.metainfo.xml ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/metainfo/org.sogik.NMCLauncher.appdata.xml export "NO_APPSTREAM=1" # we have to skip appstream checking because appstream on ubuntu 20.04 is outdated - export OUTPUT="NMCLauncher-Linux-$APPIMAGE_ARCH.AppImage" + # Use artifact-name to differentiate between build variants (Linux, Linux+LTO, Linux-Clang, etc.) + ARTIFACT_SUFFIX="" + if [ -n "${{ inputs.artifact-name }}" ]; then + ARTIFACT_SUFFIX="-${{ inputs.artifact-name }}" + fi + export OUTPUT="NMCLauncher${ARTIFACT_SUFFIX}-$APPIMAGE_ARCH.AppImage" + + # Ensure linuxdeploy AppImage exists or attempt to download for this arch + LD_FILE="$(ls linuxdeploy-*.AppImage 2>/dev/null | grep -v plugin | head -n1 || true)" + if [ -z "$LD_FILE" ]; then + echo "::warning::linuxdeploy AppImage not present; attempting to download for $APPIMAGE_ARCH" + case "$APPIMAGE_ARCH" in + x86_64) LD_URL="https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20250213-2/linuxdeploy-x86_64.AppImage" ;; + aarch64) LD_URL="https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20250213-2/linuxdeploy-aarch64.AppImage" ;; + i386) LD_URL="https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-i386.AppImage" ;; + *) LD_URL="" ;; + esac + if [ -n "$LD_URL" ]; then + curl -L -o linuxdeploy-$APPIMAGE_ARCH.AppImage "$LD_URL" + chmod +x linuxdeploy-$APPIMAGE_ARCH.AppImage + LD_FILE="linuxdeploy-$APPIMAGE_ARCH.AppImage" + else + echo "::error::No linuxdeploy AppImage available for $APPIMAGE_ARCH" + exit 1 + fi + else + chmod +x "$LD_FILE" + fi + + # Ensure linuxdeploy-plugin-qt exists or download it + PLUGIN_FILE="linuxdeploy-plugin-qt-$APPIMAGE_ARCH.AppImage" + if [ ! -f "$PLUGIN_FILE" ]; then + echo "::warning::linuxdeploy-plugin-qt not present; attempting to download for $APPIMAGE_ARCH" + case "$APPIMAGE_ARCH" in + x86_64) PLUGIN_URL="https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage" ;; + aarch64) PLUGIN_URL="https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-aarch64.AppImage" ;; + i386) PLUGIN_URL="https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-i386.AppImage" ;; + *) PLUGIN_URL="" ;; + esac + if [ -n "$PLUGIN_URL" ]; then + curl -L -o "$PLUGIN_FILE" "$PLUGIN_URL" + chmod +x "$PLUGIN_FILE" + echo "✅ Downloaded and made executable: $PLUGIN_FILE" + else + echo "::error::No linuxdeploy-plugin-qt available for $APPIMAGE_ARCH" + exit 1 + fi + else + chmod +x "$PLUGIN_FILE" + echo "✅ Plugin already present: $PLUGIN_FILE" + fi - chmod +x linuxdeploy-*.AppImage + # Verify plugin is executable + if [ ! -x "$PLUGIN_FILE" ]; then + echo "::error::Plugin $PLUGIN_FILE exists but is not executable" + ls -la "$PLUGIN_FILE" + exit 1 + fi mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib mkdir -p ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines - cp -r ${{ runner.workspace }}/Qt/${{ inputs.qt-version }}/gcc_*64/plugins/iconengines/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines + # Locate installed Qt directory that matches inputs.qt-version (e.g. "6" -> "6.8.1") + QT_BASE="${{ runner.workspace }}/Qt" + QT_DIR="" + # direct match first + if [ -d "$QT_BASE/${{ inputs.qt-version }}" ]; then + QT_DIR="$QT_BASE/${{ inputs.qt-version }}" + else + # try prefix match (6 -> 6.8.1) + QT_DIR=$(find "$QT_BASE" -maxdepth 1 -type d -name "${{ inputs.qt-version }}*" | head -n1 || true) + fi + if [ -z "$QT_DIR" ] || [ ! -d "$QT_DIR" ]; then + echo "# 🚨 Qt directory for version '${{ inputs.qt-version }}' not found under $QT_BASE" >> "$GITHUB_STEP_SUMMARY" + exit 1 + fi + + # find matching compiler dir (gcc_64 or gcc_*64) + PLUGIN_SRC=$(ls -d "$QT_DIR"/gcc_*64/plugins/iconengines 2>/dev/null | head -n1 || true) + if [ -z "$PLUGIN_SRC" ] || [ ! -d "$PLUGIN_SRC" ]; then + echo "# 🚨 Qt iconengines not found in $QT_DIR (looked for $QT_DIR/gcc_*64/plugins/iconengines)" >> "$GITHUB_STEP_SUMMARY" + exit 1 + fi + + cp -r "$PLUGIN_SRC"/* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/plugins/iconengines cp /usr/lib/"$DEB_HOST_MULTIARCH"/libcrypto.so.* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/ cp /usr/lib/"$DEB_HOST_MULTIARCH"/libssl.so.* ${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib/ @@ -83,10 +166,21 @@ runs: LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:${{ env.INSTALL_APPIMAGE_DIR }}/usr/lib" export LD_LIBRARY_PATH - chmod +x AppImageUpdate-"$APPIMAGE_ARCH".AppImage - cp AppImageUpdate-"$APPIMAGE_ARCH".AppImage ${{ env.INSTALL_APPIMAGE_DIR }}/usr/bin + # Make AppImageUpdate optional (copy if present) + if [ -f "AppImageUpdate-$APPIMAGE_ARCH.AppImage" ]; then + chmod +x "AppImageUpdate-$APPIMAGE_ARCH.AppImage" + cp "AppImageUpdate-$APPIMAGE_ARCH.AppImage" "${{ env.INSTALL_APPIMAGE_DIR }}/usr/bin/" || true + echo "✅ Added AppImageUpdate-$APPIMAGE_ARCH.AppImage" + else + echo "::warning::AppImageUpdate-$APPIMAGE_ARCH.AppImage not found; skipping" + fi - export UPDATE_INFORMATION="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|NMCLauncher-Linux-$APPIMAGE_ARCH.AppImage.zsync" + # Update information with variant suffix for zsync + ARTIFACT_SUFFIX="" + if [ -n "${{ inputs.artifact-name }}" ]; then + ARTIFACT_SUFFIX="-${{ inputs.artifact-name }}" + fi + export UPDATE_INFORMATION="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|NMCLauncher${ARTIFACT_SUFFIX}-$APPIMAGE_ARCH.AppImage.zsync" if [ '${{ inputs.gpg-private-key-id }}' != '' ]; then export SIGN=1 @@ -98,9 +192,47 @@ runs: echo ":warning: Skipped code signing for Linux AppImage, as gpg key was not present." >> $GITHUB_STEP_SUMMARY fi - ./linuxdeploy-"$APPIMAGE_ARCH".AppImage --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.sogik.NMCLauncher.svg + # Run linuxdeploy with explicit path and capture exit code + ./"$LD_FILE" --appdir ${{ env.INSTALL_APPIMAGE_DIR }} --output appimage --plugin qt -i ${{ env.INSTALL_APPIMAGE_DIR }}/usr/share/icons/hicolor/scalable/apps/org.sogik.NMCLauncher.svg + linuxdeploy_rc=$? + echo "linuxdeploy exit code: $linuxdeploy_rc" - mv "NMCLauncher-Linux-$APPIMAGE_ARCH.AppImage" "NMCLauncher-Linux-${{ env.VERSION }}-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage" + if [ $linuxdeploy_rc -ne 0 ]; then + echo "::error::linuxdeploy failed with exit code $linuxdeploy_rc" + echo "Current directory contents:" + ls -la + echo "install-appdir contents:" + ls -la ${{ env.INSTALL_APPIMAGE_DIR }} || true + # Show log if available + if [ -f linuxdeploy.log ]; then + echo "---- linuxdeploy.log (last 200 lines) ----" + tail -n 200 linuxdeploy.log || true + fi + exit $linuxdeploy_rc + fi + + # Find the produced AppImage (exclude tool AppImages) + found=$(ls -1 *.AppImage 2>/dev/null | grep -Ev '(linuxdeploy|AppImageUpdate|plugin-qt)' | head -n1 || true) + + if [ -z "$found" ]; then + echo "::error::AppImage not found. Searching for any NMCLauncher AppImage..." + echo "Current directory contents:" + ls -la + echo "All AppImages found:" + ls -1 *.AppImage 2>/dev/null || echo "No AppImages found" + echo "install-appdir contents:" + ls -la ${{ env.INSTALL_APPIMAGE_DIR }} || true + exit 1 + fi + + echo "Found AppImage: $found" + + # Rename with artifact-name suffix to match expected output + ARTIFACT_SUFFIX="" + if [ -n "${{ inputs.artifact-name }}" ]; then + ARTIFACT_SUFFIX="-${{ inputs.artifact-name }}" + fi + mv "$found" "NMCLauncher${ARTIFACT_SUFFIX}-${{ env.VERSION }}-${{ inputs.build-type }}-$APPIMAGE_ARCH.AppImage" - name: Package portable tarball shell: bash @@ -127,11 +259,11 @@ runs: - name: Upload AppImage uses: actions/upload-artifact@v4 with: - name: NMCLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage - path: NMCLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage + name: NMCLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage + path: NMCLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage - name: Upload AppImage Zsync uses: actions/upload-artifact@v4 with: - name: NMCLauncher-${{ runner.os }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync - path: NMCLauncher-${{ runner.os }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync + name: NMCLauncher-${{ inputs.artifact-name }}-${{ inputs.version }}-${{ inputs.build-type }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync + path: NMCLauncher-${{ inputs.artifact-name }}-${{ env.APPIMAGE_ARCH }}.AppImage.zsync diff --git a/.github/actions/package/windows/action.yml b/.github/actions/package/windows/action.yml index 8e1d34757..7f816c053 100644 --- a/.github/actions/package/windows/action.yml +++ b/.github/actions/package/windows/action.yml @@ -35,6 +35,19 @@ runs: INSTALL_DIR: install run: | cmake --install ${{ env.BUILD_DIR }} + + # Check if updater was built and copy it if needed + if [ ! -f "${{ env.INSTALL_DIR }}/nmclauncher_updater.exe" ]; then + echo "::warning::nmclauncher_updater.exe not found in install dir, searching build tree..." + updater_path=$(find ${{ env.BUILD_DIR }} -name "nmclauncher_updater.exe" -type f | head -n1 || true) + if [ -n "$updater_path" ] && [ -f "$updater_path" ]; then + cp "$updater_path" "${{ env.INSTALL_DIR }}/nmclauncher_updater.exe" + echo "✅ Copied updater from $updater_path" + else + echo "⚠️ Updater not found - installer may not include auto-update functionality" + fi + fi + touch ${{ env.INSTALL_DIR }}/manifest.txt for l in $(find ${{ env.INSTALL_DIR }} -type f); do l=$(cygpath -u $l); l=${l#$(pwd)/}; l=${l#${{ env.INSTALL_DIR }}/}; l=${l#./}; echo $l; done >> ${{ env.INSTALL_DIR }}/manifest.txt @@ -47,6 +60,39 @@ runs: run: | cmake --install ${{ env.BUILD_DIR }} --config ${{ inputs.build-type }} + # Check if updater was built and copy it if needed + $updaterPath = Join-Path $env:INSTALL_DIR "nmclauncher_updater.exe" + if (-not (Test-Path $updaterPath)) { + Write-Host "::warning::nmclauncher_updater.exe not found in $env:INSTALL_DIR, searching build tree..." + + $possibleLocations = @( + (Join-Path $env:BUILD_DIR "${{ inputs.build-type }}\nmclauncher_updater.exe"), + (Join-Path $env:BUILD_DIR "Release\nmclauncher_updater.exe"), + (Join-Path $env:BUILD_DIR "Debug\nmclauncher_updater.exe"), + (Join-Path $env:BUILD_DIR "nmclauncher_updater.exe") + ) + + $found = $null + foreach ($p in $possibleLocations) { + if (Test-Path $p) { + $found = $p + break + } + } + + if (-not $found) { + $hit = Get-ChildItem $env:BUILD_DIR -Recurse -Filter "nmclauncher_updater.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($hit) { $found = $hit.FullName } + } + + if ($found) { + Copy-Item $found $env:INSTALL_DIR + Write-Host "✅ Copied updater from $found" + } else { + Write-Host "⚠️ Updater not found - installer may not include auto-update functionality" + } + } + cd ${{ github.workspace }} Get-ChildItem ${{ env.INSTALL_DIR }} -Recurse | ForEach FullName | Resolve-Path -Relative | %{ $_.TrimStart('.\') } | %{ $_.TrimStart('${{ env.INSTALL_DIR }}') } | %{ $_.TrimStart('\') } | Out-File -FilePath ${{ env.INSTALL_DIR }}/manifest.txt @@ -106,14 +152,62 @@ runs: New-Item -Name NSISPlugins -ItemType Directory Invoke-Webrequest https://github.com/negrutiu/nsis-nscurl/releases/download/"${{ env.NSCURL_VERSION }}"/NScurl.zip -OutFile NSISPlugins\NScurl.zip $nscurl_hash = Get-FileHash NSISPlugins\NScurl.zip -Algorithm Sha256 | Select-Object -ExpandProperty Hash - if ( $nscurl_hash -ne "${{ env.nscurl_sha256 }}") { + if ( $nscurl_hash -ne "${{ env.NSCURL_SHA256 }}") { echo "::error:: NSCurl.zip sha256 mismatch" exit 1 } Expand-Archive -Path NSISPlugins\NScurl.zip -DestinationPath NSISPlugins\NScurl + # Pre-flight check: verify install directory contents + Write-Host "📦 Inspecting install directory: $env:INSTALL_DIR" + Get-ChildItem $env:INSTALL_DIR -Recurse | Select-Object FullName, Length | ForEach-Object { Write-Host $_.FullName } + + # Check for required files (updater may be optional depending on build config) + $updaterPath = Join-Path $env:INSTALL_DIR "nmclauncher_updater.exe" + if (-not (Test-Path $updaterPath)) { + Write-Host "::warning:: nmclauncher_updater.exe not found in $env:INSTALL_DIR" + Write-Host "Checking build directory for updater..." + + # Candidate updater locations (each Join-Path parenthesized to ensure a string result) + $possibleLocations = @( + (Join-Path $env:BUILD_DIR 'Release\nmclauncher_updater.exe'), + (Join-Path $env:BUILD_DIR 'Debug\nmclauncher_updater.exe'), + (Join-Path $env:BUILD_DIR 'nmclauncher_updater.exe') + ) + + Write-Host "Searching for updater in: $($possibleLocations -join ', ')" + + $found = $null + foreach ($p in $possibleLocations) { + if (Test-Path $p) { $found = $p; break } + } + + # Fallback: search build tree if not found in common locations + if (-not $found) { + Write-Host "Updater not found in candidate locations; searching build tree..." + $hit = Get-ChildItem $env:BUILD_DIR -Recurse -Filter 'nmclauncher_updater.exe' -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($hit) { + $found = $hit.FullName + Write-Host "Found updater at: $found" + } + } + + if ($found) { + Copy-Item $found $env:INSTALL_DIR + Write-Host "✅ Copied updater from $found to $env:INSTALL_DIR" + } else { + Write-Host "⚠️ Updater not found in build tree - installer may not include auto-update functionality" + Write-Host "Build tree contents:" + Get-ChildItem $env:BUILD_DIR -Recurse -Filter "*.exe" | ForEach-Object { Write-Host $_.FullName } + } + } else { + Write-Host "✅ Found nmclauncher_updater.exe" + } + + # Run makensis from install directory so relative paths work correctly + # The .nsi file paths (File commands) are relative to where makensis runs cd ${{ env.INSTALL_DIR }} - makensis -NOCD "${{ github.workspace }}/${{ env.BUILD_DIR }}/program_info/win_install.nsi" + makensis "${{ github.workspace }}\${{ env.BUILD_DIR }}\program_info\win_install.nsi" - name: Sign installer shell: pwsh diff --git a/.github/actions/setup-dependencies/action.yml b/.github/actions/setup-dependencies/action.yml index 405f524c4..7d02a50d8 100644 --- a/.github/actions/setup-dependencies/action.yml +++ b/.github/actions/setup-dependencies/action.yml @@ -53,7 +53,7 @@ runs: # TODO(@getchoo): Get this working on MSYS2! - name: Setup ccache - if: ${{ (runner.os != 'Windows' || inputs.msystem == '') && inputs.build-type == 'Debug' }} + if: ${{ (runner.os != 'Windows' || inputs.msystem != '') && inputs.build-type == 'Debug' }} uses: hendrikmuhs/ccache-action@v1.2.18 with: variant: sccache @@ -61,10 +61,9 @@ runs: key: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.artifact-name }}-sccache - name: Use ccache on debug builds - if: ${{ inputs.build-type == 'Debug' }} + if: ${{ (runner.os != 'Windows' || inputs.msystem != '') && inputs.build-type == 'Debug' }} shell: bash env: - # Only use ccache on MSYS2 CCACHE_VARIANT: ${{ (runner.os == 'Windows' && inputs.msystem != '') && 'ccache' || 'sccache' }} run: | echo "CMAKE_C_COMPILER_LAUNCHER=$CCACHE_VARIANT" >> "$GITHUB_ENV" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66ca987f2..7d5b9e5d0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,52 +73,121 @@ jobs: fail-fast: false matrix: include: + # Linux - GCC (standard) - os: ubuntu-22.04 artifact-name: Linux base-cmake-preset: linux - # NOTE(@getchoo): Yes, we're intentionally using 24.04 here!!! - # - # It's not really documented anywhere AFAICT, but upstream Qt binaries - # *for the same version* are compiled against 24.04 on ARM, and *not* 22.04 like x64 + # Linux - GCC + LTO + - os: ubuntu-22.04 + artifact-name: Linux+LTO + base-cmake-preset: linux + enable-lto: true + + # Linux - Clang + - os: ubuntu-22.04 + artifact-name: Linux-Clang + base-cmake-preset: linux + use-clang: true + + # Linux ARM - os: ubuntu-24.04-arm artifact-name: Linux-aarch64 base-cmake-preset: linux + # Linux ARM + LTO + - os: ubuntu-24.04-arm + artifact-name: Linux-aarch64+LTO + base-cmake-preset: linux + enable-lto: true + + # Windows MinGW (standard) - os: windows-2022 artifact-name: Windows-MinGW-w64 base-cmake-preset: windows_mingw msystem: CLANG64 vcvars-arch: amd64_x86 + # Windows MinGW + LTO + - os: windows-2022 + artifact-name: Windows-MinGW-w64+LTO + base-cmake-preset: windows_mingw + msystem: CLANG64 + vcvars-arch: amd64_x86 + enable-lto: true + + # Windows MinGW ARM - os: windows-11-arm artifact-name: Windows-MinGW-arm64 base-cmake-preset: windows_mingw msystem: CLANGARM64 vcvars-arch: arm64 + # Windows MinGW ARM + LTO + - os: windows-11-arm + artifact-name: Windows-MinGW-arm64+LTO + base-cmake-preset: windows_mingw + msystem: CLANGARM64 + vcvars-arch: arm64 + enable-lto: true + + # Windows MSVC (standard) - os: windows-2022 artifact-name: Windows-MSVC base-cmake-preset: windows_msvc - # TODO(@getchoo): This is the default in setup-dependencies/windows. Why isn't it working?!?! vcvars-arch: amd64 + # Windows MSVC + LTO + - os: windows-2022 + artifact-name: Windows-MSVC+LTO + base-cmake-preset: windows_msvc + vcvars-arch: amd64 + enable-lto: true + + # Windows MSVC ARM64 - os: windows-2022 artifact-name: Windows-MSVC-arm64 base-cmake-preset: windows_msvc_arm64_cross vcvars-arch: amd64_arm64 qt-architecture: win64_msvc2022_arm64_cross_compiled + # Windows MSVC ARM64 + LTO + - os: windows-2022 + artifact-name: Windows-MSVC-arm64+LTO + base-cmake-preset: windows_msvc_arm64_cross + vcvars-arch: amd64_arm64 + qt-architecture: win64_msvc2022_arm64_cross_compiled + enable-lto: true + + # Windows Clang + - os: windows-2022 + artifact-name: Windows-Clang + base-cmake-preset: windows_msvc + vcvars-arch: amd64 + use-clang: true + + # Windows Clang + LTO + - os: windows-2022 + artifact-name: Windows-Clang+LTO + base-cmake-preset: windows_msvc + vcvars-arch: amd64 + use-clang: true + enable-lto: true + + # macOS (standard) - os: macos-14 artifact-name: macOS base-cmake-preset: ${{ (inputs.build-type || 'Debug') == 'Debug' && 'macos_universal' || 'macos' }} macosx-deployment-target: 12.0 - runs-on: ${{ matrix.os }} + # macOS + LTO + - os: macos-14 + artifact-name: macOS+LTO + base-cmake-preset: ${{ (inputs.build-type || 'Debug') == 'Debug' && 'macos_universal' || 'macos' }} + macosx-deployment-target: 12.0 + enable-lto: true - defaults: - run: - shell: ${{ matrix.msystem != '' && 'msys2 {0}' || 'bash' }} + runs-on: ${{ matrix.os }} env: MACOSX_DEPLOYMENT_TARGET: ${{ matrix.macosx-deployment-target }} @@ -133,6 +202,14 @@ jobs: with: submodules: true + - name: Install Clang (Linux) + if: ${{ runner.os == 'Linux' && matrix.use-clang }} + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh 18 + sudo apt-get install -y lld-18 + - name: Setup dependencies id: setup-dependencies uses: ./.github/actions/setup-dependencies @@ -142,6 +219,9 @@ jobs: msystem: ${{ matrix.msystem }} vcvars-arch: ${{ matrix.vcvars-arch }} qt-architecture: ${{ matrix.qt-architecture }} + env: + CC: ${{ matrix.use-clang && runner.os == 'Linux' && 'clang-18' || '' }} + CXX: ${{ matrix.use-clang && runner.os == 'Linux' && 'clang++-18' || '' }} - name: Export CurseForge API Key run: echo "CURSEFORGE_API_KEY=${{ secrets.CURSEFORGE_API_KEY }}" >> $GITHUB_ENV @@ -155,31 +235,195 @@ jobs: - name: Get CMake preset id: cmake-preset + shell: bash env: BASE_CMAKE_PRESET: ${{ matrix.base-cmake-preset }} PRESET_TYPE: ${{ (inputs.build-type || 'Debug') == 'Debug' && 'debug' || 'ci' }} + MSYSTEM: ${{ matrix.msystem }} run: | echo preset="$BASE_CMAKE_PRESET"_"$PRESET_TYPE" >> "$GITHUB_OUTPUT" - - name: Run CMake workflow + - name: Configure CMake with optimizations (Windows MSVC) + if: ${{ runner.os == 'Windows' && (matrix.base-cmake-preset == 'windows_msvc' || matrix.base-cmake-preset == 'windows_msvc_arm64_cross') }} + shell: cmd + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + ENABLE_LTO: ${{ matrix.enable-lto || 'false' }} + USE_CLANG: ${{ matrix.use-clang || 'false' }} + run: | + set "CMAKE_EXTRA_FLAGS=" + if "%ENABLE_LTO%"=="true" set "CMAKE_EXTRA_FLAGS=-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON" + if "%USE_CLANG%"=="true" ( + set "CC=clang-cl" + set "CXX=clang-cl" + ) + if defined VSINSTALLDIR ( + call "%VSINSTALLDIR%VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.vcvars-arch }} + ) else ( + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.vcvars-arch }} + ) + cmake --preset "%CMAKE_PRESET%" %CMAKE_EXTRA_FLAGS% + + - name: Configure CMake with optimizations (MinGW) + if: ${{ runner.os == 'Windows' && matrix.msystem != '' }} + shell: msys2 {0} + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + ENABLE_LTO: ${{ matrix.enable-lto || 'false' }} + USE_CLANG: ${{ matrix.use-clang || 'false' }} + run: | + CMAKE_EXTRA_FLAGS="" + + if [ "$ENABLE_LTO" = "true" ]; then + CMAKE_EXTRA_FLAGS="-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON" + fi + + cmake --preset "$CMAKE_PRESET" $CMAKE_EXTRA_FLAGS + + - name: Configure CMake with optimizations (Linux/macOS) + if: ${{ runner.os != 'Windows' }} + shell: bash env: CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + ENABLE_LTO: ${{ matrix.enable-lto || 'false' }} + USE_CLANG: ${{ matrix.use-clang || 'false' }} + run: | + CMAKE_EXTRA_FLAGS="" + + if [ "$ENABLE_LTO" = "true" ]; then + CMAKE_EXTRA_FLAGS="-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON" + fi + if [ "$USE_CLANG" = "true" ] && [ "${{ runner.os }}" = "Linux" ]; then + export CC=clang-18 + export CXX=clang++-18 + CMAKE_EXTRA_FLAGS="$CMAKE_EXTRA_FLAGS -DCMAKE_EXE_LINKER_FLAGS=-fuse-ld=lld-18" + fi + + cmake --preset "$CMAKE_PRESET" $CMAKE_EXTRA_FLAGS + + - name: Build (Windows MSVC) + if: ${{ runner.os == 'Windows' && (matrix.base-cmake-preset == 'windows_msvc' || matrix.base-cmake-preset == 'windows_msvc_arm64_cross') }} + shell: cmd + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} ARTIFACT_NAME: ${{ matrix.artifact-name }}-Qt6 BUILD_PLATFORM: official run: | - cmake --workflow --preset "$CMAKE_PRESET" + if defined VSINSTALLDIR ( + call "%VSINSTALLDIR%VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.vcvars-arch }} + ) else ( + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.vcvars-arch }} + ) + REM Verify compiler is available + cl.exe /? >nul 2>&1 || (echo ERROR: cl.exe not found after vcvars & exit /b 1) + cmake --build --preset "%CMAKE_PRESET%" --target all + REM Build updater explicitly (may be EXCLUDE_FROM_ALL) + cmake --build --preset "%CMAKE_PRESET%" --target NMCLauncher_updater || (echo Updater target not available & exit /b 0) + + - name: Build (MinGW) + if: ${{ runner.os == 'Windows' && matrix.msystem != '' }} + shell: msys2 {0} + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + ARTIFACT_NAME: ${{ matrix.artifact-name }}-Qt6 + BUILD_PLATFORM: official + run: | + cmake --build --preset "$CMAKE_PRESET" --target all + # Build updater explicitly (may be EXCLUDE_FROM_ALL) + cmake --build --preset "$CMAKE_PRESET" --target NMCLauncher_updater || true + + - name: Build (Linux/macOS) + if: ${{ runner.os != 'Windows' }} + shell: bash + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + ARTIFACT_NAME: ${{ matrix.artifact-name }}-Qt6 + BUILD_PLATFORM: official + run: | + cmake --build --preset "$CMAKE_PRESET" --target all + + - name: Test (Windows MSVC) + if: ${{ runner.os == 'Windows' && (matrix.base-cmake-preset == 'windows_msvc' || matrix.base-cmake-preset == 'windows_msvc_arm64_cross') }} + shell: cmd + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + run: | + if defined VSINSTALLDIR ( + call "%VSINSTALLDIR%VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.vcvars-arch }} + ) else ( + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ${{ matrix.vcvars-arch }} + ) + ctest --preset "%CMAKE_PRESET%" || exit 0 + + - name: Test (MinGW) + if: ${{ runner.os == 'Windows' && matrix.msystem != '' }} + shell: msys2 {0} + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + run: | + ctest --preset "$CMAKE_PRESET" || true + + - name: Test (Linux/macOS) + if: ${{ runner.os != 'Windows' }} + shell: bash + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + run: | + ctest --preset "$CMAKE_PRESET" || true + + - name: Install (Windows MSVC) + if: ${{ runner.os == 'Windows' && (matrix.base-cmake-preset == 'windows_msvc' || matrix.base-cmake-preset == 'windows_msvc_arm64_cross') }} + shell: cmd + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + run: | + cmake --install build --prefix install + + - name: Install (MinGW) + if: ${{ runner.os == 'Windows' && matrix.msystem != '' }} + shell: msys2 {0} + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + run: | + cmake --install build --prefix install + + - name: Install (Linux/macOS) + if: ${{ runner.os != 'Windows' }} + shell: bash + env: + CMAKE_PRESET: ${{ steps.cmake-preset.outputs.preset }} + run: | + cmake --install build --prefix install ## # PACKAGE ## - - name: Get short version - id: short-version + - name: Get short version (MinGW) + if: ${{ runner.os == 'Windows' && matrix.msystem != '' }} + id: short-version-mingw + shell: msys2 {0} + run: | + echo "version=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + + - name: Get short version (Linux/macOS) + if: ${{ runner.os != 'Windows' }} + id: short-version-unix shell: bash run: | echo "version=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + - name: Set version output + id: short-version + shell: bash + run: | + if [ "${{ runner.os }}" = "Windows" ] && [ -n "${{ matrix.msystem }}" ]; then + echo "version=${{ steps.short-version-mingw.outputs.version }}" >> "$GITHUB_OUTPUT" + else + echo "version=${{ steps.short-version-unix.outputs.version }}" >> "$GITHUB_OUTPUT" + fi + - name: Package (Linux) if: ${{ runner.os == 'Linux' }} uses: ./.github/actions/package/linux diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml deleted file mode 100644 index 9997d2865..000000000 --- a/.github/workflows/nix.yml +++ /dev/null @@ -1,153 +0,0 @@ -name: Nix - -on: - push: - branches: - - "dev" - - "release-*" - tags: - - "*" - paths: - # File types - - "**.cpp" - - "**.h" - - "**.java" - - "**.ui" - - # Build files - - "**.nix" - - "nix/**" - - "flake.lock" - - # Directories - - "buildconfig/**" - - "cmake/**" - - "launcher/**" - - "libraries/**" - - "program_info/**" - - "tests/**" - - # Files - - "CMakeLists.txt" - - "COPYING.md" - - # Workflows - - ".github/workflows/nix.yml" - pull_request_target: - paths: - # File types - - "**.cpp" - - "**.h" - - "**.java" - - "**.ui" - - # Build files - - "**.nix" - - "nix/**" - - "flake.lock" - - # Directories - - "buildconfig/**" - - "cmake/**" - - "launcher/**" - - "libraries/**" - - "program_info/**" - - "tests/**" - - # Files - - "CMakeLists.txt" - - "COPYING.md" - - # Workflows - - ".github/workflows/nix.yml" - workflow_dispatch: - -permissions: - contents: read - -env: - DEBUG: ${{ github.ref_type != 'tag' }} - USE_DETERMINATE: ${{ github.event_name == 'pull_request' }} - -jobs: - build: - name: Build (${{ matrix.system }}) - - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-22.04 - system: x86_64-linux - - - os: ubuntu-22.04-arm - system: aarch64-linux - - - os: macos-13 - system: x86_64-darwin - - - os: macos-14 - system: aarch64-darwin - - runs-on: ${{ matrix.os }} - - permissions: - id-token: write - - steps: - - name: Get merge commit - if: ${{ github.event_name == 'pull_request_target' }} - id: merge-commit - uses: sogik/NMCLauncher/.github/actions/get-merge-commit@dev - with: - pull-request-id: ${{ github.event.number }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ steps.merge-commit.outputs.merge-commit-sha || github.sha }} - - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@v18 - with: - determinate: ${{ env.USE_DETERMINATE }} - - # For PRs - - name: Setup Nix Magic Cache - if: ${{ env.USE_DETERMINATE == 'true' }} - uses: DeterminateSystems/flakehub-cache-action@v2 - - # For in-tree builds - - name: Setup Cachix - if: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} - uses: cachix/cachix-action@v16 - with: - name: nmclauncher - authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} - - - name: Update Flake Lock - run: | - nix flake update - - - name: Run Flake checks - run: | - nix flake check --print-build-logs --show-trace - - - name: Build debug package - if: ${{ env.DEBUG == 'true' }} - run: | - nix build \ - --no-link --print-build-logs --print-out-paths \ - .#nmclauncher-debug >> "$GITHUB_STEP_SUMMARY" - - - name: Build release package - if: ${{ env.DEBUG == 'false' }} - env: - TAG: ${{ github.ref_name }} - SYSTEM: ${{ matrix.system }} - run: | - nix build --no-link --print-out-paths .#nmclauncher \ - | tee -a "$GITHUB_STEP_SUMMARY" \ - | xargs cachix pin nmclauncher "$TAG"-"$SYSTEM" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 179963229..000000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Publish - -on: - release: - types: [released] - -permissions: - contents: read - -jobs: - winget: - name: Winget - - runs-on: windows-latest - - steps: - - name: Publish on Winget - uses: vedantmgoyal2009/winget-releaser@v2 - with: - identifier: sogik.NMCLauncher - version: ${{ github.event.release.tag_name }} - installers-regex: 'NMCLauncher-Windows-MSVC(:?-arm64|-Legacy)?-Setup-.+\.exe$' - token: ${{ secrets.WINGET_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a31ab89e6..28f34e082 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,12 +33,31 @@ jobs: - name: Package artifacts properly run: | mv ${{ github.workspace }}/NMCLauncher-source NMCLauncher-${{ env.VERSION }} + + # Linux portable variants mv NMCLauncher-Linux-Qt6-Portable*/NMCLauncher-portable.tar.gz NMCLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz - mv NMCLauncher-*.AppImage/NMCLauncher-*-x86_64.AppImage NMCLauncher-Linux-x86_64.AppImage - mv NMCLauncher-*.AppImage.zsync/NMCLauncher-*-x86_64.AppImage.zsync NMCLauncher-Linux-x86_64.AppImage.zsync - mv NMCLauncher-*.AppImage/NMCLauncher-*-aarch64.AppImage NMCLauncher-Linux-aarch64.AppImage - mv NMCLauncher-*.AppImage.zsync/NMCLauncher-*-aarch64.AppImage.zsync NMCLauncher-Linux-aarch64.AppImage.zsync - mv NMCLauncher-macOS*/NMCLauncher.zip NMCLauncher-macOS-${{ env.VERSION }}.zip + mv NMCLauncher-Linux+LTO-Qt6-Portable*/NMCLauncher-portable.tar.gz NMCLauncher-Linux+LTO-Qt6-Portable-${{ env.VERSION }}.tar.gz + mv NMCLauncher-Linux-Clang-Qt6-Portable*/NMCLauncher-portable.tar.gz NMCLauncher-Linux-Clang-Qt6-Portable-${{ env.VERSION }}.tar.gz + mv NMCLauncher-Linux-aarch64-Qt6-Portable*/NMCLauncher-portable.tar.gz NMCLauncher-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz + mv NMCLauncher-Linux-aarch64+LTO-Qt6-Portable*/NMCLauncher-portable.tar.gz NMCLauncher-Linux-aarch64+LTO-Qt6-Portable-${{ env.VERSION }}.tar.gz + + # Linux AppImages - ahora cada variante tiene su propio AppImage + # x86_64 variants + mv NMCLauncher-Linux-*-Release-x86_64.AppImage/NMCLauncher-Linux-*-Release-x86_64.AppImage NMCLauncher-Linux-x86_64.AppImage + mv NMCLauncher-Linux-*-Release-x86_64.AppImage.zsync/NMCLauncher-Linux-*-x86_64.AppImage.zsync NMCLauncher-Linux-x86_64.AppImage.zsync + mv NMCLauncher-Linux+LTO-*-Release-x86_64.AppImage/NMCLauncher-Linux+LTO-*-Release-x86_64.AppImage NMCLauncher-Linux+LTO-x86_64.AppImage + mv NMCLauncher-Linux+LTO-*-Release-x86_64.AppImage.zsync/NMCLauncher-Linux+LTO-*-x86_64.AppImage.zsync NMCLauncher-Linux+LTO-x86_64.AppImage.zsync + mv NMCLauncher-Linux-Clang-*-Release-x86_64.AppImage/NMCLauncher-Linux-Clang-*-Release-x86_64.AppImage NMCLauncher-Linux-Clang-x86_64.AppImage + mv NMCLauncher-Linux-Clang-*-Release-x86_64.AppImage.zsync/NMCLauncher-Linux-Clang-*-x86_64.AppImage.zsync NMCLauncher-Linux-Clang-x86_64.AppImage.zsync + # aarch64 variants + mv NMCLauncher-Linux-aarch64-*-Release-aarch64.AppImage/NMCLauncher-Linux-aarch64-*-Release-aarch64.AppImage NMCLauncher-Linux-aarch64.AppImage + mv NMCLauncher-Linux-aarch64-*-Release-aarch64.AppImage.zsync/NMCLauncher-Linux-aarch64-*-aarch64.AppImage.zsync NMCLauncher-Linux-aarch64.AppImage.zsync + mv NMCLauncher-Linux-aarch64+LTO-*-Release-aarch64.AppImage/NMCLauncher-Linux-aarch64+LTO-*-Release-aarch64.AppImage NMCLauncher-Linux-aarch64+LTO.AppImage + mv NMCLauncher-Linux-aarch64+LTO-*-Release-aarch64.AppImage.zsync/NMCLauncher-Linux-aarch64+LTO-*-aarch64.AppImage.zsync NMCLauncher-Linux-aarch64+LTO.AppImage.zsync + + # macOS + mv NMCLauncher-macOS-*/NMCLauncher.zip NMCLauncher-macOS-${{ env.VERSION }}.zip + mv NMCLauncher-macOS+LTO-*/NMCLauncher.zip NMCLauncher-macOS+LTO-${{ env.VERSION }}.zip tar --exclude='.git' -czf NMCLauncher-${{ env.VERSION }}.tar.gz NMCLauncher-${{ env.VERSION }} @@ -48,9 +67,11 @@ jobs: ARM64="$(echo -n ${d} | grep -o arm64 || true)" INST="$(echo -n ${d} | grep -o Setup || true)" PORT="$(echo -n ${d} | grep -o Portable || true)" + LTO="$(echo -n ${d} | grep -o LTO || true)" NAME="NMCLauncher-Windows-MSVC" test -z "${LEGACY}" || NAME="${NAME}-Legacy" test -z "${ARM64}" || NAME="${NAME}-arm64" + test -z "${LTO}" || NAME="${NAME}+LTO" test -z "${PORT}" || NAME="${NAME}-Portable" test -z "${INST}" || mv NMCLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" * @@ -61,7 +82,9 @@ jobs: cd "${d}" || continue INST="$(echo -n ${d} | grep -o Setup || true)" PORT="$(echo -n ${d} | grep -o Portable || true)" + LTO="$(echo -n ${d} | grep -o LTO || true)" NAME="NMCLauncher-Windows-MinGW-w64" + test -z "${LTO}" || NAME="${NAME}+LTO" test -z "${PORT}" || NAME="${NAME}-Portable" test -z "${INST}" || mv NMCLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" * @@ -72,14 +95,29 @@ jobs: cd "${d}" || continue INST="$(echo -n ${d} | grep -o Setup || true)" PORT="$(echo -n ${d} | grep -o Portable || true)" + LTO="$(echo -n ${d} | grep -o LTO || true)" NAME="NMCLauncher-Windows-MinGW-arm64" + test -z "${LTO}" || NAME="${NAME}+LTO" + test -z "${PORT}" || NAME="${NAME}-Portable" + test -z "${INST}" || mv NMCLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe + test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" * + cd .. + done + + for d in NMCLauncher-Windows-Clang*; do + cd "${d}" || continue + INST="$(echo -n ${d} | grep -o Setup || true)" + PORT="$(echo -n ${d} | grep -o Portable || true)" + LTO="$(echo -n ${d} | grep -o LTO || true)" + NAME="NMCLauncher-Windows-Clang" + test -z "${LTO}" || NAME="${NAME}+LTO" test -z "${PORT}" || NAME="${NAME}-Portable" test -z "${INST}" || mv NMCLauncher-*.exe ../${NAME}-Setup-${{ env.VERSION }}.exe test -n "${INST}" || zip -r -9 "../${NAME}-${{ env.VERSION }}.zip" * cd .. done - - name: Create release + - name: Package for macOS id: create_release uses: softprops/action-gh-release@v2 with: @@ -91,21 +129,49 @@ jobs: files: | NMCLauncher-Linux-x86_64.AppImage NMCLauncher-Linux-x86_64.AppImage.zsync + NMCLauncher-Linux+LTO-x86_64.AppImage + NMCLauncher-Linux+LTO-x86_64.AppImage.zsync + NMCLauncher-Linux-Clang-x86_64.AppImage + NMCLauncher-Linux-Clang-x86_64.AppImage.zsync NMCLauncher-Linux-aarch64.AppImage NMCLauncher-Linux-aarch64.AppImage.zsync + NMCLauncher-Linux-aarch64+LTO.AppImage + NMCLauncher-Linux-aarch64+LTO.AppImage.zsync NMCLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz + NMCLauncher-Linux+LTO-Qt6-Portable-${{ env.VERSION }}.tar.gz + NMCLauncher-Linux-Clang-Qt6-Portable-${{ env.VERSION }}.tar.gz NMCLauncher-Linux-aarch64-Qt6-Portable-${{ env.VERSION }}.tar.gz + NMCLauncher-Linux-aarch64+LTO-Qt6-Portable-${{ env.VERSION }}.tar.gz NMCLauncher-Windows-MinGW-w64-${{ env.VERSION }}.zip NMCLauncher-Windows-MinGW-w64-Portable-${{ env.VERSION }}.zip NMCLauncher-Windows-MinGW-w64-Setup-${{ env.VERSION }}.exe + NMCLauncher-Windows-MinGW-w64+LTO-${{ env.VERSION }}.zip + NMCLauncher-Windows-MinGW-w64+LTO-Portable-${{ env.VERSION }}.zip + NMCLauncher-Windows-MinGW-w64+LTO-Setup-${{ env.VERSION }}.exe NMCLauncher-Windows-MinGW-arm64-${{ env.VERSION }}.zip NMCLauncher-Windows-MinGW-arm64-Portable-${{ env.VERSION }}.zip NMCLauncher-Windows-MinGW-arm64-Setup-${{ env.VERSION }}.exe + NMCLauncher-Windows-MinGW-arm64+LTO-${{ env.VERSION }}.zip + NMCLauncher-Windows-MinGW-arm64+LTO-Portable-${{ env.VERSION }}.zip + NMCLauncher-Windows-MinGW-arm64+LTO-Setup-${{ env.VERSION }}.exe NMCLauncher-Windows-MSVC-arm64-${{ env.VERSION }}.zip NMCLauncher-Windows-MSVC-arm64-Portable-${{ env.VERSION }}.zip NMCLauncher-Windows-MSVC-arm64-Setup-${{ env.VERSION }}.exe + NMCLauncher-Windows-MSVC-arm64+LTO-${{ env.VERSION }}.zip + NMCLauncher-Windows-MSVC-arm64+LTO-Portable-${{ env.VERSION }}.zip + NMCLauncher-Windows-MSVC-arm64+LTO-Setup-${{ env.VERSION }}.exe NMCLauncher-Windows-MSVC-${{ env.VERSION }}.zip NMCLauncher-Windows-MSVC-Portable-${{ env.VERSION }}.zip NMCLauncher-Windows-MSVC-Setup-${{ env.VERSION }}.exe + NMCLauncher-Windows-MSVC+LTO-${{ env.VERSION }}.zip + NMCLauncher-Windows-MSVC+LTO-Portable-${{ env.VERSION }}.zip + NMCLauncher-Windows-MSVC+LTO-Setup-${{ env.VERSION }}.exe + NMCLauncher-Windows-Clang-${{ env.VERSION }}.zip + NMCLauncher-Windows-Clang-Portable-${{ env.VERSION }}.zip + NMCLauncher-Windows-Clang-Setup-${{ env.VERSION }}.exe + NMCLauncher-Windows-Clang+LTO-${{ env.VERSION }}.zip + NMCLauncher-Windows-Clang+LTO-Portable-${{ env.VERSION }}.zip + NMCLauncher-Windows-Clang+LTO-Setup-${{ env.VERSION }}.exe NMCLauncher-macOS-${{ env.VERSION }}.zip + NMCLauncher-macOS+LTO-${{ env.VERSION }}.zip NMCLauncher-${{ env.VERSION }}.tar.gz diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml deleted file mode 100644 index 484bf099e..000000000 --- a/.github/workflows/update-flake.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Update Flake Lockfile - -on: - schedule: - # run weekly on sunday - - cron: "0 0 * * 0" - workflow_dispatch: - -permissions: - contents: write - pull-requests: write - -jobs: - update-flake: - if: github.repository == 'sogik/NMCLauncher' - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@f0fe604f8a612776892427721526b4c7cfb23aba # v31 - - - uses: DeterminateSystems/update-flake-lock@v26 - with: - commit-msg: "chore(nix): update lockfile" - pr-title: "chore(nix): update lockfile" - #pr-labels: | - #Linux - #packaging - #simple change - #changelog:omit diff --git a/CMakeLists.txt b/CMakeLists.txt index 773046731..127223536 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,11 +2,48 @@ cmake_minimum_required(VERSION 3.15) # minimum version required by QuaZip project(Launcher) +# Force rebuild for PR testing string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BUILD_DIR}" IS_IN_SOURCE_BUILD) if(IS_IN_SOURCE_BUILD) message(FATAL_ERROR "You are building the Launcher in-source. Please separate the build tree from the source tree.") endif() +##################################### Performance Optimizations ##################################### +# Enable LTO/IPO for Release builds (5-10% performance gain, smaller binaries) +include(CheckIPOSupported) +check_ipo_supported(RESULT ipo_supported OUTPUT ipo_error) + +if(ipo_supported) + message(STATUS "✓ LTO/IPO enabled for Release builds") + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL ON) +else() + message(WARNING "✗ LTO/IPO not supported: ${ipo_error}") +endif() + +# Platform-specific optimizations +if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + # GCC-specific optimizations + add_compile_options( + $<$:-O2> + $<$:-pipe> + $<$:-fno-plt> + ) + message(STATUS "✓ GCC optimizations enabled") +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # Clang-specific optimizations + add_compile_options( + $<$:-O2> + $<$:-pipe> + $<$:-fno-plt> + ) + message(STATUS "✓ Clang optimizations enabled") +elseif(MSVC) + # MSVC-specific optimizations (handled below in existing MSVC section) + message(STATUS "✓ MSVC optimizations will be configured") +endif() + ##################################### Set CMake options ##################################### set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) @@ -389,8 +426,8 @@ if(UNIX AND APPLE) set(RESOURCES_DEST_DIR "${Launcher_Name}.app/Contents/Resources") set(JARS_DEST_DIR "${Launcher_Name}.app/Contents/MacOS/jars") - # Apps to bundle - set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app") + # Apps to bundle - must point to the actual executable inside the bundle + set(APPS "\${CMAKE_INSTALL_PREFIX}/${Launcher_Name}.app/Contents/MacOS/${Launcher_APP_BINARY_NAME}") # Mac bundle settings set(MACOSX_BUNDLE_BUNDLE_NAME "${Launcher_DisplayName}") diff --git a/README.md b/README.md index ac5a65742..2afd1fbf4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ NMC Launcher is a custom launcher for Minecraft that allows you to easily manage ## Warning and support -- If you have a problem with the launcher, **open an issue** [here](https://github.com/sogik/NMCLauncher/issues). +- If you have a problem with the launcher, **open an issue** in the [issue tracker](https://github.com/sogik/NMCLauncher/issues). - For questions or discussions, **use** [this discussion forum](https://github.com/sogik/NMCLauncher/discussions). - **Do not** request support from the Prism Launcher team for this fork. diff --git a/default.nix b/default.nix deleted file mode 100644 index 5ecef5590..000000000 --- a/default.nix +++ /dev/null @@ -1,4 +0,0 @@ -(import (fetchTarball { - url = "https://github.com/edolstra/flake-compat/archive/ff81ac966bb2cae68946d5ed5fc4994f96d0ffec.tar.gz"; - sha256 = "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU="; -}) { src = ./.; }).defaultNix diff --git a/flake.lock b/flake.lock deleted file mode 100644 index 19b565e76..000000000 --- a/flake.lock +++ /dev/null @@ -1,44 +0,0 @@ -{ - "nodes": { - "libnbtplusplus": { - "flake": false, - "locked": { - "lastModified": 1744811532, - "narHash": "sha256-qhmjaRkt+O7A+gu6HjUkl7QzOEb4r8y8vWZMG2R/C6o=", - "owner": "PrismLauncher", - "repo": "libnbtplusplus", - "rev": "531449ba1c930c98e0bcf5d332b237a8566f9d78", - "type": "github" - }, - "original": { - "owner": "PrismLauncher", - "repo": "libnbtplusplus", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1762363567, - "narHash": "sha256-YRqMDEtSMbitIMj+JLpheSz0pwEr0Rmy5mC7myl17xs=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "ae814fd3904b621d8ab97418f1d0f2eb0d3716f4", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "libnbtplusplus": "libnbtplusplus", - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index d6bea56a8..000000000 --- a/flake.nix +++ /dev/null @@ -1,213 +0,0 @@ -{ - description = "A custom launcher for Minecraft that allows you to easily manage multiple installations of Minecraft at once (Fork of MultiMC)"; - - nixConfig = { - extra-substituters = [ "https://nmclauncher.cachix.org" ]; - extra-trusted-public-keys = [ - "nmclauncher.cachix.org-1:RcJ7sWlfglVEaIo+t44O0XuIQwE6FspmAAQqHS7d9Qk=" - ]; - }; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - - libnbtplusplus = { - url = "github:PrismLauncher/libnbtplusplus"; - flake = false; - }; - }; - - outputs = - { - self, - nixpkgs, - libnbtplusplus, - }: - - let - inherit (nixpkgs) lib; - - # While we only officially support aarch and x86_64 on Linux and MacOS, - # we expose a reasonable amount of other systems for users who want to - # build for most exotic platforms - systems = lib.systems.flakeExposed; - - forAllSystems = lib.genAttrs systems; - nixpkgsFor = forAllSystems (system: nixpkgs.legacyPackages.${system}); - in - - { - checks = forAllSystems ( - system: - - let - pkgs = nixpkgsFor.${system}; - llvm = pkgs.llvmPackages_19; - in - - { - formatting = - pkgs.runCommand "check-formatting" - { - nativeBuildInputs = with pkgs; [ - deadnix - llvm.clang-tools - markdownlint-cli - nixfmt-rfc-style - statix - ]; - } - '' - cd ${self} - - echo "Running clang-format...." - clang-format --dry-run --style='file' --Werror */**.{c,cc,cpp,h,hh,hpp} - - echo "Running deadnix..." - deadnix --fail - - echo "Running markdownlint..." - markdownlint --dot . - - echo "Running nixfmt..." - find -type f -name '*.nix' -exec nixfmt --check {} + - - echo "Running statix" - statix check . - - touch $out - ''; - } - ); - - devShells = forAllSystems ( - system: - - let - pkgs = nixpkgsFor.${system}; - llvm = pkgs.llvmPackages_19; - - packages' = self.packages.${system}; - - welcomeMessage = '' - Welcome to the NMC Launcher repository! - - We just set some things up for you. To get building, you can run: - - ``` - $ cd "$cmakeBuildDir" - $ ninjaBuildPhase - $ ninjaInstallPhase - ``` - - ''; - - # Re-use our package wrapper to wrap our development environment - qt-wrapper-env = packages'.nmclauncher.overrideAttrs (old: { - name = "qt-wrapper-env"; - - # Required to use script-based makeWrapper below - strictDeps = true; - - # We don't need/want the unwrapped nmc package - paths = [ ]; - - nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [ - # Ensure the wrapper is script based so it can be sourced - pkgs.makeWrapper - ]; - - # Inspired by https://discourse.nixos.org/t/python-qt-woes/11808/10 - buildCommand = '' - makeQtWrapper ${lib.getExe pkgs.runtimeShellPackage} "$out" - sed -i '/^exec/d' "$out" - ''; - }); - in - - { - default = pkgs.mkShell { - inputsFrom = [ packages'.nmclauncher-unwrapped ]; - - packages = with pkgs; [ - ccache - llvm.clang-tools - ]; - - cmakeBuildType = "Debug"; - cmakeFlags = [ "-GNinja" ] ++ packages'.nmclauncher.cmakeFlags; - dontFixCmake = true; - - shellHook = '' - echo "Sourcing ${qt-wrapper-env}" - source ${qt-wrapper-env} - - git submodule update --init --force - - if [ ! -f compile_commands.json ]; then - cmakeConfigurePhase - cd .. - ln -s "$cmakeBuildDir"/compile_commands.json compile_commands.json - fi - - echo ${lib.escapeShellArg welcomeMessage} - ''; - }; - } - ); - - formatter = forAllSystems (system: nixpkgsFor.${system}.nixfmt-rfc-style); - - overlays.default = final: prev: { - nmclauncher-unwrapped = prev.callPackage ./nix/unwrapped.nix { - inherit - libnbtplusplus - self - ; - }; - - nmclauncher = final.callPackage ./nix/wrapper.nix { }; - }; - - packages = forAllSystems ( - system: - - let - pkgs = nixpkgsFor.${system}; - - # Build a scope from our overlay - nmcPackages = lib.makeScope pkgs.newScope (final: self.overlays.default final pkgs); - - # Grab our packages from it and set the default - packages = { - inherit (nmcPackages) nmclauncher-unwrapped nmclauncher; - default = nmcPackages.nmclauncher; - }; - in - - # Only output them if they're available on the current system - lib.filterAttrs (_: lib.meta.availableOn pkgs.stdenv.hostPlatform) packages - ); - - # We put these under legacyPackages as they are meant for CI, not end user consumption - legacyPackages = forAllSystems ( - system: - - let - packages' = self.packages.${system}; - legacyPackages' = self.legacyPackages.${system}; - in - - { - nmclauncher-debug = packages'.nmclauncher.override { - nmclauncher-unwrapped = legacyPackages'.nmclauncher-unwrapped-debug; - }; - - nmclauncher-unwrapped-debug = packages'.nmclauncher-unwrapped.overrideAttrs { - cmakeBuildType = "Debug"; - dontStrip = true; - }; - } - ); - }; -} diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 982ff7b6b..15af6f57e 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1408,7 +1408,23 @@ if(WIN32 OR (DEFINED Launcher_BUILD_FILELINKER AND Launcher_BUILD_FILELINKER)) add_executable("${Launcher_Name}_filelink" WIN32 filelink/filelink_main.cpp) - target_sources("${Launcher_Name}_filelink" PRIVATE filelink/filelink.exe.manifest) + # Embed manifest through resource file to avoid mt.exe merge conflicts + # The .rc file references filelink.exe.manifest which has level="requireAdministrator" + if(MSVC OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC" OR CMAKE_CXX_SIMULATE_ID MATCHES "MSVC") + set(FILELINK_RC "${CMAKE_CURRENT_SOURCE_DIR}/filelink/filelink.rc") + set_source_files_properties(${FILELINK_RC} PROPERTIES LANGUAGE RC) + target_sources("${Launcher_Name}_filelink" PRIVATE ${FILELINK_RC}) + + # Also force linker to use our manifest settings and embed it + message(STATUS "Embedding manifest for ${Launcher_Name}_filelink via RC file to avoid mt.exe merge conflicts") + target_link_options("${Launcher_Name}_filelink" PRIVATE + "/MANIFESTUAC:level='requireAdministrator' uiAccess='false'" + "/MANIFEST:EMBED" + ) + else() + # Non-MSVC platforms: add manifest directly (won't cause issues) + target_sources("${Launcher_Name}_filelink" PRIVATE filelink/filelink.exe.manifest) + endif() target_link_libraries("${Launcher_Name}_filelink" filelink_logic) diff --git a/launcher/filelink/filelink.rc b/launcher/filelink/filelink.rc new file mode 100644 index 000000000..f1c76f36e --- /dev/null +++ b/launcher/filelink/filelink.rc @@ -0,0 +1,4 @@ +// Resource file for filelink executable +// Embeds the manifest to avoid mt.exe merge conflicts + +1 RT_MANIFEST "filelink.exe.manifest" diff --git a/launcher/install_prereqs.cmake.in b/launcher/install_prereqs.cmake.in index acbce9650..67e47ccce 100644 --- a/launcher/install_prereqs.cmake.in +++ b/launcher/install_prereqs.cmake.in @@ -1,5 +1,15 @@ set(CMAKE_MODULE_PATH "@CMAKE_MODULE_PATH@") -file(GLOB_RECURSE QTPLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@") + +# Collect Qt plugins, but exclude Sparkle framework internals and system libraries +file(GLOB_RECURSE ALL_PLUGINS "${CMAKE_INSTALL_PREFIX}/@PLUGIN_DEST_DIR@/*@CMAKE_SHARED_LIBRARY_SUFFIX@") +set(QTPLUGINS "") +foreach(plugin ${ALL_PLUGINS}) + # Skip Sparkle framework internals - they will be handled by the framework itself + if(NOT plugin MATCHES "Sparkle\\.framework") + list(APPEND QTPLUGINS "${plugin}") + endif() +endforeach() + function(gp_resolved_file_type_override resolved_file type_var) if(resolved_file MATCHES "^/(usr/)?lib/libQt") set(${type_var} other PARENT_SCOPE) @@ -13,6 +23,9 @@ function(gp_resolved_file_type_override resolved_file type_var) set(${type_var} other PARENT_SCOPE) elseif((resolved_file MATCHES "^/(usr/)?lib(.+)?/libstdc\\+\\+") AND (UNIX AND NOT APPLE)) set(${type_var} other PARENT_SCOPE) + # Exclude Sparkle framework internals from being treated as external items + elseif(resolved_file MATCHES "Sparkle\\.framework/(Versions/[^/]+/)?(Autoupdate|Updater\\.app|XPCServices)") + set(${type_var} local PARENT_SCOPE) endif() endfunction() @@ -22,5 +35,54 @@ set(gp_cmd_paths ${gp_cmd_paths} ) include(BundleUtilities) -fixup_bundle("@APPS@" "${QTPLUGINS}" "@DIRS@") + +# Debug output at install time +message(STATUS "[install] CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") + +# APPS variable is set with escaped \${CMAKE_INSTALL_PREFIX} so it evaluates at install time +# We need to evaluate it now +set(BUNDLE_APP "@APPS@") +set(BUNDLE_SEARCH_DIRS "@DIRS@") + +message(STATUS "[install] Bundle executable (before eval): ${BUNDLE_APP}") +message(STATUS "[install] Search directories: ${BUNDLE_SEARCH_DIRS}") + +# Check if we're actually dealing with a macOS bundle +# On macOS, BUNDLE_APP will contain .app/Contents/MacOS/ +# On other platforms, it may be a regular executable path +if(BUNDLE_APP MATCHES "\\.app/Contents/MacOS/") + # macOS bundle detected - verify and run fixup_bundle + message(STATUS "[install] macOS bundle detected") + + # Verify the executable exists before running fixup_bundle + if(NOT EXISTS "${BUNDLE_APP}") + # List contents to help debug + get_filename_component(PARENT_DIR "${BUNDLE_APP}" DIRECTORY) + if(EXISTS "${PARENT_DIR}") + file(GLOB CONTENTS "${PARENT_DIR}/*") + message(STATUS "[install] Contents of ${PARENT_DIR}:") + foreach(item ${CONTENTS}) + message(STATUS " - ${item}") + endforeach() + endif() + message(FATAL_ERROR "Cannot find executable to fix up: ${BUNDLE_APP}") + endif() + + # Verify the bundle app directory exists + get_filename_component(BUNDLE_DIR "${BUNDLE_APP}" DIRECTORY) + get_filename_component(BUNDLE_DIR "${BUNDLE_DIR}" DIRECTORY) + get_filename_component(BUNDLE_DIR "${BUNDLE_DIR}" DIRECTORY) + message(STATUS "[install] Bundle directory: ${BUNDLE_DIR}") + + if(NOT EXISTS "${BUNDLE_DIR}") + message(FATAL_ERROR "Cannot find bundle directory: ${BUNDLE_DIR}") + endif() + + message(STATUS "[install] Running fixup_bundle...") + fixup_bundle("${BUNDLE_APP}" "${QTPLUGINS}" "${BUNDLE_SEARCH_DIRS}") + message(STATUS "[install] fixup_bundle completed successfully") +else() + # Not a macOS bundle - skip fixup_bundle + message(STATUS "[install] Not a macOS bundle; skipping fixup_bundle (this is normal on Windows/Linux)") +endif() diff --git a/launcher/java/download/ManifestDownloadTask.cpp b/launcher/java/download/ManifestDownloadTask.cpp index 20b39e751..9ec1d67fa 100644 --- a/launcher/java/download/ManifestDownloadTask.cpp +++ b/launcher/java/download/ManifestDownloadTask.cpp @@ -94,7 +94,7 @@ void ManifestDownloadTask::downloadJava(const QJsonDocument& doc) } else if (type == "file") { // TODO download compressed version if it exists ? auto raw = Json::ensureObject(Json::ensureObject(meta, "downloads"), "raw"); - auto isExec = Json::ensureBoolean(meta, "executable", false); + auto isExec = Json::ensureBoolean(meta.value("executable"), false); auto url = Json::ensureString(raw, "url"); if (!url.isEmpty() && QUrl(url).isValid()) { auto f = File{ file, url, QByteArray::fromHex(Json::ensureString(raw, "sha1").toLatin1()), isExec }; diff --git a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp index 0b80db82d..f05bc11ff 100644 --- a/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalResourcePackParseTask.cpp @@ -186,14 +186,14 @@ QString buildStyle(const QJsonObject& obj) } if (obj.contains("bold")) { QString weight = "normal"; - if (Json::ensureBoolean(obj, "bold", false)) { + if (Json::ensureBoolean(obj.value("bold"), false)) { weight = "bold"; } styles << QString("font-weight: %1;").arg(weight); } if (obj.contains("italic")) { QString style = "normal"; - if (Json::ensureBoolean(obj, "italic", false)) { + if (Json::ensureBoolean(obj.value("italic"), false)) { style = "italic"; } styles << QString("font-style: %1;").arg(style); @@ -212,8 +212,8 @@ QString processComponent(const QJsonArray& value, bool strikethrough, bool under QString processComponent(const QJsonObject& obj, bool strikethrough, bool underline) { - underline = Json::ensureBoolean(obj, "underlined", underline); - strikethrough = Json::ensureBoolean(obj, "strikethrough", strikethrough); + underline = Json::ensureBoolean(obj.value("underlined"), underline); + strikethrough = Json::ensureBoolean(obj.value("strikethrough"), strikethrough); QString result = Json::ensureString(obj, "text"); if (underline) { diff --git a/nix/README.md b/nix/README.md deleted file mode 100644 index 041a20519..000000000 --- a/nix/README.md +++ /dev/null @@ -1,220 +0,0 @@ -# Prism Launcher Nix Packaging - -## Installing a stable release (nixpkgs) - -Prism Launcher is packaged in [nixpkgs](https://github.com/NixOS/nixpkgs/) since 22.11. - -See [Package variants](#package-variants) for a list of available packages. - -## Installing a development release (flake) - -We use [cachix](https://cachix.org/) to cache our development and release builds. -If you want to avoid rebuilds you may add the Cachix bucket to your substitutors, or use `--accept-flake-config` -to temporarily enable it when using `nix` commands. - -Example (NixOS): - -```nix -{ - nix.settings = { - trusted-substituters = [ "https://prismlauncher.cachix.org" ]; - - trusted-public-keys = [ - "prismlauncher.cachix.org-1:9/n/FGyABA2jLUVfY+DEp4hKds/rwO+SCOtbOkDzd+c=" - ]; - }; -} -``` - -### Installing the package directly - -After adding `github:PrismLauncher/PrismLauncher` to your flake inputs, you can access the flake's `packages` output. - -Example: - -```nix -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - - prismlauncher = { - url = "github:PrismLauncher/PrismLauncher"; - - # Optional: Override the nixpkgs input of prismlauncher to use the same revision as the rest of your flake - # Note that this may break the reproducibility mentioned above, and you might not be able to access the binary cache - # - # inputs.nixpkgs.follows = "nixpkgs"; - }; - }; - - outputs = - { nixpkgs, prismlauncher, ... }: - { - nixosConfigurations.foo = nixpkgs.lib.nixosSystem { - modules = [ - ./configuration.nix - - ( - { pkgs, ... }: - { - environment.systemPackages = [ prismlauncher.packages.${pkgs.system}.prismlauncher ]; - } - ) - ]; - }; - }; -} -``` - -### Using the overlay - -Alternatively, if you don't want to use our `packages` output, you can add our overlay to your nixpkgs instance. -This will ensure Prism is built with your system's packages. - -> [!WARNING] -> Depending on what revision of nixpkgs your system uses, this may result in binaries that differ from the above `packages` output -> If this is the case, you will not be able to use the binary cache - -Example: - -```nix -{ - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - - prismlauncher = { - url = "github:PrismLauncher/PrismLauncher"; - - # Optional: Override the nixpkgs input of prismlauncher to use the same revision as the rest of your flake - # Note that this may break the reproducibility mentioned above, and you might not be able to access the binary cache - # - # inputs.nixpkgs.follows = "nixpkgs"; - }; - }; - - outputs = - { nixpkgs, prismlauncher, ... }: - { - nixosConfigurations.foo = nixpkgs.lib.nixosSystem { - modules = [ - ./configuration.nix - - ( - { pkgs, ... }: - { - nixpkgs.overlays = [ prismlauncher.overlays.default ]; - - environment.systemPackages = [ pkgs.prismlauncher ]; - } - ) - ]; - }; - }; -} -``` - -### Installing the package ad-hoc (`nix shell`, `nix run`, etc.) - -You can simply call the default package of this flake. - -Example: - -```shell -nix run github:PrismLauncher/PrismLauncher - -nix shell github:PrismLauncher/PrismLauncher - -nix profile install github:PrismLauncher/PrismLauncher -``` - -## Installing a development release (without flakes) - -We use [Cachix](https://cachix.org/) to cache our development and release builds. -If you want to avoid rebuilds you may add the Cachix bucket to your substitutors. - -Example (NixOS): - -```nix -{ - nix.settings = { - trusted-substituters = [ "https://prismlauncher.cachix.org" ]; - - trusted-public-keys = [ - "prismlauncher.cachix.org-1:9/n/FGyABA2jLUVfY+DEp4hKds/rwO+SCOtbOkDzd+c=" - ]; - }; -} -``` - -### Installing the package directly (`fetchTarball`) - -We use flake-compat to allow using this Flake on a system that doesn't use flakes. - -Example: - -```nix -{ pkgs, ... }: -{ - environment.systemPackages = [ - (import ( - builtins.fetchTarball "https://github.com/PrismLauncher/PrismLauncher/archive/develop.tar.gz" - )).packages.${pkgs.system}.prismlauncher - ]; -} -``` - -### Using the overlay (`fetchTarball`) - -Alternatively, if you don't want to use our `packages` output, you can add our overlay to your instance of nixpkgs. -This results in Prism using your system's libraries - -Example: - -```nix -{ pkgs, ... }: -{ - nixpkgs.overlays = [ - (import ( - builtins.fetchTarball "https://github.com/PrismLauncher/PrismLauncher/archive/develop.tar.gz" - )).overlays.default - ]; - - environment.systemPackages = [ pkgs.prismlauncher ]; -} -``` - -### Installing the package ad-hoc (`nix-env`) - -You can add this repository as a channel and install its packages that way. - -Example: - -```shell -nix-channel --add https://github.com/PrismLauncher/PrismLauncher/archive/develop.tar.gz prismlauncher - -nix-channel --update prismlauncher - -nix-env -iA prismlauncher.prismlauncher -``` - -## Package variants - -Both Nixpkgs and this repository offer the following packages: - -- `prismlauncher` - The preferred build, wrapped with everything necessary to run the launcher and Minecraft -- `prismlauncher-unwrapped` - A minimal build that allows for advanced customization of the launcher's runtime environment - -### Customizing wrapped packages - -The wrapped package (`prismlauncher`) offers some build parameters to further customize the launcher's environment. - -The following parameters can be overridden: - -- `additionalLibs` (default: `[ ]`) Additional libraries that will be added to `LD_LIBRARY_PATH` -- `additionalPrograms` (default: `[ ]`) Additional libraries that will be added to `PATH` -- `controllerSupport` (default: `isLinux`) Turn on/off support for controllers on Linux (macOS will always have this) -- `gamemodeSupport` (default: `isLinux`) Turn on/off support for [Feral GameMode](https://github.com/FeralInteractive/gamemode) on Linux -- `jdks` (default: `[ jdk21 jdk17 jdk8 ]`) Java runtimes added to `PRISMLAUNCHER_JAVA_PATHS` variable -- `msaClientID` (default: `null`, requires full rebuild!) Client ID used for Microsoft Authentication -- `textToSpeechSupport` (default: `isLinux`) Turn on/off support for text-to-speech on Linux (macOS will always have this) -- `withWaylandGLFW` (default: `isLinux`) Build with support for native Wayland via a custom GLFW diff --git a/nix/unwrapped.nix b/nix/unwrapped.nix deleted file mode 100644 index 3fd71db29..000000000 --- a/nix/unwrapped.nix +++ /dev/null @@ -1,132 +0,0 @@ -{ - lib, - stdenv, - cmake, - cmark, - darwin, - extra-cmake-modules, - gamemode, - ghc_filesystem, - jdk17, - kdePackages, - libnbtplusplus, - ninja, - self, - stripJavaArchivesHook, - tomlplusplus, - zlib, - - msaClientID ? null, - gamemodeSupport ? stdenv.hostPlatform.isLinux, -}: - -assert lib.assertMsg ( - gamemodeSupport -> stdenv.hostPlatform.isLinux -) "gamemodeSupport is only available on Linux."; - -let - date = - let - # YYYYMMDD - date' = lib.substring 0 8 self.lastModifiedDate; - year = lib.substring 0 4 date'; - month = lib.substring 4 2 date'; - date = lib.substring 6 2 date'; - in - if (self ? "lastModifiedDate") then - lib.concatStringsSep "-" [ - year - month - date - ] - else - "unknown"; -in - -stdenv.mkDerivation { - pname = "nmclauncher-unwrapped"; - version = "9.3-unstable-${date}"; - - src = lib.fileset.toSource { - root = ../.; - fileset = lib.fileset.unions [ - ../CMakeLists.txt - ../COPYING.md - - ../buildconfig - ../cmake - ../launcher - ../libraries - ../program_info - ../tests - ]; - }; - - postUnpack = '' - rm -rf source/libraries/libnbtplusplus - ln -s ${libnbtplusplus} source/libraries/libnbtplusplus - ''; - - nativeBuildInputs = [ - cmake - ninja - extra-cmake-modules - jdk17 - stripJavaArchivesHook - ]; - - buildInputs = - [ - cmark - ghc_filesystem - kdePackages.qtbase - kdePackages.qtnetworkauth - kdePackages.quazip - tomlplusplus - zlib - ] - ++ lib.optionals stdenv.hostPlatform.isDarwin [ darwin.apple_sdk.frameworks.Cocoa ] - ++ lib.optional gamemodeSupport gamemode; - - hardeningEnable = lib.optionals stdenv.hostPlatform.isLinux [ "pie" ]; - - cmakeFlags = - [ - # downstream branding - (lib.cmakeFeature "Launcher_BUILD_PLATFORM" "nixpkgs") - ] - ++ lib.optionals (msaClientID != null) [ - (lib.cmakeFeature "Launcher_MSA_CLIENT_ID" (toString msaClientID)) - ] - ++ lib.optionals (lib.versionOlder kdePackages.qtbase.version "6") [ - (lib.cmakeFeature "Launcher_QT_VERSION_MAJOR" "5") - ] - ++ lib.optionals stdenv.hostPlatform.isDarwin [ - # we wrap our binary manually - (lib.cmakeFeature "INSTALL_BUNDLE" "nodeps") - # disable built-in updater - (lib.cmakeFeature "MACOSX_SPARKLE_UPDATE_FEED_URL" "''") - (lib.cmakeFeature "CMAKE_INSTALL_PREFIX" "${placeholder "out"}/Applications/") - ]; - - doCheck = true; - - dontWrapQtApps = true; - - meta = { - description = "Free, open source launcher for Minecraft"; - longDescription = '' - Allows you to have multiple, separate instances of Minecraft (each with - their own mods, texture packs, saves, etc) and helps you manage them and - their associated options with a simple interface. - ''; - homepage = "https://github.com/sogik/NMCLauncher"; - license = lib.licenses.bsd3; - maintainers = with lib.maintainers; [ - Scrumplex - getchoo - ]; - mainProgram = "nmcauncher"; - platforms = lib.platforms.linux ++ lib.platforms.darwin; - }; -} diff --git a/nix/wrapper.nix b/nix/wrapper.nix deleted file mode 100644 index 95827b230..000000000 --- a/nix/wrapper.nix +++ /dev/null @@ -1,134 +0,0 @@ -{ - addDriverRunpath, - alsa-lib, - flite, - gamemode, - glfw3-minecraft, - jdk17, - jdk21, - jdk8, - kdePackages, - lib, - libGL, - libX11, - libXcursor, - libXext, - libXrandr, - libXxf86vm, - libjack2, - libpulseaudio, - libusb1, - mesa-demos, - openal, - pciutils, - pipewire, - nmclauncher-unwrapped, - stdenv, - symlinkJoin, - udev, - vulkan-loader, - xrandr, - - additionalLibs ? [ ], - additionalPrograms ? [ ], - controllerSupport ? stdenv.hostPlatform.isLinux, - gamemodeSupport ? stdenv.hostPlatform.isLinux, - jdks ? [ - jdk21 - jdk17 - jdk8 - ], - msaClientID ? null, - textToSpeechSupport ? stdenv.hostPlatform.isLinux, -}: - -assert lib.assertMsg ( - controllerSupport -> stdenv.hostPlatform.isLinux -) "controllerSupport only has an effect on Linux."; - -assert lib.assertMsg ( - textToSpeechSupport -> stdenv.hostPlatform.isLinux -) "textToSpeechSupport only has an effect on Linux."; - -let - nmclauncher' = nmclauncher-unwrapped.override { inherit msaClientID gamemodeSupport; }; -in - -symlinkJoin { - name = "nmclauncher-${nmclauncher'.version}"; - - paths = [ nmclauncher' ]; - - nativeBuildInputs = [ kdePackages.wrapQtAppsHook ]; - - buildInputs = - [ - kdePackages.qtbase - kdePackages.qtsvg - ] - ++ lib.optional ( - lib.versionAtLeast kdePackages.qtbase.version "6" && stdenv.hostPlatform.isLinux - ) kdePackages.qtwayland; - - postBuild = '' - wrapQtAppsHook - ''; - - qtWrapperArgs = - let - runtimeLibs = - [ - stdenv.cc.cc.lib - ## native versions - glfw3-minecraft - openal - - ## openal - alsa-lib - libjack2 - libpulseaudio - pipewire - - ## glfw - libGL - libX11 - libXcursor - libXext - libXrandr - libXxf86vm - - udev # oshi - - vulkan-loader # VulkanMod's lwjgl - ] - ++ lib.optional textToSpeechSupport flite - ++ lib.optional gamemodeSupport gamemode.lib - ++ lib.optional controllerSupport libusb1 - ++ additionalLibs; - - runtimePrograms = [ - mesa-demos - pciutils # need lspci - xrandr # needed for LWJGL [2.9.2, 3) https://github.com/LWJGL/lwjgl/issues/128 - ] ++ additionalPrograms; - - in - [ "--prefix PRISMLAUNCHER_JAVA_PATHS : ${lib.makeSearchPath "bin/java" jdks}" ] - ++ lib.optionals stdenv.hostPlatform.isLinux [ - "--set LD_LIBRARY_PATH ${addDriverRunpath.driverLink}/lib:${lib.makeLibraryPath runtimeLibs}" - "--prefix PATH : ${lib.makeBinPath runtimePrograms}" - ]; - - meta = { - inherit (nmclauncher'.meta) - description - longDescription - homepage - changelog - license - maintainers - mainProgram - platforms - ; - }; -} diff --git a/program_info/win_install.nsi.in b/program_info/win_install.nsi.in index dcc127099..83601df05 100644 --- a/program_info/win_install.nsi.in +++ b/program_info/win_install.nsi.in @@ -375,10 +375,10 @@ Section "@Launcher_DisplayName@" File "@Launcher_APP_BINARY_NAME@.exe" File "@Launcher_APP_BINARY_NAME@_filelink.exe" - File "@Launcher_APP_BINARY_NAME@_updater.exe" + File /nonfatal "@Launcher_APP_BINARY_NAME@_updater.exe" File "qt.conf" File "qtlogging.ini" - File *.dll + File /nonfatal *.dll File /r "iconengines" File /r "imageformats" File /r "jars"