From bfd62a50f4de77cb04d4d8fcde6554ddc771ca04 Mon Sep 17 00:00:00 2001 From: Cheng Date: Wed, 21 Jan 2026 08:06:32 +0900 Subject: [PATCH] Windows CI (#3021) --- .github/actions/build-windows/action.yml | 18 ++++++++++++ .github/actions/setup-windows/action.yml | 37 ++++++++++++++++++++++++ .github/actions/test-windows/action.yml | 13 +++++++++ .github/workflows/build_and_test.yml | 12 ++++++++ CMakeLists.txt | 4 --- mlx/CMakeLists.txt | 12 ++++++++ mlx/backend/cpu/indexing.cpp | 2 +- mlx/backend/cpu/simd/base_simd.h | 15 +++++++++- 8 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 .github/actions/build-windows/action.yml create mode 100644 .github/actions/setup-windows/action.yml create mode 100644 .github/actions/test-windows/action.yml diff --git a/.github/actions/build-windows/action.yml b/.github/actions/build-windows/action.yml new file mode 100644 index 00000000..5de29583 --- /dev/null +++ b/.github/actions/build-windows/action.yml @@ -0,0 +1,18 @@ +name: 'Build on Windows' + +runs: + using: 'composite' + steps: + - name: Build CPP only + shell: cmd + env: + # For MSVC, Ninja/Release is the only config supported by ccache. + CMAKE_ARGS: >- + -G Ninja + -DCMAKE_BUILD_TYPE=Release + -DCMAKE_C_COMPILER=cl + -DCMAKE_CXX_COMPILER=cl + -DCMAKE_RC_COMPILER=rc + run: | + cmake . -B build %CMAKE_ARGS% + cmake --build build -j %NUMBER_OF_PROCESSORS% diff --git a/.github/actions/setup-windows/action.yml b/.github/actions/setup-windows/action.yml new file mode 100644 index 00000000..a7ea8c4f --- /dev/null +++ b/.github/actions/setup-windows/action.yml @@ -0,0 +1,37 @@ +name: 'Setup Windows environment' + +inputs: + python-version: + description: 'Version of python to set up' + required: false + default: '3.14' + use-ccache: + description: 'Whether to enable ccache' + required: false + default: 'true' + +runs: + using: 'composite' + steps: + - name: Use ccache + if: ${{ inputs.use-ccache == 'true' }} + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ccache-${{ runner.os }}-${{ runner.arch }}-cpu + max-size: 1GB + + - uses: actions/setup-python@v6 + with: + python-version: ${{ inputs.python-version }} + + - name: Setup Visual Studio cmd + shell: cmd + run: | + :: Find out path to VS. + pushd "C:\Program Files (x86)\Microsoft Visual Studio\Installer\" + for /f "delims=" %%x in ('.\vswhere.exe -latest -property InstallationPath') do set VSPATH=%%x + popd + :: Import VS vars. + call "%VSPATH%\VC\Auxiliary\Build\vcvarsall.bat" x64 + :: Export to all steps. + >>%GITHUB_ENV% set diff --git a/.github/actions/test-windows/action.yml b/.github/actions/test-windows/action.yml new file mode 100644 index 00000000..65d66ddb --- /dev/null +++ b/.github/actions/test-windows/action.yml @@ -0,0 +1,13 @@ +name: 'Run tests on Windows' + +runs: + using: 'composite' + steps: + - name: Run CPP tests - CPU + shell: bash + env: + DEVICE: cpu + run: | + echo "::group::CPP tests - CPU" + ./build/tests/tests -tce="*gguf*,test random uniform" + echo "::endgroup::" diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index d80a41bc..0fc09794 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -76,6 +76,18 @@ jobs: - uses: ./.github/actions/setup-macos - uses: ./.github/actions/build-macos + windows_build_and_test: + name: Windows (cpu, x86_64) + needs: check_lint + runs-on: windows-2025 + steps: + - uses: actions/checkout@v6 + - uses: ./.github/actions/setup-windows + with: + use-ccache: false + - uses: ./.github/actions/build-windows + - uses: ./.github/actions/test-windows + build_documentation: name: Build Documentation if: github.repository == 'ml-explore/mlx' diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ed30932..6e1301cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,10 +150,6 @@ cmake_policy(SET CMP0135 NEW) add_library(mlx) -# Supress warnings: note: parameter passing for argument of type -# ‘std::pair’ when C++17 is enabled changed to match C++14 in GCC -# 10.1 -target_compile_options(mlx PRIVATE -Wno-psabi) target_compile_options(mlx PUBLIC ${SANITIZER_COMPILE_FLAGS}) target_link_options(mlx PUBLIC ${SANITIZER_LINK_FLAGS}) diff --git a/mlx/CMakeLists.txt b/mlx/CMakeLists.txt index 66669a34..9dc58e78 100644 --- a/mlx/CMakeLists.txt +++ b/mlx/CMakeLists.txt @@ -24,9 +24,21 @@ add_library(mlx_version OBJECT ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp) target_compile_definitions(mlx_version PRIVATE MLX_VERSION="${MLX_VERSION}") target_link_libraries(mlx PRIVATE $) +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # Supress warnings: note: parameter passing for argument of type + # ‘std::pair’ when C++17 is enabled changed to match C++14 in + # GCC 10.1 + target_compile_options(mlx PRIVATE -Wno-psabi) +endif() + if(MSVC) # Disable some MSVC warnings to speed up compilation. target_compile_options(mlx PUBLIC /wd4068 /wd4244 /wd4267 /wd4804) + # Enable /bigobj for heavily templated code (e.g., binary.cpp) that exceeds + # the default 65,535 section limit in COFF object files. Use generator + # expression to only apply to C/CXX, not CUDA (NVCC doesn't understand /bigobj + # directly). + target_compile_options(mlx PRIVATE $<$:/bigobj>) endif() if(WIN32) diff --git a/mlx/backend/cpu/indexing.cpp b/mlx/backend/cpu/indexing.cpp index 47fb881a..a1b412c7 100644 --- a/mlx/backend/cpu/indexing.cpp +++ b/mlx/backend/cpu/indexing.cpp @@ -761,7 +761,7 @@ void masked_scatter_impl(const array& mask, const array& src, array& out) { const size_t mask_batch_size = mask.size() / batch_count; const size_t src_batch_size = src.size() / batch_count; - for (uint b = 0; b < batch_count; ++b) { + for (size_t b = 0; b < batch_count; ++b) { size_t src_consumed = 0; src_it.seek(b * src_batch_size); diff --git a/mlx/backend/cpu/simd/base_simd.h b/mlx/backend/cpu/simd/base_simd.h index fc9fbbff..51d078a2 100644 --- a/mlx/backend/cpu/simd/base_simd.h +++ b/mlx/backend/cpu/simd/base_simd.h @@ -6,6 +6,10 @@ #include #include +#ifdef _MSC_VER +#include // For _BitScanReverse +#endif + namespace mlx::core::simd { template struct Simd; @@ -105,7 +109,7 @@ Simd log1p(Simd in) { if (r == 0) { // handle underflow return Simd{T{x, theta}}; } - return Simd{T{((typeof(x))(0.5)) * std::log1p(r), theta}}; + return Simd{T{((decltype(x))(0.5)) * std::log1p(r), theta}}; } else { auto z0 = std::hypot(x + 1, y); return Simd{T{std::log(z0), theta}}; @@ -173,7 +177,16 @@ DEFAULT_BINARY(||) template Simd clz(Simd x_) { +#ifdef _MSC_VER + // MSVC doesn't have __builtin_clz, use _BitScanReverse instead + unsigned long index; + if (_BitScanReverse(&index, static_cast(x_.value))) { + return static_cast(31 - index); + } + return static_cast(32); // All zeros case +#else return __builtin_clz(x_.value); +#endif } template