Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,39 @@ jobs:
cargo test --all
cargo test --all --all-features

check-emscripten:
name: Check compile for wasm32-unknown-emscripten
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# Keep toolchains in sync with the emscripten job in
# .github/workflows/wheels.yml:
# the 3.13 line's nightly override and the 3.14 line's
# pyodide-pinned stable (`pyodide config get rust_toolchain`).
include:
- rust-toolchain: nightly-2026-06-01
python-version: "3.13"
- rust-toolchain: "1.93.0"
python-version: "3.14"
steps:
- uses: actions/checkout@v4
with:
submodules: "recursive"

- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust-toolchain }}
targets: wasm32-unknown-emscripten

- uses: Swatinem/rust-cache@v2

- name: cargo check
run: cargo check --target wasm32-unknown-emscripten -p arro3-core -p arro3-compute --features pyo3/extension-module
env:
PYO3_CROSS_PYTHON_VERSION: ${{ matrix.python-version }}

check-features_pyo3_arrow:
runs-on: ubuntu-latest
strategy:
Expand Down
91 changes: 0 additions & 91 deletions .github/workflows/pyodide-wheels.yml

This file was deleted.

93 changes: 90 additions & 3 deletions .github/workflows/wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,93 @@ jobs:
name: wheels-macos-${{ matrix.platform.target }}-${{ matrix.module }}
path: dist

# PEP 783 emscripten wheels for Pyodide.
#
# The Rust toolchain, Emscripten version, rustflags, and platform tag are all
# defined by pyodide-build
emscripten:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.13", "3.14"]
module:
- arro3-core
- arro3-compute
include:
# Pyodide's pinned toolchain for Python 3.13 (nightly-2025-02-01,
# rustc 1.86) is very old. We override with a newer nightly
- python-version: "3.13"
rust-toolchain-override: nightly-2026-06-01
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
version: "0.9.x"
python-version: ${{ matrix.python-version }}

- name: Install pyodide-build
run: uv sync --only-group pyodide

- name: Get pyodide config
id: pyodide-config
run: |
{
echo "rust-toolchain=$(uv run --no-sync pyodide config get rust_toolchain)"
echo "pyodide-abi-version=$(uv run --no-sync pyodide config get pyodide_abi_version)"
echo "rustflags=$(uv run --no-sync pyodide config get rustflags)"
} >> "$GITHUB_OUTPUT"

# Install Emscripten via the Pyodide cross-build environment rather
# than a stock emsdk: this pins the Emscripten version matching the
# target Pyodide ABI, and applies Pyodide's patches to Emscripten,
# several of which affect dynamic linking of Rust side modules.
# https://github.com/pyodide/pyodide/tree/main/emsdk/patches
# https://github.com/kylebarron/arro3/pull/502#discussion_r3392470467
- name: Install emsdk (Pyodide xbuildenv)
env:
PYODIDE_XBUILDENV_PATH: ${{ github.workspace }}/.pyodide-xbuildenv
run: |
uv run --no-sync pyodide xbuildenv install
uv run --no-sync pyodide xbuildenv install-emscripten
# shellcheck disable=SC1090
source "$PYODIDE_XBUILDENV_PATH/$(uv run --no-sync pyodide xbuildenv version)/emsdk/emsdk_env.sh"
{
echo "EMSDK=$EMSDK"
echo "EMSDK_NODE=$EMSDK_NODE"
} >> "$GITHUB_ENV"
{
echo "$EMSDK"
echo "$EMSDK/upstream/emscripten"
dirname "$EMSDK_NODE"
} >> "$GITHUB_PATH"

- name: Build wheels
uses: PyO3/maturin-action@v1
env:
CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUSTFLAGS: ${{ steps.pyodide-config.outputs.rustflags }}
MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION: ${{ steps.pyodide-config.outputs.pyodide-abi-version }}
with:
target: wasm32-unknown-emscripten
rust-toolchain: ${{ matrix.rust-toolchain-override || steps.pyodide-config.outputs.rust-toolchain }}
args: --release --out dist -i ${{ matrix.python-version }} --manifest-path ${{ matrix.module }}/Cargo.toml
sccache: "true"

# PyPI rejects legacy emscripten_x_y_z tags; fail before upload if
# maturin didn't emit the PEP 783 pyemscripten tag.
- name: Verify platform tag
run: |
ls -lh dist/

- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-emscripten-py${{ matrix.python-version }}-${{ matrix.module }}
path: dist

sdist:
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -267,16 +354,16 @@ jobs:
# IMPORTANT: this permission is mandatory for trusted publishing
id-token: write
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
needs: [linux, musllinux, windows, macos]
needs: [linux, musllinux, windows, macos, emscripten]
steps:
- uses: actions/download-artifact@v4
with:
pattern: wheels-*-${{ matrix.module }}
merge-multiple: true
path: dist
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: 3.8
python-version: 3.13

- name: Publish package distributions to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
61 changes: 43 additions & 18 deletions DEVELOP.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,69 @@ uv run mkdocs serve

## Emscripten Python wheels

Install rust nightly and add wasm toolchain
Emscripten wheels (PEP 783) are built once per Python version. The entire
toolchain config (Rust toolchain, Emscripten version, ABI tag, rustflags) is
defined by `pyodide-build` *running under that same Python version* — e.g.
Python 3.13 maps to ABI `2025_0`/Emscripten 4.0.9 while Python 3.14 maps to
ABI `2026_0`/Emscripten 5.0.3. Use `uvx -p` to query the config for a given
Python version without touching the project venv:

```bash
rustup toolchain install nightly
rustup target add --toolchain nightly wasm32-unknown-emscripten
PYTHON_VERSION=3.14 # or 3.13
# The `pyodide` executable lives in pyodide-cli; most subcommands (config,
# xbuildenv) are plugins provided by pyodide-build, so both packages are
# needed.
pyodide_cmd() {
uvx -p "$PYTHON_VERSION" --from pyodide-cli --with pyodide-build pyodide "$@"
}
RUST_TOOLCHAIN=$(pyodide_cmd config get rust_toolchain)
PYODIDE_ABI_VERSION=$(pyodide_cmd config get pyodide_abi_version)
PYODIDE_RUSTFLAGS=$(pyodide_cmd config get rustflags)

echo "RUST_TOOLCHAIN: $RUST_TOOLCHAIN"
echo "PYODIDE_ABI_VERSION: $PYODIDE_ABI_VERSION"
echo "PYODIDE_RUSTFLAGS: $PYODIDE_RUSTFLAGS"
```

Install maturin and pyodide-build (choose a specific version of pyodide-build if desired)
Install the matching Rust toolchain and wasm target:

```bash
pip install -U maturin
pip install pyodide-build
rustup toolchain install $RUST_TOOLCHAIN
rustup target add --toolchain $RUST_TOOLCHAIN wasm32-unknown-emscripten
```

Clone emsdk. I clone this into a specific path at `~/github/emscripten-core/emsdk` so that it can be shared across projects.
Install Emscripten via the Pyodide cross-build environment rather than a
stock emsdk. This pins the Emscripten version matching the target Pyodide ABI
automatically, and applies [Pyodide's patches to
Emscripten](https://github.com/pyodide/pyodide/tree/main/emsdk/patches) —
several of which affect dynamic linking of Rust side modules:

```bash
mkdir -p ~/github/emscripten-core/
git clone https://github.com/emscripten-core/emsdk.git ~/github/emscripten-core/emsdk
# Or, set this manually
PYODIDE_EMSCRIPTEN_VERSION=$(pyodide config get emscripten_version)
~/github/emscripten-core/emsdk/emsdk install ${PYODIDE_EMSCRIPTEN_VERSION}
~/github/emscripten-core/emsdk/emsdk activate ${PYODIDE_EMSCRIPTEN_VERSION}
source ~/github/emscripten-core/emsdk/emsdk_env.sh
export PYODIDE_XBUILDENV_PATH="$HOME/.cache/pyodide-xbuildenv"
pyodide_cmd xbuildenv install
pyodide_cmd xbuildenv install-emscripten
source "$PYODIDE_XBUILDENV_PATH/$(pyodide_cmd xbuildenv version)/emsdk/emsdk_env.sh"
```

Build `arro3-core`:
Build `arro3-core`. `MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION` is required for the
wheel to get the PyPI-accepted `pyemscripten_*` platform tag instead of the
legacy `emscripten_x_y_z` tag PyPI rejects (this also needs a recent maturin,
hence `uvx maturin` rather than the project venv's maturin):

```bash
RUSTUP_TOOLCHAIN=nightly \
maturin build \
RUSTUP_TOOLCHAIN=$RUST_TOOLCHAIN \
CARGO_TARGET_WASM32_UNKNOWN_EMSCRIPTEN_RUSTFLAGS="$PYODIDE_RUSTFLAGS" \
MATURIN_PYEMSCRIPTEN_PLATFORM_VERSION=$PYODIDE_ABI_VERSION \
uvx maturin build \
--release \
-o dist \
-m arro3-core/Cargo.toml \
--target wasm32-unknown-emscripten \
-i python3.11
-i python$PYTHON_VERSION
```

Verify the wheel filename ends in `pyemscripten_${PYODIDE_ABI_VERSION}_wasm32.whl` before considering it publishable.

## Updating pyo3 version

It takes a few steps to update for a new pyo3 version. We have to do these steps in a specific order because of intertangled dependencies.
Expand Down
Loading
Loading