Skip to content

Merge pull request #92 from m96-chan/feature/v0.2.10 #28

Merge pull request #92 from m96-chan/feature/v0.2.10

Merge pull request #92 from m96-chan/feature/v0.2.10 #28

Workflow file for this run

name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
test_only:
description: 'Test build without publishing'
type: boolean
default: false
jobs:
# Build source distribution
build-sdist:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1 # Shallow clone for faster checkout
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build
- name: Build sdist
run: python -m build --sdist
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: sdist
path: dist/*.tar.gz
# Build CUDA wheel for Linux (Python 3.12)
build-linux:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1 # Shallow clone for faster checkout
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Install CUDA Toolkit
uses: Jimver/cuda-toolkit@v0.2.29
with:
cuda: "13.0.2"
method: "network"
linux-local-args: '["--toolkit"]'
- name: Install build dependencies
run: |
python -m pip install --upgrade pip
pip install build scikit-build-core pybind11 ninja cmake auditwheel patchelf maturin
- name: Build Rust module
run: |
cd rust/pygpukit-python
maturin build --release --interpreter python
# Extract and copy the Rust extension to src/pygpukit/
cd ../target/wheels
unzip -o *.whl -d ../rust-extracted
find ../rust-extracted -name "_pygpukit_rust*.so" -exec cp {} ../../../src/pygpukit/ \;
ls -la ../../../src/pygpukit/*.so || true
env:
RUSTFLAGS: "" # Override -D warnings from setup-rust-toolchain
- name: Build wheel (C++ + Rust)
run: |
python -m build --wheel
env:
# PyGPUkit requires SM >= 80 (Ampere and newer)
# SM100/120 (Blackwell) supported with CUDA 13.x
CMAKE_CUDA_ARCHITECTURES: "80;86;89;90;100;120"
- name: Show wheel info before repair
run: |
ls -la dist/
echo "=== Extension modules in wheel ==="
python -m zipfile -l dist/*.whl | grep -E '\.so|\.pyd'
- name: Repair wheel with auditwheel
run: |
# Repair the wheel, excluding CUDA libraries (user must have CUDA driver)
auditwheel repair dist/*.whl \
--wheel-dir dist-repaired \
--exclude libcudart.so.12 \
--exclude libcuda.so.1 \
--exclude libnvrtc.so.12 \
--exclude libnvrtc-builtins.so.13.0 \
--plat manylinux_2_35_x86_64
# Replace original wheel with repaired one
rm dist/*.whl
mv dist-repaired/*.whl dist/
- name: Show wheel info after repair
run: |
ls -la dist/
echo "=== Extension modules in wheel ==="
python -m zipfile -l dist/*.whl | grep -E '\.so|\.pyd'
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: wheel-linux-py312
path: dist/*.whl
# Build CUDA wheel for Windows (Python 3.12)
build-windows:
runs-on: [self-hosted, Windows, X64, cuda]
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1 # Shallow clone for faster checkout
- name: Set up Python 3.12
shell: pwsh
run: |
pyenv install 3.12 --skip-existing
pyenv local 3.12
python --version
- name: Set up Rust
shell: pwsh
run: |
# Install rustup if not present
if (-not (Get-Command rustup -ErrorAction SilentlyContinue)) {
Write-Host "Installing rustup..."
Invoke-WebRequest -Uri https://win.rustup.rs/x86_64 -OutFile rustup-init.exe
.\rustup-init.exe -y --default-toolchain stable
Remove-Item rustup-init.exe
$env:PATH = "$env:USERPROFILE\.cargo\bin;$env:PATH"
}
rustup default stable
rustup update
rustc --version
cargo --version
- name: Clean previous builds
shell: pwsh
run: |
if (Test-Path dist) { Remove-Item -Recurse -Force dist }
if (Test-Path build) { Remove-Item -Recurse -Force build }
if (Test-Path rust/target) { Remove-Item -Recurse -Force rust/target }
Get-ChildItem -Filter "*.egg-info" -Directory | Remove-Item -Recurse -Force
- name: Install build dependencies
shell: pwsh
run: |
python -m pip install --upgrade pip
pip install build scikit-build-core pybind11 ninja cmake maturin
- name: Build Rust module
shell: pwsh
run: |
cd rust/pygpukit-python
maturin build --release --interpreter python
# Copy the built extension to src/pygpukit/
$wheel = Get-ChildItem ../target/wheels/*.whl | Select-Object -First 1
Expand-Archive -Path $wheel.FullName -DestinationPath ../target/rust-extracted -Force
$ext = Get-ChildItem ../target/rust-extracted/_pygpukit_rust*.pyd -Recurse | Select-Object -First 1
if ($ext) {
Copy-Item $ext.FullName ../../src/pygpukit/
Write-Host "Copied Rust extension: $($ext.Name)"
}
Get-ChildItem ../../src/pygpukit/*.pyd
- name: Build wheel (C++ + Rust)
shell: cmd
run: |
@REM Set up VS environment for cl.exe
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
@REM Use CUDA 13.1 for CUTLASS 4.x (SM100/SM120 Blackwell support)
@REM CUTLASS 4.3.3 requires CUDA 12.8+ due to constexpr dim3 usage
set "CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.1"
set "PATH=%CUDA_PATH%\bin;%PATH%"
python -m build --wheel
env:
# PyGPUkit requires SM >= 80 (Ampere and newer)
# CUDA 13.1+ required for CUTLASS 4.x (constexpr dim3 support)
CMAKE_CUDA_ARCHITECTURES: "80;86;89;90;100;120"
- name: Verify wheel contents
shell: pwsh
run: |
Get-ChildItem dist/*.whl | ForEach-Object {
Write-Host "Built: $($_.Name)"
Write-Host "=== Wheel contents ==="
python -m zipfile -l $_.FullName | Select-String -Pattern "\.pyd|\.so"
}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: wheel-windows-py312
path: dist/*.whl
# NOTE: Driver-only mode is now the default (v0.2.4+)
# All wheels are single-binary distribution - no separate driver-only test needed
# Publish to TestPyPI first
publish-testpypi:
runs-on: ubuntu-latest
needs: [build-linux, build-windows, build-sdist]
if: github.event_name == 'push' || !inputs.test_only
environment: testpypi
permissions:
id-token: write
steps:
- name: Download sdist
uses: actions/download-artifact@v4
with:
name: sdist
path: dist
- name: Download Linux wheel
uses: actions/download-artifact@v4
with:
name: wheel-linux-py312
path: dist
- name: Download Windows wheel
uses: actions/download-artifact@v4
with:
name: wheel-windows-py312
path: dist
- name: List dist contents
run: |
echo "=== Artifacts to publish ==="
ls -la dist/
- name: Publish to TestPyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true
# Publish to PyPI after TestPyPI succeeds
publish-pypi:
runs-on: ubuntu-latest
needs: publish-testpypi
if: github.event_name == 'push' || !inputs.test_only
environment: pypi
permissions:
id-token: write
steps:
- name: Download sdist
uses: actions/download-artifact@v4
with:
name: sdist
path: dist
- name: Download Linux wheel
uses: actions/download-artifact@v4
with:
name: wheel-linux-py312
path: dist
- name: Download Windows wheel
uses: actions/download-artifact@v4
with:
name: wheel-windows-py312
path: dist
- name: List dist contents
run: |
echo "=== Artifacts to publish ==="
ls -la dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
# Create GitHub Release
github-release:
runs-on: ubuntu-latest
needs: [build-sdist, build-linux, build-windows, publish-pypi]
if: github.event_name == 'push'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
fetch-depth: 1 # Shallow clone for faster checkout
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: dist/*
generate_release_notes: true