diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index ad203ecfce..4792c59fb7 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -30,6 +30,7 @@ on: - 'version.inc' - ".github/workflows/build_*.yml" - 'build_linux.sh' + - 'build_release_vs.bat' - 'build_release_vs2022.bat' - 'build_release_macos.sh' - 'scripts/flatpak/**' @@ -76,11 +77,22 @@ jobs: build-deps-only: ${{ inputs.build-deps-only || false }} secrets: inherit build_windows: + name: Build Windows ${{ matrix.arch }} + strategy: + fail-fast: false + matrix: + include: + - arch: x64 + os: windows-latest + - arch: arm64 + os: windows-11-arm # Don't run scheduled builds on forks: if: ${{ !cancelled() && (github.event_name != 'schedule' || github.repository == 'OrcaSlicer/OrcaSlicer') }} uses: ./.github/workflows/build_check_cache.yml with: - os: ${{ vars.SELF_HOSTED && 'orca-win-server' || 'windows-latest' }} + # Self-hosted runner is x64-only; ARM64 always uses the GitHub-hosted runner. + os: ${{ (matrix.arch == 'x64' && vars.SELF_HOSTED) && 'orca-win-server' || matrix.os }} + arch: ${{ matrix.arch }} build-deps-only: ${{ inputs.build-deps-only || false }} force-build: ${{ github.event_name == 'schedule' }} secrets: inherit diff --git a/.github/workflows/build_check_cache.yml b/.github/workflows/build_check_cache.yml index 8d14fb325d..646a02dbf0 100644 --- a/.github/workflows/build_check_cache.yml +++ b/.github/workflows/build_check_cache.yml @@ -33,11 +33,12 @@ jobs: - name: set outputs id: set_outputs env: - # Keep macOS/Linux cache keys architecture-specific. amd64 Linux passes + # Keep macOS/Windows cache keys architecture-specific. amd64 Linux passes # no arch (key stays 'linux-clang', preserving the existing cache); # aarch64 gets its own 'linux-clang-aarch64' key. - cache-os: ${{ runner.os == 'macOS' && format('macos-{0}', inputs.arch) || (runner.os == 'Windows' && 'windows' || format('linux-clang{0}', inputs.arch && format('-{0}', inputs.arch) || '')) }} - dep-folder-name: ${{ runner.os == 'macOS' && format('/{0}', inputs.arch) || '/OrcaSlicer_dep' }} + cache-os: ${{ runner.os == 'macOS' && format('macos-{0}', inputs.arch) || (runner.os == 'Windows' && format('windows-{0}', inputs.arch) || format('linux-clang{0}', inputs.arch && format('-{0}', inputs.arch) || '')) }} + # ARM64 builds use the build-arm64 tree (see build_release_vs.bat); x64/other use build. + dep-folder-name: ${{ runner.os == 'macOS' && format('/{0}', inputs.arch) || (runner.os == 'Windows' && inputs.arch == 'arm64') && '-arm64/OrcaSlicer_dep' || '/OrcaSlicer_dep' }} output-cmd: ${{ runner.os == 'Windows' && '$env:GITHUB_OUTPUT' || '"$GITHUB_OUTPUT"'}} run: | echo cache-key=${{ env.cache-os }}-cache-orcaslicer_deps-build-${{ hashFiles('deps/**') }} >> ${{ env.output-cmd }} diff --git a/.github/workflows/build_deps.yml b/.github/workflows/build_deps.yml index 978d6f5d66..8b476c9290 100644 --- a/.github/workflows/build_deps.yml +++ b/.github/workflows/build_deps.yml @@ -45,11 +45,28 @@ jobs: key: ${{ inputs.cache-key }} - uses: lukka/get-cmake@latest + # The windows-11-arm runner needs CMake <= 3.31 (handled in the next step). + if: ${{ !(runner.os == 'Windows' && inputs.arch == 'arm64') }} with: cmakeVersion: "~4.3.0" # use most recent 4.3.x version useLocalCache: true # <--= Use the local cache (default is 'false'). useCloudCache: true + - name: Install CMake 3.31.x (Windows ARM64) + # windows-11-arm ships CMake 4.x, which removed pre-3.5 policy + # compatibility AND has incomplete ASM_ARMASM linker modules + # (breaks Boost.Context on ARM64). Pin to the last 3.x release. + if: runner.os == 'Windows' && inputs.arch == 'arm64' + shell: pwsh + run: | + $ver = "3.31.6" + $url = "https://github.com/Kitware/CMake/releases/download/v$ver/cmake-$ver-windows-arm64.zip" + Invoke-WebRequest -Uri $url -OutFile "$env:RUNNER_TEMP\cmake.zip" + Expand-Archive -Path "$env:RUNNER_TEMP\cmake.zip" -DestinationPath "$env:RUNNER_TEMP\cmake" -Force + $cmakeBin = "$env:RUNNER_TEMP\cmake\cmake-$ver-windows-arm64\bin" + if (-not (Test-Path "$cmakeBin\cmake.exe")) { throw "cmake.exe not found at $cmakeBin" } + Add-Content -Path $env:GITHUB_PATH -Value $cmakeBin + - name: setup dev on Windows if: runner.os == 'Windows' uses: microsoft/setup-msbuild@v3 @@ -65,6 +82,50 @@ jobs: shell: pwsh + - name: Install MSYS2 (clangarm64) with GMP/MPFR and LLVM tools + if: runner.os == 'Windows' && inputs.arch == 'arm64' + uses: msys2/setup-msys2@v2 + with: + msystem: CLANGARM64 + update: true + install: >- + mingw-w64-clang-aarch64-gmp + mingw-w64-clang-aarch64-mpfr + mingw-w64-clang-aarch64-llvm + + - name: Stage ARM64 GMP/MPFR (no prebuilt blobs exist for win-arm64) + # GMP/MPFR ship prebuilt x64/x86 blobs in-tree but none for ARM64. + # Pull them from MSYS2 clangarm64 and generate MSVC import libs via + # llvm-dlltool, then stage into deps/{GMP,MPFR}/.../win-arm64 where the + # MSVC branch of GMP.cmake/MPFR.cmake copies them into the dep prefix. + if: runner.os == 'Windows' && inputs.arch == 'arm64' + shell: msys2 {0} + run: | + set -euo pipefail + BIN=/clangarm64/bin + REPO=$(cygpath -u "$GITHUB_WORKSPACE") + + make_import_lib() { + local dll="$1"; local lib="$2"; local def="/tmp/${dll%.dll}.def" + echo "EXPORTS" > "$def" + llvm-readobj --coff-exports "$BIN/$dll" | awk '/Name: /{print $2}' >> "$def" + llvm-dlltool -m arm64 -D "$dll" -d "$def" -l "$BIN/$lib" + } + + make_import_lib libgmp-10.dll libgmp-10.lib + + # MPFR 4.x ships as libmpfr-6.dll; rename to libmpfr-4 BEFORE generating + # the import lib so the baked-in runtime DLL name is correct. + MPFR_DLL=$(ls $BIN/libmpfr-*.dll | head -1 | xargs basename) + if [ "$MPFR_DLL" != "libmpfr-4.dll" ]; then cp "$BIN/$MPFR_DLL" "$BIN/libmpfr-4.dll"; fi + make_import_lib libmpfr-4.dll libmpfr-4.lib + + mkdir -p $REPO/deps/GMP/gmp/lib/win-arm64 $REPO/deps/MPFR/mpfr/lib/win-arm64 + cp $BIN/libgmp-10.dll $BIN/libgmp-10.lib $REPO/deps/GMP/gmp/lib/win-arm64/ + cp $BIN/libmpfr-4.dll $BIN/libmpfr-4.lib $REPO/deps/MPFR/mpfr/lib/win-arm64/ + cp /clangarm64/include/gmp.h $REPO/deps/GMP/gmp/include/ + cp /clangarm64/include/mpfr.h $REPO/deps/MPFR/mpfr/include/ || true + # Build Dependencies - name: Build on Windows if: runner.os == 'Windows' @@ -73,8 +134,14 @@ jobs: if (-not "${{ vars.SELF_HOSTED }}") { choco install strawberryperl } - .\build_release_vs.bat deps - .\build_release_vs.bat pack + $arch = "${{ inputs.arch }}" + if ($arch -eq "arm64") { + .\build_release_vs.bat deps arm64 + .\build_release_vs.bat pack arm64 + } else { + .\build_release_vs.bat deps + .\build_release_vs.bat pack + } shell: pwsh - name: Build on Mac ${{ inputs.arch }} diff --git a/.github/workflows/build_orca.yml b/.github/workflows/build_orca.yml index aff9b79a85..fc406b09d5 100644 --- a/.github/workflows/build_orca.yml +++ b/.github/workflows/build_orca.yml @@ -50,11 +50,28 @@ jobs: fail-on-cache-miss: true - uses: lukka/get-cmake@latest + # The windows-11-arm runner needs CMake <= 3.31 (handled in the next step). + if: ${{ !(runner.os == 'Windows' && inputs.arch == 'arm64') }} with: cmakeVersion: "~4.3.0" # use most recent 4.3.x version useLocalCache: true # <--= Use the local cache (default is 'false'). useCloudCache: true + - name: Install CMake 3.31.x (Windows ARM64) + # windows-11-arm ships CMake 4.x, which removed pre-3.5 policy + # compatibility AND has incomplete ASM_ARMASM linker modules + # (breaks Boost.Context on ARM64). Pin to the last 3.x release. + if: runner.os == 'Windows' && inputs.arch == 'arm64' + shell: pwsh + run: | + $ver = "3.31.6" + $url = "https://github.com/Kitware/CMake/releases/download/v$ver/cmake-$ver-windows-arm64.zip" + Invoke-WebRequest -Uri $url -OutFile "$env:RUNNER_TEMP\cmake.zip" + Expand-Archive -Path "$env:RUNNER_TEMP\cmake.zip" -DestinationPath "$env:RUNNER_TEMP\cmake" -Force + $cmakeBin = "$env:RUNNER_TEMP\cmake\cmake-$ver-windows-arm64\bin" + if (-not (Test-Path "$cmakeBin\cmake.exe")) { throw "cmake.exe not found at $cmakeBin" } + Add-Content -Path $env:GITHUB_PATH -Value $cmakeBin + - name: Get the version and date on Ubuntu and macOS if: runner.os != 'Windows' run: | @@ -289,6 +306,18 @@ jobs: max_releases: 1 # Windows + - name: Set Windows build variables + if: runner.os == 'Windows' + shell: pwsh + run: | + if ("${{ inputs.arch }}" -eq "arm64") { + "BUILD_DIR=build-arm64" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8 + "ARCH_SUFFIX=_arm64" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8 + } else { + "BUILD_DIR=build" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8 + "ARCH_SUFFIX=" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8 + } + - name: setup MSVC if: runner.os == 'Windows' uses: microsoft/setup-msbuild@v3 @@ -306,23 +335,28 @@ jobs: # env: # WindowsSdkDir: 'C:\Program Files (x86)\Windows Kits\10\' # WindowsSDKVersion: '10.0.26100.0\' - run: .\build_release_vs.bat slicer + run: | + $arch = "${{ inputs.arch }}" + if ($arch -eq "arm64") { .\build_release_vs.bat slicer arm64 } else { .\build_release_vs.bat slicer } + shell: pwsh + # NSIS is x86-only; it runs (and the installer it emits runs) under ARM64's + # x86 emulation, packaging the native arm64 payload from build-arm64. - name: Create installer Win if: runner.os == 'Windows' && !vars.SELF_HOSTED - working-directory: ${{ github.workspace }}/build + working-directory: ${{ github.workspace }}/${{ env.BUILD_DIR }} run: | cpack -G NSIS - name: Pack app if: runner.os == 'Windows' - working-directory: ${{ github.workspace }}/build + working-directory: ${{ github.workspace }}/${{ env.BUILD_DIR }} shell: cmd - run: '"C:/Program Files/7-Zip/7z.exe" a -tzip OrcaSlicer_Windows_${{ env.ver }}_portable.zip ${{ github.workspace }}/build/OrcaSlicer' + run: '"C:/Program Files/7-Zip/7z.exe" a -tzip OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable.zip ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer' - name: Pack PDB - if: runner.os == 'Windows' && !vars.SELF_HOSTED - working-directory: ${{ github.workspace }}/build/src/Release + if: runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED + working-directory: ${{ github.workspace }}/${{ env.BUILD_DIR }}/src/Release shell: cmd run: '"C:/Program Files/7-Zip/7z.exe" a -m0=lzma2 -mx9 Debug_PDB_${{ env.ver }}_for_developers_only.7z *.pdb' @@ -330,25 +364,25 @@ jobs: if: runner.os == 'Windows' uses: actions/upload-artifact@v7 with: - name: OrcaSlicer_Windows_${{ env.ver }}_portable - path: ${{ github.workspace }}/build/OrcaSlicer + name: OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable + path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer - name: Upload artifacts Win installer if: runner.os == 'Windows' && !vars.SELF_HOSTED uses: actions/upload-artifact@v7 with: - name: OrcaSlicer_Windows_${{ env.ver }} - path: ${{ github.workspace }}/build/OrcaSlicer*.exe + name: OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }} + path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer*.exe - name: Upload artifacts Win PDB - if: runner.os == 'Windows' && !vars.SELF_HOSTED + if: runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED uses: actions/upload-artifact@v7 with: name: PDB path: ${{ github.workspace }}/build/src/Release/Debug_PDB_${{ env.ver }}_for_developers_only.7z - name: Upload OrcaSlicer_profile_validator Win - if: runner.os == 'Windows' && !vars.SELF_HOSTED + if: runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED uses: actions/upload-artifact@v7 with: name: OrcaSlicer_profile_validator_Windows_${{ env.ver }} @@ -360,8 +394,8 @@ jobs: with: upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label} release_id: 137995723 - asset_path: ${{ github.workspace }}/build/OrcaSlicer_Windows_${{ env.ver }}_portable.zip - asset_name: OrcaSlicer_Windows_nightly${{ env.nightly_suffix }}_portable.zip + asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_${{ env.ver }}${{ env.ARCH_SUFFIX }}_portable.zip + asset_name: OrcaSlicer_Windows${{ env.ARCH_SUFFIX }}_nightly${{ env.nightly_suffix }}_portable.zip asset_content_type: application/x-zip-compressed max_releases: 1 @@ -371,13 +405,13 @@ jobs: with: upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label} release_id: 137995723 - asset_path: ${{ github.workspace }}/build/OrcaSlicer_Windows_Installer_${{ env.ver }}.exe - asset_name: OrcaSlicer_Windows_Installer_nightly${{ env.nightly_suffix }}.exe + asset_path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_Installer_${{ env.ver }}.exe + asset_name: OrcaSlicer_Windows_Installer${{ env.ARCH_SUFFIX }}_nightly${{ env.nightly_suffix }}.exe asset_content_type: application/x-msdownload max_releases: 1 - name: Deploy Windows OrcaSlicer_profile_validator release - if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && runner.os == 'Windows' && !vars.SELF_HOSTED + if: github.repository == 'OrcaSlicer/OrcaSlicer' && github.ref == 'refs/heads/main' && runner.os == 'Windows' && inputs.arch != 'arm64' && !vars.SELF_HOSTED uses: WebFreak001/deploy-nightly@v3.2.0 with: upload_url: https://uploads.github.com/repos/OrcaSlicer/OrcaSlicer/releases/137995723/assets{?name,label} @@ -393,8 +427,9 @@ jobs: shell: pwsh run: | ./scripts/msix/build_msix.ps1 ` - -InstallDir "${{ github.workspace }}/build/OrcaSlicer" ` - -OutputPath "${{ github.workspace }}/build/OrcaSlicer_Windows_MSIX_${{ env.ver }}.msix" ` + -InstallDir "${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer" ` + -OutputPath "${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_MSIX_${{ env.ver }}${{ env.ARCH_SUFFIX }}.msix" ` + -Architecture "${{ inputs.arch }}" ` -IdentityName "${{ vars.ORCA_MSIX_IDENTITY_NAME || 'OrcaSlicer.OrcaSlicer' }}" ` -Publisher "${{ vars.ORCA_MSIX_PUBLISHER || 'CN=38F7EA55-C73B-4072-B3B2-C8E0EA15BB82' }}" ` -PublisherDisplayName "${{ vars.ORCA_MSIX_PUBLISHER_DISPLAY_NAME || 'OrcaSlicer' }}" @@ -403,8 +438,8 @@ jobs: if: runner.os == 'Windows' && !vars.SELF_HOSTED uses: actions/upload-artifact@v7 with: - name: OrcaSlicer_Windows_MSIX_${{ env.ver }} - path: ${{ github.workspace }}/build/OrcaSlicer_Windows_MSIX_${{ env.ver }}.msix + name: OrcaSlicer_Windows_MSIX_${{ env.ver }}${{ env.ARCH_SUFFIX }} + path: ${{ github.workspace }}/${{ env.BUILD_DIR }}/OrcaSlicer_Windows_MSIX_${{ env.ver }}${{ env.ARCH_SUFFIX }}.msix # Ubuntu - name: Apt-Install Dependencies diff --git a/build_release_vs.bat b/build_release_vs.bat index 3f1a2e0af4..0c1334d5f7 100644 --- a/build_release_vs.bat +++ b/build_release_vs.bat @@ -3,6 +3,17 @@ set WP=%CD% set _START_TIME=%TIME% +@REM Default target architecture to the host CPU arch; override by passing +@REM "x64" or "arm64" as an argument. PROCESSOR_ARCHITEW6432 covers a 32-bit +@REM shell running on a 64-bit OS, where PROCESSOR_ARCHITECTURE reads "x86". +set arch=x64 +if /I "%PROCESSOR_ARCHITECTURE%"=="ARM64" set arch=ARM64 +if /I "%PROCESSOR_ARCHITEW6432%"=="ARM64" set arch=ARM64 +if /I "%1"=="arm64" set arch=ARM64 +if /I "%2"=="arm64" set arch=ARM64 +if /I "%1"=="x64" set arch=x64 +if /I "%2"=="x64" set arch=x64 + @REM Check for Ninja Multi-Config option (-x) set USE_NINJA=0 for %%a in (%*) do ( @@ -68,12 +79,13 @@ echo Using CMake generator: %CMAKE_GENERATOR% @REM Pack deps if "%1"=="pack" ( - setlocal ENABLEDELAYEDEXPANSION + setlocal ENABLEDELAYEDEXPANSION cd %WP%/deps/build + if "%arch%"=="ARM64" cd %WP%/deps/build-arm64 for /f "tokens=2-4 delims=/ " %%a in ('date /t') do set build_date=%%c%%b%%a - echo packing deps: OrcaSlicer_dep_win64_!build_date!_vs!VS_VERSION!.zip + echo packing deps: OrcaSlicer_dep_win-!arch!_!build_date!_vs!VS_VERSION!.zip - %WP%/tools/7z.exe a OrcaSlicer_dep_win64_!build_date!_vs!VS_VERSION!.zip OrcaSlicer_dep + %WP%/tools/7z.exe a OrcaSlicer_dep_win-!arch!_!build_date!_vs!VS_VERSION!.zip OrcaSlicer_dep goto :done ) @@ -95,9 +107,10 @@ if "%debug%"=="ON" ( set build_dir=build ) ) -echo build type set to %build_type% +if "%arch%"=="ARM64" set build_dir=%build_dir%-arm64 +echo build type set to %build_type%, arch=%arch% -setlocal DISABLEDELAYEDEXPANSION +setlocal DISABLEDELAYEDEXPANSION cd deps mkdir %build_dir% cd %build_dir% @@ -116,7 +129,7 @@ if "%USE_NINJA%"=="1" ( cmake ../ -G %CMAKE_GENERATOR% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target deps ) else ( - cmake ../ -G %CMAKE_GENERATOR% -A x64 -DCMAKE_BUILD_TYPE=%build_type% + cmake ../ -G %CMAKE_GENERATOR% -A %arch% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target deps -- -m ) @echo off @@ -135,7 +148,7 @@ if "%USE_NINJA%"=="1" ( cmake .. -G %CMAKE_GENERATOR% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target ALL_BUILD ) else ( - cmake .. -G %CMAKE_GENERATOR% -A x64 -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type% + cmake .. -G %CMAKE_GENERATOR% -A %arch% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target ALL_BUILD -- -m ) @echo off diff --git a/build_release_vs2022.bat b/build_release_vs2022.bat index 4a5ae11277..32f39745e3 100644 --- a/build_release_vs2022.bat +++ b/build_release_vs2022.bat @@ -15,10 +15,18 @@ if "%1"=="pack" ( set debug=OFF set debuginfo=OFF +@REM Default target architecture to the host CPU arch; override with x64/arm64 arg. +set arch=x64 +if /I "%PROCESSOR_ARCHITECTURE%"=="ARM64" set arch=ARM64 +if /I "%PROCESSOR_ARCHITEW6432%"=="ARM64" set arch=ARM64 if "%1"=="debug" set debug=ON if "%2"=="debug" set debug=ON if "%1"=="debuginfo" set debuginfo=ON if "%2"=="debuginfo" set debuginfo=ON +if /I "%1"=="arm64" set arch=ARM64 +if /I "%2"=="arm64" set arch=ARM64 +if /I "%1"=="x64" set arch=x64 +if /I "%2"=="x64" set arch=x64 if "%debug%"=="ON" ( set build_type=Debug set build_dir=build-dbg @@ -31,7 +39,8 @@ if "%debug%"=="ON" ( set build_dir=build ) ) -echo build type set to %build_type% +if "%arch%"=="ARM64" set build_dir=%build_dir%-arm64 +echo build type set to %build_type%, arch=%arch% setlocal DISABLEDELAYEDEXPANSION cd deps @@ -48,7 +57,7 @@ echo "building deps.." echo on REM Set minimum CMake policy to avoid <3.5 errors set CMAKE_POLICY_VERSION_MINIMUM=3.5 -cmake ../ -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=%build_type% +cmake ../ -G "Visual Studio 17 2022" -A %arch% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target deps -- -m @echo off @@ -62,7 +71,7 @@ cd %build_dir% echo on set CMAKE_POLICY_VERSION_MINIMUM=3.5 -cmake .. -G "Visual Studio 17 2022" -A x64 -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type% +cmake .. -G "Visual Studio 17 2022" -A %arch% -DORCA_TOOLS=ON %SIG_FLAG% -DCMAKE_BUILD_TYPE=%build_type% cmake --build . --config %build_type% --target ALL_BUILD -- -m @echo off cd .. diff --git a/cmake/modules/FindGLEW.cmake b/cmake/modules/FindGLEW.cmake index 93e8ed89bf..e9ac3b6436 100644 --- a/cmake/modules/FindGLEW.cmake +++ b/cmake/modules/FindGLEW.cmake @@ -124,6 +124,8 @@ endif() if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "x64" OR "${CMAKE_GENERATOR}" MATCHES "Win64") set(_arch "x64") +elseif("${CMAKE_GENERATOR_PLATFORM}" MATCHES "ARM64") + set(_arch "x64") # GLEW ships one header set; ARM64 uses the x64 import path else() set(_arch "Win32") endif() diff --git a/deps/Boost/Boost.cmake b/deps/Boost/Boost.cmake index e8aebb1b92..bdd801857e 100644 --- a/deps/Boost/Boost.cmake +++ b/deps/Boost/Boost.cmake @@ -10,6 +10,15 @@ if (APPLE AND CMAKE_OSX_ARCHITECTURES) set(_context_arch_line "-DBOOST_CONTEXT_ARCHITECTURE:STRING=${CMAKE_OSX_ARCHITECTURES}") endif () +# Windows ARM64: Boost.Context's default fcontext implementation assembles .asm +# via armasm64, which trips a CMake ASM_ARMASM linker-module bug under the VS +# generator. The winfib implementation (Windows Fiber API) avoids assembly while +# keeping the Boost::context target that Boost.Asio's stackful coroutines need. +set(_context_impl_line "") +if (MSVC AND "${DEPS_ARCH}" STREQUAL "arm64") + set(_context_impl_line "-DBOOST_CONTEXT_IMPLEMENTATION:STRING=winfib") +endif () + set(_options "") if (MSVC AND DEP_DEBUG) set(_options "FORWARD_CONFIG") @@ -28,6 +37,7 @@ orcaslicer_add_cmake_project(Boost -DBOOST_IOSTREAMS_ENABLE_ZSTD:BOOL=OFF "${_context_abi_line}" "${_context_arch_line}" + "${_context_impl_line}" ) set(DEP_Boost_DEPENDS ZLIB) \ No newline at end of file diff --git a/deps/GMP/gmp/lib/win-arm64/libgmp-10.dll b/deps/GMP/gmp/lib/win-arm64/libgmp-10.dll new file mode 100644 index 0000000000..ea927b544e Binary files /dev/null and b/deps/GMP/gmp/lib/win-arm64/libgmp-10.dll differ diff --git a/deps/GMP/gmp/lib/win-arm64/libgmp-10.lib b/deps/GMP/gmp/lib/win-arm64/libgmp-10.lib new file mode 100644 index 0000000000..afc8909bbe Binary files /dev/null and b/deps/GMP/gmp/lib/win-arm64/libgmp-10.lib differ diff --git a/deps/MPFR/mpfr/lib/win-arm64/libmpfr-4.dll b/deps/MPFR/mpfr/lib/win-arm64/libmpfr-4.dll new file mode 100644 index 0000000000..b1188e25c0 Binary files /dev/null and b/deps/MPFR/mpfr/lib/win-arm64/libmpfr-4.dll differ diff --git a/deps/MPFR/mpfr/lib/win-arm64/libmpfr-4.lib b/deps/MPFR/mpfr/lib/win-arm64/libmpfr-4.lib new file mode 100644 index 0000000000..9031499e7d Binary files /dev/null and b/deps/MPFR/mpfr/lib/win-arm64/libmpfr-4.lib differ diff --git a/deps/OpenCV/OpenCV.cmake b/deps/OpenCV/OpenCV.cmake index 6a76c18137..d8c7cbac3b 100644 --- a/deps/OpenCV/OpenCV.cmake +++ b/deps/OpenCV/OpenCV.cmake @@ -1,4 +1,6 @@ -if (MSVC) +# Intel IPP / IPP-ICV is x86/x64 only — there is no ARM64 build, so enabling it +# leaves ~200 unresolved ippicv* externals at link time on Windows ARM64. +if (MSVC AND NOT "${DEPS_ARCH}" STREQUAL "arm64") set(_use_IPP "-DWITH_IPP=ON") if (DEP_DEBUG) set(_options "FORWARD_CONFIG") diff --git a/deps/OpenEXR/OpenEXR.cmake b/deps/OpenEXR/OpenEXR.cmake index dd754d3a38..72c924f50b 100644 --- a/deps/OpenEXR/OpenEXR.cmake +++ b/deps/OpenEXR/OpenEXR.cmake @@ -32,6 +32,17 @@ else() if (CMAKE_SYSTEM_NAME STREQUAL "Linux") set(_patch_cmd ${PATCH_CMD} ${CMAKE_CURRENT_LIST_DIR}/0001-OpenEXR-GCC13.patch) +elseif (MSVC AND "${DEPS_ARCH}" STREQUAL "arm64") + # Windows ARM64: OpenEXR 2.5.5 hard-codes IMF_HAVE_SSE2 for any MSVC + # (ImfSimd.h: `_MSC_VER >= 1300`), pulling in (x86-only) -> C1189. + # Patch the header to require an x86 target, and force the SSE cache vars off. + set(_patch_cmd ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/patch_openexr_arm64.cmake) + set(_openexr_arm64_args + -DOPENEXR_IMF_HAVE_SSE2:BOOL=OFF + -DOPENEXR_IMF_HAVE_SSSE3:BOOL=OFF + -DILMBASE_HAVE_SSE:BOOL=OFF + -DILMBASE_FORCE_DISABLE_INTEL_SSE:BOOL=ON + ) else () set(_patch_cmd "") endif () @@ -49,6 +60,7 @@ orcaslicer_add_cmake_project(OpenEXR -DPYILMBASE_ENABLE:BOOL=OFF -DOPENEXR_VIEWERS_ENABLE:BOOL=OFF -DOPENEXR_BUILD_UTILS:BOOL=OFF + ${_openexr_arm64_args} ) endif() diff --git a/deps/OpenEXR/patch_openexr_arm64.cmake b/deps/OpenEXR/patch_openexr_arm64.cmake new file mode 100644 index 0000000000..d660f2ab1d --- /dev/null +++ b/deps/OpenEXR/patch_openexr_arm64.cmake @@ -0,0 +1,29 @@ +# Applied as PATCH_COMMAND for OpenEXR 2.5.5 on Windows ARM64. +# +# Root cause of the ARM64 build failure: OpenEXR/IlmImf/ImfSimd.h hard-codes +# #if defined __SSE2__ || (_MSC_VER >= 1300 && !_M_CEE_PURE) +# #define IMF_HAVE_SSE2 1 +# #endif +# The `_MSC_VER >= 1300` arm is true for *every* MSVC, including ARM64, so +# IMF_HAVE_SSE2 gets defined and (an x86-only header) is pulled +# in -> error C1189. This is a pure-preprocessor decision, so no CMake cache +# variable can suppress it. Patch the header to also require an x86 target. + +set(_simd "OpenEXR/IlmImf/ImfSimd.h") +if(EXISTS "${_simd}") + file(READ "${_simd}" _content) + set(_old "#if defined __SSE2__ || (_MSC_VER >= 1300 && !_M_CEE_PURE)") + set(_new "#if (defined __SSE2__ || (_MSC_VER >= 1300 && !_M_CEE_PURE)) && (defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__))") + if(_content MATCHES "_M_IX86") + message(STATUS "[ARM64 patch] ImfSimd.h already guarded") + else() + string(REPLACE "${_old}" "${_new}" _patched "${_content}") + if(_patched STREQUAL _content) + message(FATAL_ERROR "[ARM64 patch] Failed to match SSE2 guard in ${_simd}") + endif() + file(WRITE "${_simd}" "${_patched}") + message(STATUS "[ARM64 patch] Guarded IMF_HAVE_SSE2 with x86 arch check in ${_simd}") + endif() +else() + message(FATAL_ERROR "[ARM64 patch] Not found: ${_simd}") +endif() diff --git a/deps/OpenSSL/OpenSSL.cmake b/deps/OpenSSL/OpenSSL.cmake index 5f463c14a9..21a49b91b8 100644 --- a/deps/OpenSSL/OpenSSL.cmake +++ b/deps/OpenSSL/OpenSSL.cmake @@ -6,7 +6,11 @@ if(DEFINED OPENSSL_ARCH) set(_cross_arch ${OPENSSL_ARCH}) else() if(WIN32) - set(_cross_arch "VC-WIN64A") + if("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "ARM64") + set(_cross_arch "VC-WIN64-ARM") + else() + set(_cross_arch "VC-WIN64A") + endif() elseif(APPLE) set(_cross_arch "darwin64-${CMAKE_OSX_ARCHITECTURES}-cc") endif() diff --git a/deps_src/imgui/imgui_widgets.cpp b/deps_src/imgui/imgui_widgets.cpp index 65f0bc5260..73eacf7f8d 100644 --- a/deps_src/imgui/imgui_widgets.cpp +++ b/deps_src/imgui/imgui_widgets.cpp @@ -267,7 +267,7 @@ void ImGui::Text(const char* fmt, ...) void ImGui::TextCentered(const char* text, ...) { va_list vaList; - va_start(vaList,&text); + va_start(vaList, text); float font_size = ImGui::GetFontSize() * strlen(text) / 2; ImGui::SameLine(ImGui::GetCursorPos().x / 2 - font_size + (font_size / 2)); diff --git a/scripts/msix/AppxManifest.xml b/scripts/msix/AppxManifest.xml index 56477bf80a..62b2216c5a 100644 --- a/scripts/msix/AppxManifest.xml +++ b/scripts/msix/AppxManifest.xml @@ -11,7 +11,7 @@ + ProcessorArchitecture="@MSIX_ARCH@" /> OrcaSlicer diff --git a/scripts/msix/build_msix.ps1 b/scripts/msix/build_msix.ps1 index 55e9fc156f..523e667bed 100644 --- a/scripts/msix/build_msix.ps1 +++ b/scripts/msix/build_msix.ps1 @@ -10,6 +10,8 @@ Requires the Windows SDK (makeappx.exe) unless -StageOnly is used. param( [string]$InstallDir = "build/OrcaSlicer", [string]$OutputPath = "build/OrcaSlicer_Windows_MSIX.msix", + [ValidateSet("x64", "arm64")] + [string]$Architecture = "x64", [string]$StagingDir = "", [switch]$StageOnly, [string]$IdentityName = "OrcaSlicer.OrcaSlicer", @@ -47,6 +49,7 @@ $manifest = $manifest.Replace('@MSIX_VERSION@', $msixVersion) $manifest = $manifest.Replace('@MSIX_IDENTITY_NAME@', $IdentityName) $manifest = $manifest.Replace('@MSIX_PUBLISHER@', $Publisher) $manifest = $manifest.Replace('@MSIX_PUBLISHER_DISPLAY_NAME@', $PublisherDisplayName) +$manifest = $manifest.Replace('@MSIX_ARCH@', $Architecture) Set-Content -Path (Join-Path $StagingDir 'AppxManifest.xml') -Value $manifest -Encoding utf8 if ($StageOnly) { @@ -54,11 +57,15 @@ if ($StageOnly) { return } -$makeappx = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.*\x64\makeappx.exe" -ErrorAction SilentlyContinue | +# makeappx is a host tool: x64 runners ship only x64, arm64 runners ship arm64. +# Pick the build host's architecture (not the target $Architecture, which only +# affects the manifest ProcessorArchitecture above). +$hostArch = switch ($env:PROCESSOR_ARCHITECTURE) { 'ARM64' { 'arm64' } 'x86' { 'x86' } default { 'x64' } } +$makeappx = Get-ChildItem "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.*\$hostArch\makeappx.exe" -ErrorAction SilentlyContinue | Sort-Object { [version]$_.Directory.Parent.Name } -Descending | Select-Object -First 1 -ExpandProperty FullName if (-not $makeappx) { - throw "makeappx.exe not found under '${env:ProgramFiles(x86)}\Windows Kits\10\bin' - install the Windows SDK" + throw "makeappx.exe not found under '${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.*\$hostArch' - install the Windows SDK" } Write-Output "Using makeappx: $makeappx" diff --git a/src/dev-utils/BaseException.cpp b/src/dev-utils/BaseException.cpp index d3f36fcc63..f33c8f635f 100644 --- a/src/dev-utils/BaseException.cpp +++ b/src/dev-utils/BaseException.cpp @@ -357,6 +357,12 @@ void CBaseException::ShowRegistorInformation(PCONTEXT pCtx) OutputString(_T("SS:RSP:%04X:%016llX RBP:%016llX\r\n"), pCtx->SegSs, pCtx->Rsp, pCtx->Rbp); OutputString(_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"), pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs); OutputString(_T("Flags:%08X\r\n"), pCtx->EFlags); +#elif defined(_M_ARM64) + OutputString(_T("\nRegisters:\r\n")); + OutputString(_T("PC:%016llX SP:%016llX FP:%016llX LR:%016llX\r\n"), + (unsigned long long)pCtx->Pc, (unsigned long long)pCtx->Sp, + (unsigned long long)pCtx->Fp, (unsigned long long)pCtx->Lr); + OutputString(_T("Cpsr:%08X\r\n"), pCtx->Cpsr); #endif OutputString( _T("\r\n") ); @@ -380,7 +386,11 @@ void CBaseException::ShowExceptionInformation() OutputString(_T("Param %d :0x%x \n"), i, m_pEp->ExceptionRecord->ExceptionInformation[i]); } OutputString(_T("Context :%p \n"), m_pEp->ContextRecord); +#if defined(_M_ARM64) + OutputString(_T("ContextFlag : 0x%x, Cpsr: 0x%x \n"), m_pEp->ContextRecord->ContextFlags, m_pEp->ContextRecord->Cpsr); +#else OutputString(_T("ContextFlag : 0x%x, EFlags: 0x%x \n"), m_pEp->ContextRecord->ContextFlags, m_pEp->ContextRecord->EFlags); +#endif TCHAR szFaultingModule[MAX_PATH]; DWORD section, offset; diff --git a/src/dev-utils/StackWalker.cpp b/src/dev-utils/StackWalker.cpp index 818ac3405e..468e8927a5 100644 --- a/src/dev-utils/StackWalker.cpp +++ b/src/dev-utils/StackWalker.cpp @@ -457,6 +457,15 @@ LPSTACKINFO CStackWalker::StackWalker(HANDLE hThread, const CONTEXT* context) sf.AddrBStore.Mode = AddrModeFlat; sf.AddrStack.Offset = c.IntSp; sf.AddrStack.Mode = AddrModeFlat; + // ARM64 +#elif defined(_M_ARM64) + imageType = IMAGE_FILE_MACHINE_ARM64; + sf.AddrPC.Offset = c.Pc; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrFrame.Offset = c.Fp; + sf.AddrFrame.Mode = AddrModeFlat; + sf.AddrStack.Offset = c.Sp; + sf.AddrStack.Mode = AddrModeFlat; #else #error "Platform not supported!" #endif diff --git a/src/libslic3r/Int128.hpp b/src/libslic3r/Int128.hpp index 8dc9e012dd..f8951f20f9 100644 --- a/src/libslic3r/Int128.hpp +++ b/src/libslic3r/Int128.hpp @@ -188,8 +188,9 @@ public: static inline Int128 multiply(int64_t lhs, int64_t rhs) { -#if defined(_MSC_VER) && defined(_WIN64) - // On Visual Studio 64bit, use the _mul128() intrinsic function. +#if defined(_MSC_VER) && defined(_M_X64) + // On Visual Studio x64, use the _mul128() intrinsic function. + // (ARM64 MSVC has no _mul128; it falls through to the portable path.) Int128 result; result.m_lo = (uint64_t)_mul128(lhs, rhs, &result.m_hi); return result; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 89e2338c55..b0c0af8c9d 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -743,6 +743,15 @@ void GUI_App::post_init() if (! this->initialized()) throw Slic3r::RuntimeError("Calling post_init() while not yet initialized"); +#if wxUSE_WEBVIEW_EDGE + // Ensure the Microsoft WebView2 runtime is installed before any WebView is + // created. The setup wizard and several dialogs render entirely through + // WebView2; without the runtime they come up blank. This runs here (not in the + // constructor) so that wxWidgets is fully initialized and the event loop is + // running, and so it precedes the first WebView creation (the setup wizard). + init_webview_runtime(); +#endif + m_open_method = "double_click"; bool switch_to_3d = false; @@ -1057,9 +1066,10 @@ GUI_App::GUI_App() //app config initializes early becasuse it is used in instance checking in OrcaSlicer.cpp this->init_app_config(); this->init_download_path(); -#if wxUSE_WEBVIEW_EDGE - this->init_webview_runtime(); -#endif + // Note: the WebView2 runtime check (init_webview_runtime) used to run here, but + // the constructor executes before wxWidgets is fully initialized and before the + // event loop starts, so its modal prompt/installer could silently fail to appear. + // It now runs in post_init(), before the first WebView (the setup wizard) is created. reset_to_active(); } @@ -2301,13 +2311,37 @@ void GUI_App::init_download_path() #if wxUSE_WEBVIEW_EDGE void GUI_App::init_webview_runtime() { - // Check WebView Runtime - if (!WebView::CheckWebViewRuntime()) { - int nRet = wxMessageBox(_L("Orca Slicer requires the Microsoft WebView2 Runtime to operate certain features.\nClick Yes to install it now."), - _L("WebView2 Runtime"), wxYES_NO); - if (nRet == wxYES) { - WebView::DownloadAndInstallWebViewRuntime(); - } + // Check whether the Microsoft WebView2 runtime is already present. + if (WebView::CheckWebViewRuntime()) { + BOOST_LOG_TRIVIAL(info) << "WebView2 runtime detected."; + return; + } + + BOOST_LOG_TRIVIAL(warning) << "WebView2 runtime not found; prompting user to install."; + int nRet = wxMessageBox(_L("Orca Slicer requires the Microsoft WebView2 Runtime to operate certain features.\nClick Yes to install it now."), + _L("WebView2 Runtime"), wxYES_NO); + if (nRet != wxYES) { + BOOST_LOG_TRIVIAL(warning) << "User declined WebView2 runtime installation."; + return; + } + + // The bootstrapper auto-detects the device architecture (x64/x86/ARM64) and + // installs the matching runtime. The install is synchronous, and because this + // runs before the first WebView is created, a successful install takes effect + // in this same process without a restart. + bool installed = WebView::DownloadAndInstallWebViewRuntime(); + + // Re-check: the install can still fail (declined UAC elevation, no network, + // etc.). Without the runtime the setup wizard and other WebView dialogs render + // blank, so surface an explicit message rather than failing silently. + if (installed && WebView::CheckWebViewRuntime()) { + BOOST_LOG_TRIVIAL(info) << "WebView2 runtime installed successfully."; + } else { + BOOST_LOG_TRIVIAL(error) << "WebView2 runtime installation failed or still not detected."; + wxMessageBox(_L("The Microsoft WebView2 Runtime could not be installed.\n" + "Some features, including the setup wizard, may appear blank until it is installed.\n" + "Please install it manually from https://developer.microsoft.com/microsoft-edge/webview2/ and restart Orca Slicer."), + _L("WebView2 Runtime"), wxOK | wxICON_WARNING); } } #endif diff --git a/src/slic3r/GUI/Widgets/WebView.cpp b/src/slic3r/GUI/Widgets/WebView.cpp index d31c168ded..1570ce9e0e 100644 --- a/src/slic3r/GUI/Widgets/WebView.cpp +++ b/src/slic3r/GUI/Widgets/WebView.cpp @@ -77,13 +77,16 @@ DWORD DownloadAndInstallWV2RT() { if (downloaded) { // Either Package the WebView2 Bootstrapper with your app or download it using fwlink // Then invoke install at Runtime. + // Keep the path string alive for the duration of the ShellExecuteExW call; + // assigning .c_str() of a temporary directly would leave lpFile dangling. + const std::wstring installer_path = target_file_path.generic_wstring(); SHELLEXECUTEINFOW shExInfo = {0}; shExInfo.cbSize = sizeof(shExInfo); shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS; shExInfo.hwnd = 0; shExInfo.lpVerb = L"runas"; - shExInfo.lpFile = target_file_path.generic_wstring().c_str(); - shExInfo.lpParameters = L" /install"; + shExInfo.lpFile = installer_path.c_str(); + shExInfo.lpParameters = L" /silent /install"; shExInfo.lpDirectory = 0; shExInfo.nShow = 0; shExInfo.hInstApp = 0; @@ -338,7 +341,11 @@ bool WebView::CheckWebViewRuntime() { wxWebViewFactoryEdge factory; auto wxVersion = factory.GetVersionInfo(wxVersionContext::RunTime); - return wxVersion.GetMajor() != 0; + bool present = wxVersion.GetMajor() != 0; + BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": WebView2 runtime " + << (present ? "found, version " : "not found (") + << wxVersion.ToString().ToUTF8().data() << (present ? "" : ")"); + return present; } bool WebView::DownloadAndInstallWebViewRuntime()