From 0797797b3506017190c23aa1bcbaf3280816e790 Mon Sep 17 00:00:00 2001 From: Harish Raja Selvan Date: Thu, 10 Sep 2026 15:12:58 +0530 Subject: [PATCH] ci: add Windows ARM64 build support --- .github/workflows/ci.yml | 10 ++++-- CMakeLists.txt | 2 +- python/tests/test_translator.py | 6 +++- ...prepare_build_environment_windows_arm64.sh | 31 +++++++++++++++++++ src/cpu/vec_neon.h | 2 +- 5 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 python/tools/prepare_build_environment_windows_arm64.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1611e2e79..f67c7d190 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -193,6 +193,8 @@ jobs: arch: arm64 - os: macos-15-intel arch: x86_64 + - os: windows-11-arm + arch: ARM64 steps: - uses: actions/checkout@v4 @@ -200,7 +202,7 @@ jobs: submodules: recursive - name: Cache MKL and oneDNN (Windows) - if: runner.os == 'Windows' + if: runner.os == 'Windows' && matrix.arch != 'ARM64' uses: actions/cache@v4 with: path: | @@ -219,7 +221,7 @@ jobs: CIBW_ENVIRONMENT_MACOS: "CTRANSLATE2_ROOT='/usr/local' MACOSX_DEPLOYMENT_TARGET=11.00" CIBW_BEFORE_ALL_LINUX: python/tools/prepare_build_environment_linux.sh CIBW_BEFORE_ALL_MACOS: python/tools/prepare_build_environment_macos.sh - CIBW_BEFORE_ALL_WINDOWS: bash python/tools/prepare_build_environment_windows.sh + CIBW_BEFORE_ALL_WINDOWS: bash python/tools/${{ matrix.arch == 'ARM64' && 'prepare_build_environment_windows_arm64.sh' || 'prepare_build_environment_windows.sh' }} CIBW_BEFORE_BUILD: pip install -r python/install_requirements.txt CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 @@ -299,6 +301,10 @@ jobs: artifact_pattern: python-wheels-macOS-arm64 wheel_pattern: "*cp312*macosx*arm64.whl" + - os: windows-11-arm + artifact_pattern: python-wheels-Windows-ARM64 + wheel_pattern: "*cp312*win_arm64.whl" + steps: - name: Set up Python 3.12 uses: actions/setup-python@v5 diff --git a/CMakeLists.txt b/CMakeLists.txt index 027d09420..783f138cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,7 +272,7 @@ macro(ct2_compile_kernels_for_isa isa flag) list(APPEND SOURCES ${CMAKE_CURRENT_BINARY_DIR}/kernels_${isa}.cc) endmacro() -if(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm64)|(aarch64)" +if(CMAKE_SYSTEM_PROCESSOR MATCHES "(arm64)|(aarch64)|(ARM64)" OR (APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")) add_definitions(-DCT2_ARM64_BUILD) set(CT2_BUILD_ARCH "arm64") diff --git a/python/tests/test_translator.py b/python/tests/test_translator.py index f76b78c31..736b808b9 100644 --- a/python/tests/test_translator.py +++ b/python/tests/test_translator.py @@ -68,7 +68,8 @@ def test_contains_model(tmp_dir): def test_get_supported_compute_types(): compute_types = ctranslate2.get_supported_compute_types("cpu") assert "float32" in compute_types - assert "int8" in compute_types + if "int8" not in compute_types: + pytest.skip("int8 compute type is not supported by this CPU backend") assert "int8_float32" in compute_types @@ -88,6 +89,9 @@ def test_compute_type(): with pytest.raises(TypeError, match="incompatible constructor arguments"): ctranslate2.Translator(model_path, compute_type=["int8", "int16"]) + if "int8" not in ctranslate2.get_supported_compute_types("cpu"): + pytest.skip("int8 compute type is not supported by this CPU backend") + translator = ctranslate2.Translator(model_path, compute_type="int8") assert translator.compute_type == "int8_float32" diff --git a/python/tools/prepare_build_environment_windows_arm64.sh b/python/tools/prepare_build_environment_windows_arm64.sh new file mode 100644 index 000000000..f1d99616c --- /dev/null +++ b/python/tools/prepare_build_environment_windows_arm64.sh @@ -0,0 +1,31 @@ +#! /bin/bash + +set -e +set -x +set -o pipefail + +OPENBLAS_VERSION=0.3.28 +OPENBLAS_ROOT="$PWD/openblas-install" + +curl --netrc-optional -L -o openblas.tar.gz https://github.com/OpenMathLib/OpenBLAS/releases/download/v${OPENBLAS_VERSION}/OpenBLAS-${OPENBLAS_VERSION}.tar.gz +tar xzf openblas.tar.gz +cd OpenBLAS-${OPENBLAS_VERSION} +( + cmake -G Ninja -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DTARGET=ARMV8 -DBINARY=64 -DNOFORTRAN=ON -DBUILD_WITHOUT_LAPACK=ON -DONLY_CBLAS=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="$OPENBLAS_ROOT" -B build . + cmake --build build --config Release --target install --parallel +) > /dev/null 2>&1 +cd .. +rm -rf OpenBLAS-${OPENBLAS_VERSION} openblas.tar.gz + +NPROC=$(nproc) + +mkdir build +cd build +cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=$CTRANSLATE2_ROOT -DWITH_MKL=OFF -DWITH_OPENBLAS=ON -DWITH_RUY=OFF -DOPENMP_RUNTIME=COMP -DOPENBLAS_INCLUDE_DIR="$OPENBLAS_ROOT/include/openblas" -DOPENBLAS_LIBRARY="$OPENBLAS_ROOT/lib/openblas.lib" -DBUILD_CLI=OFF .. +cmake --build . --config Release --target install --parallel $NPROC --verbose +cd .. +rm -r build + +cp README.md python/ +cp $CTRANSLATE2_ROOT/bin/ctranslate2.dll python/ctranslate2/ +cp "$OPENBLAS_ROOT/bin/openblas.dll" python/ctranslate2/ diff --git a/src/cpu/vec_neon.h b/src/cpu/vec_neon.h index 4a407a5f1..49be7ade3 100644 --- a/src/cpu/vec_neon.h +++ b/src/cpu/vec_neon.h @@ -160,7 +160,7 @@ namespace ctranslate2 { } static inline value_type round(value_type v) { -#ifdef __aarch64__ +#if defined(__aarch64__) || defined(_M_ARM64) return vrndiq_f32(v); #else float temp[4] = {std::nearbyintf(v[0]), std::nearbyintf(v[1]), std::nearbyintf(v[2]), std::nearbyintf(v[3])};