Build and Release to PyPI #9
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release to PyPI | |
| on: | |
| release: | |
| types: [published] # activate on published releases | |
| workflow_dispatch: # manual trigger | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-22.04, macos-latest] # macos-latest is ARM64 (currently macos-15) | |
| python: ["3.9", "3.10", "3.11", "3.12", "3.13"] | |
| runs-on: ${{ matrix.os }} | |
| env: | |
| CARGO_TERM_COLOR: always # nicer Cargo output | |
| steps: | |
| # 1. Check out sources (and submodules if libxsmm is vendored) | |
| - uses: actions/checkout@v4 | |
| with: { submodules: recursive } | |
| # 2. OS-specific prerequisites | |
| - name: Install Linux build deps | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y build-essential pkg-config patchelf | |
| # Install pre-built OpenBLAS (we link directly, no compilation!) | |
| sudo apt-get install -y libopenblas-dev | |
| # 3. Build static libxsmm on Linux | |
| - name: Build libxsmm (static) | |
| if: runner.os == 'Linux' | |
| run: | | |
| git clone --depth 1 https://github.com/libxsmm/libxsmm.git /tmp/libxsmm | |
| make -C /tmp/libxsmm STATIC=1 | |
| echo "LIBXSMM_DIR=/tmp/libxsmm" >> $GITHUB_ENV | |
| # 4. Toolchains | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| # 5. Install Python dependencies | |
| - name: Install Python build deps | |
| run: | | |
| pip install maturin numpy | |
| # Install auditwheel on Linux only | |
| if [ "$RUNNER_OS" = "Linux" ]; then | |
| pip install auditwheel | |
| fi | |
| # 6. Build the wheel | |
| - name: Build wheel with maturin | |
| env: | |
| RUSTFLAGS: ${{ runner.os == 'Linux' && '-L native=/tmp/libxsmm/lib' || '' }} | |
| run: | | |
| if [ "$RUNNER_OS" = "Linux" ]; then | |
| maturin build --release \ | |
| --compatibility pypi \ | |
| --features use-libxsmm \ | |
| -i python | |
| else | |
| maturin build --release \ | |
| --compatibility pypi \ | |
| -i python | |
| fi | |
| # 7. auditwheel repair (Linux only) | |
| - name: auditwheel repair | |
| if: runner.os == 'Linux' | |
| run: | | |
| mkdir -p dist | |
| for whl in target/wheels/*.whl; do | |
| auditwheel repair "$whl" --wheel-dir dist/ | |
| done | |
| # 8. Quick import-smoke-test | |
| - name: Smoke test wheel | |
| run: | | |
| # Install the wheel (prefer repaired wheel on Linux) | |
| if [ "$RUNNER_OS" = "Linux" ] && [ -d dist ]; then | |
| pip install --no-deps --force-reinstall dist/*.whl | |
| else | |
| pip install --no-deps --force-reinstall target/wheels/*.whl | |
| fi | |
| # Test import and basic functionality | |
| python << 'EOF' | |
| import maxsim_cpu | |
| import numpy as np | |
| print('MaxSim CPU imported successfully') | |
| # Basic functionality test | |
| q = np.random.randn(4, 128).astype(np.float32) | |
| q = q / np.linalg.norm(q, axis=1, keepdims=True) | |
| d = np.random.randn(2, 8, 128).astype(np.float32) | |
| d = d / np.linalg.norm(d, axis=2, keepdims=True) | |
| scores = maxsim_cpu.maxsim_scores(q, d) | |
| print(f'Test passed! Scores shape: {scores.shape}') | |
| assert scores.shape == (2,), f'Expected shape (2,), got {scores.shape}' | |
| EOF | |
| # 9. Upload artifacts | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheels-${{ matrix.os }}-${{ matrix.python }} | |
| path: | | |
| target/wheels/*.whl | |
| dist/*.whl | |
| if-no-files-found: error | |
| publish: | |
| name: Publish to PyPI | |
| needs: build | |
| runs-on: ubuntu-latest | |
| # Publish on both releases and manual workflow runs | |
| permissions: | |
| id-token: write # Required for PyPI trusted publishing via OIDC | |
| steps: | |
| - name: Download all wheels | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: wheels-* | |
| merge-multiple: true | |
| path: dist/ | |
| - name: List downloaded wheels | |
| run: | | |
| echo "Contents of dist/:" | |
| ls -la dist/ | |
| echo "All .whl files:" | |
| find . -name "*.whl" -type f | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| password: ${{ secrets.PYPI_TOKEN }} | |
| skip-existing: true | |
| verbose: true |