Wilcoxon refactor #409
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
| # https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries | |
| # https://github.com/pypa/cibuildwheel/blob/main/examples/github-deploy.yml | |
| name: Build and upload to PyPI | |
| on: | |
| workflow_dispatch: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| release: | |
| types: [published] | |
| jobs: | |
| build_wheels: | |
| name: Build wheels for ${{ matrix.os }}-cu${{ matrix.cuda_major }} | |
| runs-on: ${{ matrix.runs-on }} | |
| strategy: | |
| matrix: | |
| include: | |
| # CUDA 12 wheels (compiled with 12.2 for runtime 12.2+ compatibility) | |
| - os: linux-intel | |
| cuda_major: "12" | |
| runs-on: ubuntu-latest | |
| cibw_image: "ghcr.io/scverse/rapids_singlecell:manylinux_2_28_x86_64_cuda12.2" | |
| dockerfile: "docker/manylinux_2_28_x86_64_cuda12.2.Dockerfile" | |
| cuda_archs: "75-real;80-real;86-real;89-real;90" | |
| - os: linux-arm | |
| cuda_major: "12" | |
| runs-on: ubuntu-24.04-arm | |
| cibw_image: "ghcr.io/scverse/rapids_singlecell:manylinux_2_28_aarch64_cuda12.2" | |
| dockerfile: "docker/manylinux_2_28_aarch64_cuda12.2.Dockerfile" | |
| cuda_archs: "75-real;80-real;86-real;89-real;90" | |
| # CUDA 13 wheels (native Blackwell support) | |
| - os: linux-intel | |
| cuda_major: "13" | |
| runs-on: ubuntu-latest | |
| cibw_image: "ghcr.io/scverse/rapids_singlecell:manylinux_2_28_x86_64_cuda13.0" | |
| dockerfile: "docker/manylinux_2_28_x86_64_cuda13.0.Dockerfile" | |
| cuda_archs: "75-real;80-real;86-real;89-real;90-real;100-real;120" | |
| - os: linux-arm | |
| cuda_major: "13" | |
| runs-on: ubuntu-24.04-arm | |
| cibw_image: "ghcr.io/scverse/rapids_singlecell:manylinux_2_28_aarch64_cuda13.0" | |
| dockerfile: "docker/manylinux_2_28_aarch64_cuda13.0.Dockerfile" | |
| cuda_archs: "75-real;80-real;86-real;89-real;90-real;100-real;120" | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get version from setuptools-scm | |
| id: version | |
| run: | | |
| pip install setuptools-scm | |
| VERSION=$(python -m setuptools_scm) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Detected version: $VERSION" | |
| - name: Set package name, extras, and CUDA archs for CUDA ${{ matrix.cuda_major }} | |
| run: | | |
| python3 - ${{ matrix.cuda_major }} "${{ matrix.cuda_archs }}" <<'SCRIPT' | |
| import sys, pathlib | |
| cuda = sys.argv[1] | |
| cuda_archs = sys.argv[2] | |
| other = "13" if cuda == "12" else "12" | |
| path = pathlib.Path("pyproject.toml") | |
| text = path.read_text() | |
| def remove_toml_array(text, key): | |
| lines = text.splitlines(keepends=True) | |
| out = [] | |
| i = 0 | |
| while i < len(lines): | |
| if lines[i].startswith(f"{key} = ["): | |
| depth = lines[i].count("[") - lines[i].count("]") | |
| i += 1 | |
| while i < len(lines) and depth > 0: | |
| depth += lines[i].count("[") - lines[i].count("]") | |
| i += 1 | |
| continue | |
| out.append(lines[i]) | |
| i += 1 | |
| return "".join(out) | |
| # Rename package | |
| text = text.replace( | |
| 'name = "rapids-singlecell"', | |
| f'name = "rapids-singlecell-cu{cuda}"', | |
| ) | |
| # Rename matching extra to "rapids", remove the other | |
| text = text.replace(f'rapids-cu{cuda} = [', 'rapids = [') | |
| text = remove_toml_array(text, f"rapids-cu{other}") | |
| # librmm is needed at build time because CMake links the CUDA | |
| # extension against librmm. Add the matching wheel to the isolated | |
| # PEP 517 build requirements after selecting the CUDA package variant. | |
| for dep in ( | |
| f' "librmm-cu{other}>=25.10",\n', | |
| f' "rmm-cu{other}>=25.10",\n', | |
| ): | |
| text = text.replace(dep, "") | |
| rmm_build_req = f' "librmm-cu{cuda}>=25.10",\n' | |
| build_system_text = text.split("[project]", 1)[0] | |
| if f'"librmm-cu{cuda}>=25.10"' not in build_system_text: | |
| text = text.replace( | |
| ']\nbuild-backend = "scikit_build_core.build"', | |
| f'{rmm_build_req}]\nbuild-backend = "scikit_build_core.build"', | |
| 1, | |
| ) | |
| # Set CUDA architectures (replace "native" with CI target archs) | |
| text = text.replace( | |
| 'CMAKE_CUDA_ARCHITECTURES = "native"', | |
| f'CMAKE_CUDA_ARCHITECTURES = "{cuda_archs}"', | |
| ) | |
| path.write_text(text) | |
| # Verify | |
| for line in path.read_text().splitlines(): | |
| if "name" in line or "rapids" in line.lower() or "CUDA_ARCH" in line: | |
| print(line) | |
| SCRIPT | |
| - name: Sanity check pyproject.toml | |
| run: | | |
| python3 -c "import tomllib; tomllib.load(open('pyproject.toml', 'rb'))" | |
| grep -E "name|rapids|CUDA_ARCH" pyproject.toml | |
| - name: Build CUDA manylinux image | |
| run: | | |
| docker build -t "${{ matrix.cibw_image }}" -f "${{ matrix.dockerfile }}" docker | |
| - name: Build wheels | |
| uses: pypa/cibuildwheel@v3.1.4 | |
| env: | |
| SETUPTOOLS_SCM_PRETEND_VERSION: ${{ steps.version.outputs.version }} | |
| CIBW_BUILD: 'cp312-*' | |
| CIBW_SKIP: '*-musllinux*' | |
| CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.os == 'linux-intel' && matrix.cibw_image || '' }} | |
| CIBW_MANYLINUX_AARCH64_IMAGE: ${{ matrix.os == 'linux-arm' && matrix.cibw_image || '' }} | |
| CIBW_ENVIRONMENT_PASS_LINUX: SETUPTOOLS_SCM_PRETEND_VERSION | |
| CIBW_ENVIRONMENT: > | |
| CUDA_PATH=/usr/local/cuda | |
| LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH | |
| PATH=/usr/local/cuda/bin:$PATH | |
| CIBW_BEFORE_BUILD: > | |
| rm -f build/.librmm_dir && | |
| mkdir -p build && | |
| python -m pip install -U pip | |
| scikit-build-core cmake ninja nanobind | |
| librmm-cu${{ matrix.cuda_major }} && | |
| RMM_ROOT=$(python -c "import librmm; print(librmm.__path__[0])") && | |
| LOG_ROOT=$(python -c "import rapids_logger; print(rapids_logger.__path__[0])") && | |
| echo "[rsc-build] librmm=$RMM_ROOT" && | |
| echo "[rsc-build] rapids_logger=$LOG_ROOT" && | |
| ln -sf "$RMM_ROOT/lib64/librmm.so" /usr/local/lib/librmm.so && | |
| ln -sf "$LOG_ROOT/lib64/librapids_logger.so" /usr/local/lib/librapids_logger.so && | |
| ldconfig && | |
| python -c "import librmm; print(librmm.__path__[0])" > build/.librmm_dir && | |
| echo "[rsc-build] marker=$(cat build/.librmm_dir)" | |
| CIBW_TEST_SKIP: "*" | |
| CIBW_TEST_COMMAND: "" | |
| CIBW_REPAIR_WHEEL_COMMAND: "auditwheel repair --exclude libcublas.so.${{ matrix.cuda_major }} --exclude libcublasLt.so.${{ matrix.cuda_major }} --exclude libcudart.so.${{ matrix.cuda_major }} --exclude librmm.so --exclude librapids_logger.so -w {dest_dir} {wheel}" | |
| CIBW_BUILD_VERBOSITY: "1" | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: cibw-wheels-${{ matrix.os }}-cu${{ matrix.cuda_major }}-${{ strategy.job-index }} | |
| path: ./wheelhouse/*.whl | |
| build_sdist: | |
| name: Build source distribution | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Build sdist | |
| run: pipx run build --sdist | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: cibw-sdist | |
| path: dist/*.tar.gz | |
| upload_wheels: | |
| needs: [build_wheels] | |
| runs-on: ubuntu-latest | |
| environment: publish-cu${{ matrix.cuda_major }} | |
| permissions: | |
| id-token: write | |
| if: github.event_name == 'release' && github.event.action == 'published' | |
| strategy: | |
| matrix: | |
| cuda_major: ["12", "13"] | |
| steps: | |
| - uses: actions/download-artifact@v5 | |
| with: | |
| pattern: cibw-wheels-*-cu${{ matrix.cuda_major }}-* | |
| path: dist | |
| merge-multiple: true | |
| - uses: pypa/gh-action-pypi-publish@release/v1 | |
| upload_sdist: | |
| needs: [build_sdist] | |
| runs-on: ubuntu-latest | |
| environment: publish | |
| permissions: | |
| id-token: write | |
| if: github.event_name == 'release' && github.event.action == 'published' | |
| steps: | |
| - uses: actions/download-artifact@v5 | |
| with: | |
| name: cibw-sdist | |
| path: dist | |
| - uses: pypa/gh-action-pypi-publish@release/v1 |