diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 51fb542ad0..97d0503327 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -69,6 +69,8 @@ jobs: script: ci/build_python.sh sha: ${{ inputs.sha }} sccache-dist-token-secret-name: GIST_REPO_READ_ORG_GITHUB_TOKEN + # Build a conda package for each CUDA x ARCH x minimum supported Python version + matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) upload-conda: needs: [cpp-build, python-build] secrets: inherit @@ -118,6 +120,8 @@ jobs: package-name: cuml package-type: python sccache-dist-token-secret-name: GIST_REPO_READ_ORG_GITHUB_TOKEN + # Build a wheel for each CUDA x ARCH x minimum supported Python version + matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) wheel-publish-cuml: needs: wheel-build-cuml secrets: inherit @@ -129,3 +133,4 @@ jobs: date: ${{ inputs.date }} package-name: cuml package-type: python + publish-wheel-search-key: cuml_wheel_python_abi3 diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 023581bde5..f468547774 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -279,6 +279,8 @@ jobs: with: build_type: pull-request script: ci/build_python.sh + # Build a conda package for each CUDA x ARCH x minimum supported Python version + matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) conda-python-tests-singlegpu: needs: [conda-python-build, changed-files] secrets: inherit @@ -390,6 +392,8 @@ jobs: package-name: cuml package-type: python sccache-dist-token-secret-name: GIST_REPO_READ_ORG_GITHUB_TOKEN + # Build a wheel for each CUDA x ARCH x minimum supported Python version + matrix_filter: group_by({CUDA_VER, ARCH}) | map(min_by(.PY_VER | split(".") | map(tonumber))) wheel-tests-cuml: needs: [wheel-build-cuml, changed-files] secrets: inherit diff --git a/build.sh b/build.sh index fac54ca02b..838736867f 100755 --- a/build.sh +++ b/build.sh @@ -85,6 +85,13 @@ BUILD_REPORT_INCL_CACHE_STATS=OFF # Set defaults for vars that may not have been defined externally INSTALL_PREFIX=${INSTALL_PREFIX:=${PREFIX:=${CONDA_PREFIX:=$LIBCUML_BUILD_DIR/install}}} PARALLEL_LEVEL=${PARALLEL_LEVEL:=$(nproc)} +PYTHON_ARGS_FOR_INSTALL=( + -v + --no-build-isolation + --no-deps + --config-settings + "rapidsai.disable-cuda=true" +) # Default to Ninja if generator is not specified export CMAKE_GENERATOR="${CMAKE_GENERATOR:=Ninja}" @@ -349,11 +356,17 @@ fi # Build and (optionally) install the cuml Python package if (! hasArg --configure-only) && (completeBuild || hasArg cuml || hasArg pydocs); then + # If `RAPIDS_PY_VERSION` is set, use that as the lower-bound for the stable ABI CPython version + if [ -n "${RAPIDS_PY_VERSION}" ]; then + RAPIDS_PY_API="cp${RAPIDS_PY_VERSION//./}" + PYTHON_ARGS_FOR_INSTALL+=("--config-settings" "skbuild.wheel.py-api=${RAPIDS_PY_API}") + fi + # Replace spaces with semicolons in SKBUILD_EXTRA_CMAKE_ARGS SKBUILD_EXTRA_CMAKE_ARGS=${SKBUILD_EXTRA_CMAKE_ARGS// /;} SKBUILD_CMAKE_ARGS="-DCMAKE_MESSAGE_LOG_LEVEL=${CMAKE_LOG_LEVEL};${SKBUILD_EXTRA_CMAKE_ARGS}" \ - python -m pip install --no-build-isolation --no-deps --config-settings rapidsai.disable-cuda=true "${REPODIR}"/python/cuml + python -m pip install "${PYTHON_ARGS_FOR_INSTALL[@]}" "${CUML_EXTRA_PYTHON_ARGS[@]}" "${REPODIR}"/python/cuml if hasArg pydocs; then cd "${REPODIR}"/docs diff --git a/ci/build_docs.sh b/ci/build_docs.sh index 7fdbc23a18..110e94d6fd 100755 --- a/ci/build_docs.sh +++ b/ci/build_docs.sh @@ -1,11 +1,11 @@ #!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: Apache-2.0 set -euo pipefail rapids-logger "Downloading artifacts from previous jobs" CPP_CHANNEL=$(rapids-download-conda-from-github cpp) -PYTHON_CHANNEL=$(rapids-download-conda-from-github python) +PYTHON_CHANNEL=$(rapids-download-from-github "$(rapids-package-name "conda_python" cuml --stable --cuda "${RAPIDS_CUDA_VERSION}")") rapids-logger "Create test conda environment" . /opt/conda/etc/profile.d/conda.sh diff --git a/ci/build_python.sh b/ci/build_python.sh index c053ddbd3e..ffa3264b7f 100755 --- a/ci/build_python.sh +++ b/ci/build_python.sh @@ -1,5 +1,5 @@ #!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: Apache-2.0 set -euo pipefail @@ -44,3 +44,6 @@ sccache --stop-server >/dev/null 2>&1 || true # remove build_cache directory to avoid uploading the entire source tree # tracked in https://github.com/prefix-dev/rattler-build/issues/1424 rm -rf "$RAPIDS_CONDA_BLD_OUTPUT_DIR"/build_cache + +RAPIDS_PACKAGE_NAME="$(rapids-package-name conda_python cuml --stable --cuda)" +export RAPIDS_PACKAGE_NAME diff --git a/ci/build_wheel.sh b/ci/build_wheel.sh index 79fcbad10e..0c4eb5bccd 100755 --- a/ci/build_wheel.sh +++ b/ci/build_wheel.sh @@ -6,6 +6,22 @@ set -euo pipefail package_name=$1 package_dir=$2 +shift 2 + +# Parse optional flags +stable_abi=false +while [[ $# -gt 0 ]]; do + case "$1" in + --stable) + stable_abi=true + shift + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac +done source rapids-configure-sccache source rapids-date-string @@ -28,6 +44,12 @@ RAPIDS_PIP_WHEEL_ARGS=( --no-deps --disable-pip-version-check ) + +# Add py-api setting for stable ABI builds +if [[ "${stable_abi}" == "true" ]] && [[ -n "${RAPIDS_PY_API:-}" ]]; then + RAPIDS_PIP_WHEEL_ARGS+=(--config-settings="skbuild.wheel.py-api=${RAPIDS_PY_API}") +fi + # Only use --build-constraint when build isolation is enabled. # # Passing '--build-constraint' and '--no-build-isolation` together results in an error from 'pip', diff --git a/ci/build_wheel_cuml.sh b/ci/build_wheel_cuml.sh index 38b42569a8..33b9da3e7f 100755 --- a/ci/build_wheel_cuml.sh +++ b/ci/build_wheel_cuml.sh @@ -34,8 +34,13 @@ EXCLUDE_ARGS=( --exclude "librmm.so" ) +# TODO: move this variable into `ci-wheel` +# Format Python limited API version string +RAPIDS_PY_API="cp${RAPIDS_PY_VERSION//./}" +export RAPIDS_PY_API + export SKBUILD_CMAKE_ARGS="-DDISABLE_DEPRECATION_WARNINGS=ON;-DSINGLEGPU=OFF;-DUSE_LIBCUML_WHEEL=ON" -./ci/build_wheel.sh "${package_name}" "${package_dir}" +./ci/build_wheel.sh "${package_name}" "${package_dir}" --stable # repair wheels and write to the location that artifact-uploading code expects to find them python -m auditwheel repair \ @@ -44,3 +49,6 @@ python -m auditwheel repair \ ${package_dir}/dist/* ./ci/validate_wheel.sh ${package_dir} "${RAPIDS_WHEEL_BLD_OUTPUT_DIR}" + +RAPIDS_PACKAGE_NAME="$(rapids-package-name wheel_python cuml --stable --cuda)" +export RAPIDS_PACKAGE_NAME diff --git a/ci/test_notebooks.sh b/ci/test_notebooks.sh index 36e2fb6a48..167874ff0f 100755 --- a/ci/test_notebooks.sh +++ b/ci/test_notebooks.sh @@ -10,7 +10,7 @@ conda config --set channel_priority strict rapids-logger "Downloading artifacts from previous jobs" CPP_CHANNEL=$(rapids-download-conda-from-github cpp) -PYTHON_CHANNEL=$(rapids-download-conda-from-github python) +PYTHON_CHANNEL=$(rapids-download-from-github "$(rapids-package-name "conda_python" cuml --stable --cuda "${RAPIDS_CUDA_VERSION}")") rapids-logger "Generate Notebook testing dependencies" rapids-dependency-file-generator \ diff --git a/ci/test_python_common.sh b/ci/test_python_common.sh index af07b7ae67..f8a023bb60 100644 --- a/ci/test_python_common.sh +++ b/ci/test_python_common.sh @@ -1,5 +1,5 @@ #!/bin/bash -# SPDX-FileCopyrightText: Copyright (c) 2022-2025, NVIDIA CORPORATION. +# SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION. # SPDX-License-Identifier: Apache-2.0 set -euo pipefail @@ -11,7 +11,7 @@ conda config --set channel_priority strict rapids-logger "Downloading artifacts from previous jobs" CPP_CHANNEL=$(rapids-download-conda-from-github cpp) -PYTHON_CHANNEL=$(rapids-download-conda-from-github python) +PYTHON_CHANNEL=$(rapids-download-from-github "$(rapids-package-name "conda_python" cuml --stable --cuda "${RAPIDS_CUDA_VERSION}")") rapids-logger "Generate Python testing dependencies" rapids-dependency-file-generator \ diff --git a/ci/test_wheel.sh b/ci/test_wheel.sh index 72a869f44a..75a07c5afd 100755 --- a/ci/test_wheel.sh +++ b/ci/test_wheel.sh @@ -7,7 +7,7 @@ set -euo pipefail source rapids-init-pip RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen "${RAPIDS_CUDA_VERSION}")" -CUML_WHEELHOUSE=$(RAPIDS_PY_WHEEL_NAME="cuml_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-github python) +CUML_WHEELHOUSE=$(rapids-download-from-github "$(rapids-package-name "wheel_python" cuml --stable --cuda "$RAPIDS_CUDA_VERSION")") LIBCUML_WHEELHOUSE=$(RAPIDS_PY_WHEEL_NAME="libcuml_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-github cpp) RAPIDS_TESTS_DIR=${RAPIDS_TESTS_DIR:-"${PWD}/test-results"} mkdir -p "${RAPIDS_TESTS_DIR}" diff --git a/ci/test_wheel_dask.sh b/ci/test_wheel_dask.sh index 014a24d714..bbdded3d08 100755 --- a/ci/test_wheel_dask.sh +++ b/ci/test_wheel_dask.sh @@ -7,7 +7,7 @@ set -euo pipefail source rapids-init-pip RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen "${RAPIDS_CUDA_VERSION}")" -CUML_WHEELHOUSE=$(RAPIDS_PY_WHEEL_NAME="cuml_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-github python) +CUML_WHEELHOUSE=$(rapids-download-from-github "$(rapids-package-name "wheel_python" cuml --stable --cuda "$RAPIDS_CUDA_VERSION")") LIBCUML_WHEELHOUSE=$(RAPIDS_PY_WHEEL_NAME="libcuml_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-github cpp) RAPIDS_TESTS_DIR=${RAPIDS_TESTS_DIR:-"${PWD}/test-results"} mkdir -p "${RAPIDS_TESTS_DIR}" diff --git a/ci/test_wheel_integrations.sh b/ci/test_wheel_integrations.sh index 387800ed94..f0ec76791b 100755 --- a/ci/test_wheel_integrations.sh +++ b/ci/test_wheel_integrations.sh @@ -7,7 +7,7 @@ set -euo pipefail source rapids-init-pip RAPIDS_PY_CUDA_SUFFIX="$(rapids-wheel-ctk-name-gen "${RAPIDS_CUDA_VERSION}")" -CUML_WHEELHOUSE=$(RAPIDS_PY_WHEEL_NAME="cuml_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-github python) +CUML_WHEELHOUSE=$(rapids-download-from-github "$(rapids-package-name "wheel_python" cuml --stable --cuda "$RAPIDS_CUDA_VERSION")") LIBCUML_WHEELHOUSE=$(RAPIDS_PY_WHEEL_NAME="libcuml_${RAPIDS_PY_CUDA_SUFFIX}" rapids-download-wheels-from-github cpp) RAPIDS_TESTS_DIR=${RAPIDS_TESTS_DIR:-"${PWD}/test-results"} mkdir -p "${RAPIDS_TESTS_DIR}" diff --git a/conda/recipes/cuml/recipe.yaml b/conda/recipes/cuml/recipe.yaml index 1933c97779..f88bfedb45 100644 --- a/conda/recipes/cuml/recipe.yaml +++ b/conda/recipes/cuml/recipe.yaml @@ -8,8 +8,9 @@ context: cuda_version: ${{ (env.get("RAPIDS_CUDA_VERSION") | split("."))[:2] | join(".") }} cuda_major: '${{ (env.get("RAPIDS_CUDA_VERSION") | split("."))[0] }}' date_string: '${{ env.get("RAPIDS_DATE_STRING") }}' - py_version: ${{ env.get("RAPIDS_PY_VERSION") }} - py_buildstring: ${{ py_version | version_to_buildstring }} + py_abi_min: ${{ env.get("RAPIDS_PY_VERSION") }} + py_buildstring : ${{ py_abi_min | version_to_buildstring }} + py_runtime_latest: "3.13" head_rev: '${{ git.head_rev(".")[:8] }}' package: @@ -20,7 +21,9 @@ source: path: ../../.. build: - string: cuda${{ cuda_major }}_py${{ py_buildstring }}_${{ date_string }}_${{ head_rev }} + python: + version_independent: true + string: cuda${{ cuda_major }}_cp${{ py_buildstring }}_abi3_${{ date_string }}_${{ head_rev }} files: exclude: - '*libarrow.so.*gdb.py' @@ -44,6 +47,7 @@ build: NVCC_APPEND_FLAGS: ${{ env.get("NVCC_APPEND_FLAGS", default="") }} PARALLEL_LEVEL: ${{ env.get("PARALLEL_LEVEL", default="8") }} RAPIDS_ARTIFACTS_DIR: ${{ env.get("RAPIDS_ARTIFACTS_DIR", default="") }} + RAPIDS_PY_VERSION: ${{ py_abi_min }} SCCACHE_BUCKET: ${{ env.get("SCCACHE_BUCKET", default="") }} SCCACHE_DIST_AUTH_TYPE: ${{ env.get("SCCACHE_DIST_AUTH_TYPE", default="token") }} SCCACHE_DIST_FALLBACK_TO_LOCAL_COMPILE: ${{ env.get("SCCACHE_DIST_FALLBACK_TO_LOCAL_COMPILE", default="false") }} @@ -78,7 +82,8 @@ requirements: - libcuml =${{ version }} - pip - pylibraft =${{ minor_version }} - - python =${{ py_version }} + - python =${{ py_abi_min }} + - python-abi3 ${{ py_abi_min }}.* - rapids-build-backend >=0.4.0,<0.5.0 - rapids-logger =0.2 - scikit-build-core>=0.11.0 @@ -113,6 +118,13 @@ requirements: - cuda-cudart - cuda-version +tests: + - python: + imports: + - cuml + python_version: ${{ py_runtime_latest }}.* + pip_check: false + about: homepage: ${{ load_from_file("python/cuml/pyproject.toml").project.urls.Homepage }} license: ${{ load_from_file("python/cuml/pyproject.toml").project.license }}