From 875d495e8704bea6d448cb08f8158f7c34ec9385 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 4 Sep 2026 13:27:59 +0200 Subject: [PATCH 1/4] daft: add build-daft.yml for riscv64 wheels --- .github/workflows/build-daft.yml | 134 +++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 .github/workflows/build-daft.yml diff --git a/.github/workflows/build-daft.yml b/.github/workflows/build-daft.yml new file mode 100644 index 000000000..ab429afa8 --- /dev/null +++ b/.github/workflows/build-daft.yml @@ -0,0 +1,134 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `build` job of +# https://github.com/Eventual-Inc/Daft/blob/v0.7.24/.github/workflows/build-wheel.yml +name: Build daft wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'daft version to build (git tag without the leading v, e.g. 0.7.24)' + required: true + default: '0.7.24' + pull_request: + paths: + - '.github/workflows/build-daft.yml' + +concurrency: + group: ${{ github.workflow }}-${{ inputs.version || '0.7.24' }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + # `inputs.version` is empty on pull_request events; default to 0.7.24 there. + DAFT_VERSION: ${{ inputs.version || '0.7.24' }} + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + RUSTUP_MAX_RETRIES: 10 + # Limit parallel rustc invocations to avoid resource exhaustion on the + # riscv64 runner (build-lancedb.yml/build-polars-runtime.yml need the same). + CARGO_BUILD_JOBS: 2 + +jobs: + setup: + uses: $/.github/workflows/_setup.yml + + build_wheels: + needs: [setup] + name: Build daft ${{ inputs.version || '0.7.24' }} cp310-abi3-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + timeout-minutes: 1440 + + steps: + - name: Checkout Daft v${{ env.DAFT_VERSION }} + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + repository: Eventual-Inc/Daft + ref: v${{ env.DAFT_VERSION }} + persist-credentials: false + + # Upstream derives this from `setuptools_scm` and writes it into + # Cargo.toml before building (build-wheel.yml's "Patch package version" + # step) because their CI also builds untagged/nightly commits. We only + # ever build an exact release tag, so the version is already known; the + # workspace-wide placeholder is the only place it needs to land. + - name: Patch package version + run: | + awk -v ver="${DAFT_VERSION}" ' + /^\[workspace\.package\]/ { in_block=1 } + /^\[/ && !/^\[workspace\.package\]/ { in_block=0 } + in_block && /^version = / { print "version = \"" ver "\""; next } + { print } + ' Cargo.toml > Cargo.toml.new + mv Cargo.toml.new Cargo.toml + grep -qx "version = \"${DAFT_VERSION}\"" Cargo.toml + + - name: Free disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + + # Same OOM guard build-lancedb.yml/build-deltalake.yml need on these + # runners for a comparably sized Rust workspace. + - name: Set swap space + uses: pierotofy/set-swap-space@fc79b3f67fa8a838184ce84a674ca12238d2c761 # master + with: + swap-size-gb: 16 + + - name: Build wheel + uses: PyO3/maturin-action@e83996d129638aa358a18fbd1dfb82f0b0fb5d3b # v1.51.0 + with: + command: build + target: riscv64gc-unknown-linux-gnu + # pyo3 carries `abi3-py310` unconditionally in Cargo.toml, so + # upstream ships one cp310-abi3 wheel and no free-threaded variant; + # build on the floor interpreter the tag claims (gotcha 181). + # `rust-toolchain.toml` pins a nightly channel (daft-core and + # friends use unstable `#![feature(...)]`); maturin-action picks it + # up on its own, same as upstream's job does. + args: -i python3.10 --profile release --strip --out dist + manylinux: '2_39' + before-script-linux: | + git config --global --add safe.directory "*" + # The dashboard's `build.rs` requires Node/npm for release builds + # unless this is set, in which case it embeds an empty asset + # bundle instead; avoids needing a riscv64 Node toolchain for a + # bundled web dashboard nothing in the test suite exercises. + export CI=true + export DAFT_DASHBOARD_SKIP_BUILD=1 + env: + DAFT_ANALYTICS_ENABLED: '0' + + - name: Test wheel + run: | + python3 -m venv /tmp/daft-test-venv + source /tmp/daft-test-venv/bin/activate + pip install ray==2.58.0 pytest pandas==2.3.3 pytz numpy==2.3.4 pyarrow==25.0.1 dist/*.whl --force-reinstall + # `daft/` at the checkout root would otherwise shadow the installed + # wheel (same reason upstream's own test-wheels job removes it). + rm -rf daft + DAFT_ANALYTICS_ENABLED=0 DAFT_RUNNER=native python -m pytest tests/dataframe --durations=50 + DAFT_ANALYTICS_ENABLED=0 DAFT_RUNNER=ray python -m pytest tests/dataframe --durations=50 + env: + PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ + # Without it pip prefers PyPI's releases, which have no riscv64 + # wheel for these, and source-builds them in the container. + PIP_ONLY_BINARY: numpy,pandas,pyarrow,ray + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: daft-${{ env.DAFT_VERSION }}-cp310-abi3-manylinux_riscv64 + path: dist/*.whl + if-no-files-found: error + + publish: + name: Publish daft ${{ inputs.version || '0.7.24' }} + needs: [setup, build_wheels] + permissions: + contents: write + pull-requests: write + uses: $/.github/workflows/_publish-wheel.yml + with: + artifact-pattern: daft-${{ inputs.version || '0.7.24' }}-*-manylinux_riscv64 From 24c712fe1b4bb5bca032461978112599d7ba9ce3 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Fri, 4 Sep 2026 22:28:46 +0200 Subject: [PATCH 2/4] daft: test the wheel with uv instead of system pip System pip's vendored packaging library doesn't recognize the manylinux_2_39_riscv64 platform tag and rejects the wheel as "not a supported wheel on this platform"; uv's resolver does. --- .github/workflows/build-daft.yml | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-daft.yml b/.github/workflows/build-daft.yml index ab429afa8..55ed33bb5 100644 --- a/.github/workflows/build-daft.yml +++ b/.github/workflows/build-daft.yml @@ -101,11 +101,20 @@ jobs: env: DAFT_ANALYTICS_ENABLED: '0' + - name: Install Python + uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 + with: + python-version: '3.10' + activate-environment: true + enable-cache: false + + # The system `pip` on this runner predates riscv64 manylinux tag + # support and rejects the wheel as "not a supported wheel on this + # platform"; uv's resolver knows the tag (same reason + # build-polars-runtime.yml's "Test wheel" step uses uv too). - name: Test wheel run: | - python3 -m venv /tmp/daft-test-venv - source /tmp/daft-test-venv/bin/activate - pip install ray==2.58.0 pytest pandas==2.3.3 pytz numpy==2.3.4 pyarrow==25.0.1 dist/*.whl --force-reinstall + uv pip install ray==2.58.0 pytest pandas==2.3.3 pytz numpy==2.3.4 pyarrow==25.0.1 dist/*.whl --force-reinstall # `daft/` at the checkout root would otherwise shadow the installed # wheel (same reason upstream's own test-wheels job removes it). rm -rf daft From 47be82d1ff55b3244107c67c5ff60086a23e76a6 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sat, 5 Sep 2026 12:36:53 +0200 Subject: [PATCH 3/4] daft: drop the ray-runner test pass The only riscv64 ray build published anywhere is 2.58.0 (cp312/cp313/cp314 only), which exceeds the ray[data, client]<2.58.0,>=2.11.0 upper bound daft's own ray extra declares, so there is no ray build daft supports to test with. Switch the test venv to cp312 too, since that is now the floor our registry publishes riscv64 numpy/pandas/pyarrow builds for. --- .github/workflows/build-daft.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-daft.yml b/.github/workflows/build-daft.yml index 55ed33bb5..3fa5f36e1 100644 --- a/.github/workflows/build-daft.yml +++ b/.github/workflows/build-daft.yml @@ -104,7 +104,11 @@ jobs: - name: Install Python uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 with: - python-version: '3.10' + # cp312 is the floor our registry currently publishes riscv64 + # numpy/pandas/pyarrow builds compatible with daft's own extras + # bounds for (the abi3 wheel under test installs fine on any + # interpreter >= the cp310 floor it claims). + python-version: '3.12' activate-environment: true enable-cache: false @@ -112,19 +116,23 @@ jobs: # support and rejects the wheel as "not a supported wheel on this # platform"; uv's resolver knows the tag (same reason # build-polars-runtime.yml's "Test wheel" step uses uv too). + # Upstream's test-wheels job also runs this suite under `DAFT_RUNNER=ray`; + # that pass is dropped here because the only riscv64 ray build published + # anywhere is 2.58.0 (cp312/cp313/cp314 only), which exceeds the + # `ray[data, client]<2.58.0,>=2.11.0` upper bound daft's own `ray` + # extra declares, so there is no ray build daft supports to test with. - name: Test wheel run: | - uv pip install ray==2.58.0 pytest pandas==2.3.3 pytz numpy==2.3.4 pyarrow==25.0.1 dist/*.whl --force-reinstall + uv pip install pytest pandas==2.3.3 pytz numpy==2.3.4 pyarrow==25.0.1 dist/*.whl --force-reinstall # `daft/` at the checkout root would otherwise shadow the installed # wheel (same reason upstream's own test-wheels job removes it). rm -rf daft DAFT_ANALYTICS_ENABLED=0 DAFT_RUNNER=native python -m pytest tests/dataframe --durations=50 - DAFT_ANALYTICS_ENABLED=0 DAFT_RUNNER=ray python -m pytest tests/dataframe --durations=50 env: PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ # Without it pip prefers PyPI's releases, which have no riscv64 # wheel for these, and source-builds them in the container. - PIP_ONLY_BINARY: numpy,pandas,pyarrow,ray + PIP_ONLY_BINARY: numpy,pandas,pyarrow - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: From 2a56af4338faabfd83441b9e56abcc0affe75305 Mon Sep 17 00:00:00 2001 From: Ludovic Henry Date: Sun, 6 Sep 2026 09:36:57 +0200 Subject: [PATCH 4/4] daft: fix test-wheel step to use UV_* env vars, not PIP_* uv pip install only honors its own UV_EXTRA_INDEX_URL/UV_ONLY_BINARY, not the PIP_-prefixed names copied from cibuildwheel's pip-based test steps elsewhere in this repo. With those silently ignored, uv resolved pyarrow==25.0.1 against public PyPI only (no riscv64 wheel there) and source-built it, which needs the real Arrow C++ CMake package the manylinux image doesn't carry -- surfacing ~6.5h later as a CMake "could not find Arrow" configure error that looked like a missing native dependency of daft itself. Swap to UV_EXTRA_INDEX_URL/ UV_ONLY_BINARY and add UV_INDEX_STRATEGY=unsafe-best-match so uv actually reaches our registry's riscv64 pyarrow/numpy/pandas builds (same pattern as build-matplotlib.yml/build-onnx.yml). See CLAUDE.md gotcha 244. --- .github/workflows/build-daft.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-daft.yml b/.github/workflows/build-daft.yml index 3fa5f36e1..4a5495732 100644 --- a/.github/workflows/build-daft.yml +++ b/.github/workflows/build-daft.yml @@ -129,10 +129,19 @@ jobs: rm -rf daft DAFT_ANALYTICS_ENABLED=0 DAFT_RUNNER=native python -m pytest tests/dataframe --durations=50 env: - PIP_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ - # Without it pip prefers PyPI's releases, which have no riscv64 - # wheel for these, and source-builds them in the container. - PIP_ONLY_BINARY: numpy,pandas,pyarrow + # `uv pip install` (unlike cibuildwheel's pip-based test step) only + # honors its own UV_* env vars, not PIP_*; the PIP_-prefixed forms + # silently no-op, so uv skipped our registry, resolved pyarrow only + # against PyPI (no riscv64 wheel there) and source-built it, which + # needs the real Arrow C++ CMake package the manylinux image + # doesn't have (gotcha 244). `unsafe-best-match` is needed on top + # of the extra index because uv's default "first-index" strategy + # stops at the first index that lists the package name at all, + # never reaching our registry's riscv64 build (build-matplotlib.yml + # uses the same pair for the same reason). + UV_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/ + UV_INDEX_STRATEGY: unsafe-best-match + UV_ONLY_BINARY: numpy,pandas,pyarrow - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: