From 438b7713dfbfa4ed79fb4e2fc3951b81fae413c3 Mon Sep 17 00:00:00 2001 From: Mugundan Date: Wed, 7 Oct 2026 08:47:43 +0530 Subject: [PATCH] Add CI support for publishing Windows ARM64 wheels --- .github/workflows/build-wheels.yml | 33 +++++++++++++--- cibw-scripts/before_all_windows.sh | 12 ++++++ cibw-scripts/setup_windows_arm64.ps1 | 56 ++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 cibw-scripts/setup_windows_arm64.ps1 diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 99c9231..7a0d04f 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -17,7 +17,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-14, macos-15-intel] + os: [ubuntu-latest, windows-latest, windows-11-arm, macos-14, macos-15-intel] steps: - name: Checkout code @@ -34,20 +34,33 @@ jobs: run: | echo "MACOSX_DEPLOYMENT_TARGET=$(sw_vers -productVersion | cut -d '.' -f 1-2)" >> $GITHUB_ENV # This does not work inside CIBW_BEFORE_ALL_MACOS; Without it, the wheel repair fails. - - - name: Windows - Set up pkg-config and CMake - if: runner.os == 'windows' + + - name: Windows - Install CMake & pkgconfig + if: runner.os == 'Windows' shell: bash run: | choco install cmake --version=3.31.5 --allow-downgrade -y --no-progress choco install -y --no-progress --stoponfirstfailure pkgconfiglite + + - name: Windows - Set x86-64 PKG_CONFIG_PATH + if: runner.os == 'Windows' && runner.arch == 'X64' + shell: bash + run: | echo "PKG_CONFIG_PATH=C:/mingw64/lib/pkgconfig" >> $GITHUB_ENV + - name: Windows ARM64 - Set up compilers and OpenBLAS + if: runner.os == 'Windows' && runner.arch == 'ARM64' + shell: pwsh + run: | + $VsVars = 'C:\Program Files\Microsoft Visual Studio\18\Enterprise\VC\Auxiliary\Build\vcvarsarm64.bat' + cmd /c "`"$VsVars`" && set" > "$env:RUNNER_TEMP\vcvars.txt" + ./cibw-scripts/setup_windows_arm64.ps1 + - name: Build wheels uses: pypa/cibuildwheel@v3.4.1 env: # All cibuildwheel options are here (nothing "hidden" in pyproject.toml) - CIBW_SKIP: "*-win32 *i686 cp3??t-*" + CIBW_SKIP: "*-win32 *i686 cp3??t-* cp310-win_arm64" CIBW_BUILD_FRONTEND: build CIBW_BUILD_VERBOSITY: 3 CIBW_TEST_REQUIRES: pytest scipy @@ -65,6 +78,14 @@ jobs: pip install delvewheel CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: | bash ./cibw-scripts/repair_wheel_command_windows.sh {wheel} {dest_dir} + CIBW_ENVIRONMENT_PASS_WINDOWS: > + CC + CXX + FC + AR + PKG_CONFIG_PATH + OPENBLAS_DIR + ODRPACK_WIN_ARM64 - name: Upload wheels uses: actions/upload-artifact@v6 @@ -127,4 +148,4 @@ jobs: # - uses: pypa/gh-action-pypi-publish@release/v1 # with: -# repository-url: https://test.pypi.org/legacy/ \ No newline at end of file +# repository-url: https://test.pypi.org/legacy/ diff --git a/cibw-scripts/before_all_windows.sh b/cibw-scripts/before_all_windows.sh index 92b5a01..4080c23 100644 --- a/cibw-scripts/before_all_windows.sh +++ b/cibw-scripts/before_all_windows.sh @@ -1,5 +1,17 @@ +#!/bin/bash set -xe +# ARM64: compilers (CC/CXX/FC) and OpenBLAS are already set up by +# cibw-scripts/setup_windows_arm64.ps1, so there is nothing to install here. +if [[ -n "${ODRPACK_WIN_ARM64:-}" ]]; then + clang-cl --version + flang-new --version + pkg-config --modversion openblas + exit 0 +fi + +# x86-64: install OpenBLAS via MSYS2/MinGW. + # Verify active compiler locations which gcc which gfortran diff --git a/cibw-scripts/setup_windows_arm64.ps1 b/cibw-scripts/setup_windows_arm64.ps1 new file mode 100644 index 0000000..d11f738 --- /dev/null +++ b/cibw-scripts/setup_windows_arm64.ps1 @@ -0,0 +1,56 @@ +$ErrorActionPreference = 'Stop' +$ProgressPreference = 'SilentlyContinue' +$LlvmVersion = '22.1.8' +$LlvmBin = 'C:\Program Files\LLVM\bin' +$LlvmInstaller = "$env:RUNNER_TEMP\LLVM-22.1.8-woa64.exe" +$LlvmUrl = "https://github.com/llvm/llvm-project/releases/download/llvmorg-$LlvmVersion/LLVM-$LlvmVersion-woa64.exe" +Invoke-WebRequest $LlvmUrl -UseBasicParsing -OutFile $LlvmInstaller +Start-Process -FilePath $LlvmInstaller -ArgumentList '/S' -Wait +$env:PATH = "$LlvmBin;$env:PATH" +$LlvmBin | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append +$LlvmRuntime = "$LlvmBin\..\lib\clang\22.1.8\lib\windows" +$FlangRuntime = "$LlvmBin\..\lib\clang\22\lib\aarch64-pc-windows-msvc" +$env:LIB = "$FlangRuntime;$LlvmRuntime;$env:LIB" +"LIB=$env:LIB" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append +@( + 'CC=clang-cl' + 'CXX=clang-cl' + 'FC=flang-new' + 'AR=llvm-ar' + 'ODRPACK_WIN_ARM64=1' +) | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + +$OpenBlasVersion = '0.3.34' +$OpenBlasDir = 'C:\openblas' +$zip = "$env:RUNNER_TEMP\openblas.zip" +$tmp = "$env:RUNNER_TEMP\openblas_extract" +$url = "https://github.com/OpenMathLib/OpenBLAS/releases/download/v$OpenBlasVersion/OpenBLAS-$OpenBlasVersion-woa64-64-dll.zip" +Invoke-WebRequest -Uri $url -OutFile $zip -UseBasicParsing + +# Extract to a temp dir, then flatten the top-level OpenBLAS folder +Expand-Archive -LiteralPath $zip -DestinationPath $tmp -Force +Move-Item "$tmp\OpenBLAS" $OpenBlasDir + +$pkgConfigDir = "$OpenBlasDir\lib\pkgconfig" +$prefix = $OpenBlasDir.Replace('\', '/') + +@" +libdir=$prefix/lib +libnameprefix= +libnamesuffix= +libsuffix= +includedir=$prefix/include/openblas + +Name: OpenBLAS +Description: OpenBLAS is an optimized BLAS library based on GotoBLAS2 1.13 BSD version +Version: $OpenBlasVersion +URL: https://github.com/OpenMathLib/OpenBLAS +Libs: -L`${libdir} -l`${libnameprefix}openblas`${libnamesuffix}`${libsuffix} +Cflags: -I`${includedir} +"@ | Set-Content -LiteralPath "$pkgConfigDir\openblas.pc" -Encoding ASCII +@( + "PKG_CONFIG_PATH=$($pkgConfigDir.Replace('\', '/'))" + "OPENBLAS_DIR=$OpenBlasDir" +) | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + +"$OpenBlasDir\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append