From dd515168f477d2a7384104f49ecf3dd7bba2172a Mon Sep 17 00:00:00 2001 From: prrao87 Date: Wed, 4 Nov 2026 20:15:47 -0500 Subject: [PATCH 1/3] ci: build and test Windows x86-64 wheels Windows users had only the sdist, which needs Rust and protoc. The wheel is built natively on windows-2022 with the same Haswell baseline as the Linux x86-64 wheel, tested on Python 3.12 to 3.14, and published with the others. --- .github/workflows/python-publish.yml | 48 +++++++++++++++++++++++++--- README.md | 2 +- RELEASE.md | 1 + python/.cargo/config.toml | 3 ++ python/README.md | 5 +-- python/pyproject.toml | 1 + 6 files changed, 52 insertions(+), 8 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 1eb73cf..58d175f 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,5 +1,5 @@ -# Build, test and publish lance-csr wheels: Linux x86-64 (manylinux_2_28) and native -# Apple Silicon (macOS arm64), plus an sdist for every other platform. +# Build, test and publish lance-csr wheels: Linux x86-64 (manylinux_2_28), native +# Apple Silicon (macOS arm64) and Windows x86-64, plus an sdist for every other platform. # # Pull requests that change how wheels are built (this workflow, the wheel check, the # release build profile) build and test them without publishing. A release builds and tests @@ -135,15 +135,52 @@ jobs: path: python/dist/*.whl if-no-files-found: error + build-windows: + runs-on: windows-2022 + timeout-minutes: 150 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - uses: astral-sh/setup-uv@v4 + + - name: Install build dependencies + run: choco install protoc --version=29.3 -y --no-progress + + - name: Build Windows x86-64 wheel + uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1 + with: + command: build + working-directory: python + target: x86_64-pc-windows-msvc + sccache: "true" + args: --release --locked --strip --out dist + + - name: Inspect wheel + working-directory: python + shell: bash + run: | + uvx twine check dist/*.whl + sha256sum dist/*.whl + + - uses: actions/upload-artifact@v4 + with: + name: python-dist-windows-x64 + path: python/dist/*.whl + if-no-files-found: error + test: # The wheels are abi3 (CPython 3.12+), so each platform's single wheel is tested on # every supported Python, in a clean environment with Rust removed from PATH: a wheel # that silently needed compiling would fail here. - needs: [build-linux, build-macos] + needs: [build-linux, build-macos, build-windows] strategy: fail-fast: false matrix: - os: [ubuntu-24.04, macos-15] + os: [ubuntu-24.04, macos-15, windows-2022] python: ["3.12", "3.13", "3.14"] runs-on: ${{ matrix.os }} timeout-minutes: 30 @@ -171,6 +208,7 @@ jobs: case "$RUNNER_OS" in Linux) wheel=$(ls "$PWD"/dist/*manylinux*.whl) ;; macOS) wheel=$(ls "$PWD"/dist/*macosx*.whl) ;; + Windows) wheel=$(cygpath -w "$(ls "$PWD"/dist/*win_amd64*.whl)") ;; esac # A fresh environment with the wheel and test tools; --no-build refuses any sdist. run=(uv run --isolated --no-project --no-build --python ${{ matrix.python }} @@ -181,7 +219,7 @@ jobs: "${run[@]}" python -I -m pytest "$RUNNER_TEMP/tests" -q -p no:cacheprovider publish: - needs: [build-linux, build-macos, test] + needs: [build-linux, build-macos, build-windows, test] if: > github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.mode == 'release') diff --git a/README.md b/README.md index bd64b03..6ebccd8 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ case needs distributed graph queries or graph algorithms, that's the kind of eng uv add lance-csr ``` -Prebuilt wheels cover Linux x86-64 and native Apple Silicon (CPython 3.12+); no Rust toolchain is needed. From +Prebuilt wheels cover Linux x86-64, native Apple Silicon and Windows x86-64 (CPython 3.12+); no Rust toolchain is needed. From Rust, run `cargo add lance-csr` and see the [Rust guide](https://lance-csr.hdclabs.ai/rust/). To build from source, see [`python/DEVELOPMENT.md`](python/DEVELOPMENT.md). diff --git a/RELEASE.md b/RELEASE.md index 7d0990d..88c9ce4 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -66,6 +66,7 @@ Publishing it starts `.github/workflows/python-publish.yml`: | --- | ---: | --- | | `build-linux` | about 22 min | manylinux_2_28 x86-64 wheel and the sdist | | `build-macos` | about 35 min | macOS arm64 wheel, built natively on `macos-15` | +| `build-windows` | not yet measured | Windows x86-64 wheel, built natively on `windows-2022` | | `test` | under 1 min each | each wheel on Python 3.12, 3.13 and 3.14 | | `publish` | seconds | checks the tag matches `python/pyproject.toml`, then uploads through PyPI trusted publishing | | `publish-crates` | about 10 to 15 min | after `publish`: packages and verifies `lance-csr`, then uploads it through crates.io trusted publishing | diff --git a/python/.cargo/config.toml b/python/.cargo/config.toml index 3c7937b..85ba3bc 100644 --- a/python/.cargo/config.toml +++ b/python/.cargo/config.toml @@ -25,5 +25,8 @@ rustflags = [ [target.x86_64-unknown-linux-gnu] rustflags = ["-C", "target-cpu=haswell", "-C", "target-feature=+avx2,+fma,+f16c"] +[target.x86_64-pc-windows-msvc] +rustflags = ["-C", "target-cpu=haswell", "-C", "target-feature=+avx2,+fma,+f16c"] + [target.aarch64-apple-darwin] rustflags = ["-C", "target-cpu=apple-m1", "-C", "target-feature=+neon,+fp16"] diff --git a/python/README.md b/python/README.md index 471d200..aab38d3 100644 --- a/python/README.md +++ b/python/README.md @@ -18,8 +18,9 @@ Or run a script with it, without a project: uv run --with lance-csr python your_script.py ``` -Prebuilt wheels are published for Linux x86-64 (glibc 2.28 or newer: RHEL 8, Ubuntu 20.04 and later) -and native Apple Silicon (macOS 11 or newer), for CPython 3.12 and later. Installing from a wheel needs +Prebuilt wheels are published for Linux x86-64 (glibc 2.28 or newer: RHEL 8, Ubuntu 20.04 and later), +native Apple Silicon (macOS 11 or newer) and Windows x86-64, for CPython 3.12 and later. The x86-64 +wheels need a CPU with AVX2 (Intel Haswell, AMD Excavator or newer). Installing from a wheel needs no Rust toolchain; to make sure uv never falls back to compiling from source, use: ```bash diff --git a/python/pyproject.toml b/python/pyproject.toml index d4c56d9..0cc57b7 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -17,6 +17,7 @@ classifiers = [ "Intended Audience :: Science/Research", "License :: OSI Approved :: Apache Software License", "Operating System :: MacOS", + "Operating System :: Microsoft :: Windows", "Operating System :: POSIX :: Linux", "Programming Language :: Python", "Programming Language :: Python :: 3", From 8828f30d7000c24759a0ea4b0f42ef8621a1743c Mon Sep 17 00:00:00 2001 From: prrao87 Date: Wed, 4 Nov 2026 21:10:55 -0500 Subject: [PATCH 2/3] ci: build the Windows wheel without sccache sccache's server closed its connection while compiling lance on windows-2022, failing the build. --- .github/workflows/python-publish.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 58d175f..226b66f 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -156,7 +156,8 @@ jobs: command: build working-directory: python target: x86_64-pc-windows-msvc - sccache: "true" + # sccache's Windows server dropped the connection mid-way through compiling lance. + sccache: "false" args: --release --locked --strip --out dist - name: Inspect wheel From a590a400f5ae5e207cc15d8e3a1984750b9e54cd Mon Sep 17 00:00:00 2001 From: prrao87 Date: Wed, 4 Nov 2026 22:04:38 -0500 Subject: [PATCH 3/3] ci: size the Windows wheel job from its first build It took 52 minutes without sccache, so it now has the same 90-minute timeout as the other builds and sets the release's critical path. --- .github/workflows/python-publish.yml | 2 +- RELEASE.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 226b66f..0261af4 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -137,7 +137,7 @@ jobs: build-windows: runs-on: windows-2022 - timeout-minutes: 150 + timeout-minutes: 90 steps: - uses: actions/checkout@v4 diff --git a/RELEASE.md b/RELEASE.md index 88c9ce4..2632d61 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -4,7 +4,7 @@ A release publishes the Python package to [PyPI](https://pypi.org/project/lance- `lance-csr` crate to [crates.io](https://crates.io/crates/lance-csr). PyPI publishing is automated from a GitHub release, and the crates follow once PyPI has the new version. -The whole release takes about 50 minutes: the macOS wheel build, then the crates. Don't add steps that build the +The whole release takes about 65 minutes: the Windows wheel build, then the crates. Don't add steps that build the release wheels a second time. ## Before you start @@ -66,7 +66,7 @@ Publishing it starts `.github/workflows/python-publish.yml`: | --- | ---: | --- | | `build-linux` | about 22 min | manylinux_2_28 x86-64 wheel and the sdist | | `build-macos` | about 35 min | macOS arm64 wheel, built natively on `macos-15` | -| `build-windows` | not yet measured | Windows x86-64 wheel, built natively on `windows-2022` | +| `build-windows` | about 52 min | Windows x86-64 wheel, built natively on `windows-2022` | | `test` | under 1 min each | each wheel on Python 3.12, 3.13 and 3.14 | | `publish` | seconds | checks the tag matches `python/pyproject.toml`, then uploads through PyPI trusted publishing | | `publish-crates` | about 10 to 15 min | after `publish`: packages and verifies `lance-csr`, then uploads it through crates.io trusted publishing |