diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b19c6d6b98..b2b7e3b343 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -123,7 +123,6 @@ jobs: name: ${{ env.CUDA_CORE_ARTIFACT_NAME }} path: ${{ env.CUDA_CORE_ARTIFACTS_DIR }}/*.whl if-no-files-found: error - overwrite: 'true' - name: Set up mini CTK uses: ./.github/actions/fetch_ctk @@ -170,7 +169,35 @@ jobs: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}/*.whl if-no-files-found: error - overwrite: 'true' + + # upload-artifact's "overwrite: true" option has a race condition among parallel + # jobs, so we let job 0 do the work + - name: Build and check cuda-python wheel + if: ${{ strategy.job-index == 0 }} + run: | + pushd cuda_python + pip wheel -v --no-deps . + twine check *.whl + popd + + - name: List the cuda-python artifacts directory + if: ${{ strategy.job-index == 0 }} + run: | + if [[ "${{ matrix.host-platform }}" == win* ]]; then + export CHOWN=chown + else + export CHOWN="sudo chown" + fi + $CHOWN -R $(whoami) cuda_python/*.whl + ls -lahR cuda_python + + - name: Upload cuda-python build artifacts + if: ${{ strategy.job-index == 0 }} + uses: actions/upload-artifact@v4 + with: + name: cuda-python-wheel + path: cuda_python/*.whl + if-no-files-found: error - name: Pass environment variables to the next runner id: pass_env diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index f88e38bfbc..90d1cd05a2 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -70,6 +70,17 @@ jobs: echo "CUDA_BINDINGS_ARTIFACT_NAME=${CUDA_BINDINGS_ARTIFACT_BASENAME}-${{ github.sha }}" >> $GITHUB_ENV echo "CUDA_BINDINGS_ARTIFACTS_DIR=$(realpath "$REPO_DIR/cuda_bindings/dist")" >> $GITHUB_ENV + - name: Download cuda-python build artifacts + uses: actions/download-artifact@v4 + with: + name: cuda-python-wheel + path: . + + - name: Display structure of downloaded cuda-python artifacts + run: | + pwd + ls -lahR . + - name: Download cuda.bindings build artifacts uses: actions/download-artifact@v4 with: @@ -102,6 +113,8 @@ jobs: pip install *.whl popd + pip install cuda_python*.whl + - name: Build all (latest) docs id: build run: | diff --git a/.github/workflows/test-wheel.yml b/.github/workflows/test-wheel.yml index d1454d3227..652633d0b6 100644 --- a/.github/workflows/test-wheel.yml +++ b/.github/workflows/test-wheel.yml @@ -86,6 +86,13 @@ jobs: dependencies: "build-essential jq wget" dependent_exes: "gcc jq wget" + - name: Download cuda-python build artifacts + if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}} + uses: actions/download-artifact@v4 + with: + name: cuda-python-wheel + path: . + - name: Download cuda.bindings build artifacts if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '0'}} uses: actions/download-artifact@v4 @@ -93,7 +100,7 @@ jobs: name: ${{ env.CUDA_BINDINGS_ARTIFACT_NAME }} path: ${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }} - - name: Download cuda.bindings build artifacts from the prior branch + - name: Download cuda-python & cuda.bindings build artifacts from the prior branch if: ${{ env.SKIP_CUDA_BINDINGS_TEST == '1'}} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -120,6 +127,14 @@ jobs: mkdir -p "${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}" mv $OLD_BASENAME/*.whl "${{ env.CUDA_BINDINGS_ARTIFACTS_DIR }}"/ + gh run download $LATEST_PRIOR_RUN_ID -p cuda-python-wheel -R NVIDIA/cuda-python + mv cuda-python-wheel/*.whl . + + - name: Display structure of downloaded cuda-python artifacts + run: | + pwd + ls -lahR . + - name: Display structure of downloaded cuda.bindings artifacts run: | pwd @@ -203,3 +218,11 @@ jobs: pip install -r "tests/requirements-cu${TEST_CUDA_MAJOR}.txt" pytest -rxXs tests/ popd + + - name: Ensure cuda-python installable + run: | + if [[ "${{ inputs.local-ctk }}" == 1 ]]; then + pip install cuda_python*.whl + else + pip install $(ls cuda_python*.whl)[all] + fi diff --git a/cuda_bindings/cuda/bindings/_version.py b/cuda_bindings/cuda/bindings/_version.py index 0f781bd110..c144fb2cad 100644 --- a/cuda_bindings/cuda/bindings/_version.py +++ b/cuda_bindings/cuda/bindings/_version.py @@ -6,4 +6,4 @@ # this software and related documentation outside the terms of the EULA # is strictly prohibited. -__version__ = "12.6.2.post1" +__version__ = "12.6.3" diff --git a/cuda_bindings/pyproject.toml b/cuda_bindings/pyproject.toml index 7ea87f967a..6357b4064b 100644 --- a/cuda_bindings/pyproject.toml +++ b/cuda_bindings/pyproject.toml @@ -11,7 +11,7 @@ requires = ["setuptools", "cython", "pyclibrary"] build-backend = "setuptools.build_meta" [project] -name = "cuda-python" +name = "cuda-bindings" description = "Python bindings for CUDA" authors = [{name = "NVIDIA Corporation", email = "cuda-python-conduct@nvidia.com"},] license = {file = "LICENSE"} diff --git a/cuda_bindings/setup.py b/cuda_bindings/setup.py index 7c8725ee84..388827784c 100644 --- a/cuda_bindings/setup.py +++ b/cuda_bindings/setup.py @@ -308,9 +308,9 @@ def build_extension(self, ext): # Allow extensions to discover libraries at runtime # relative their wheels installation. if ext.name == "cuda.bindings._bindings.cynvrtc": - ldflag = f"-Wl,--disable-new-dtags,-rpath,$ORIGIN/../../../nvidia/cuda_nvrtc/lib" + ldflag = "-Wl,--disable-new-dtags,-rpath,$ORIGIN/../../../nvidia/cuda_nvrtc/lib" elif ext.name == "cuda.bindings._internal.nvjitlink": - ldflag = f"-Wl,--disable-new-dtags,-rpath,$ORIGIN/../../../nvidia/nvjitlink/lib" + ldflag = "-Wl,--disable-new-dtags,-rpath,$ORIGIN/../../../nvidia/nvjitlink/lib" else: ldflag = None @@ -326,7 +326,7 @@ def build_extension(self, ext): cmdclass = { "bdist_wheel": WheelsBuildExtensions, "build_ext": ParallelBuildExtensions, - } +} # ---------------------------------------------------------------------- # Setup diff --git a/cuda_bindings/tests/test_nvjitlink.py b/cuda_bindings/tests/test_nvjitlink.py index 4a2c1a6b03..000ef52e07 100644 --- a/cuda_bindings/tests/test_nvjitlink.py +++ b/cuda_bindings/tests/test_nvjitlink.py @@ -55,9 +55,7 @@ def ptx_header(version, arch): def check_nvjitlink_usable(): from cuda.bindings._internal import nvjitlink as inner_nvjitlink - if inner_nvjitlink._inspect_function_pointer("__nvJitLinkVersion") == 0: - return False - return True + return inner_nvjitlink._inspect_function_pointer("__nvJitLinkVersion") != 0 pytestmark = pytest.mark.skipif( diff --git a/cuda_core/cuda/core/experimental/_launcher.py b/cuda_core/cuda/core/experimental/_launcher.py index 91379d5744..91b6856da2 100644 --- a/cuda_core/cuda/core/experimental/_launcher.py +++ b/cuda_core/cuda/core/experimental/_launcher.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE -import importlib.metadata from dataclasses import dataclass from typing import Optional, Union @@ -11,7 +10,7 @@ from cuda.core.experimental._kernel_arg_handler import ParamHolder from cuda.core.experimental._module import Kernel from cuda.core.experimental._stream import Stream -from cuda.core.experimental._utils import CUDAError, check_or_create_options, handle_return +from cuda.core.experimental._utils import CUDAError, check_or_create_options, get_binding_version, handle_return # TODO: revisit this treatment for py313t builds _inited = False @@ -25,7 +24,7 @@ def _lazy_init(): global _use_ex # binding availability depends on cuda-python version - _py_major_minor = tuple(int(v) for v in (importlib.metadata.version("cuda-python").split(".")[:2])) + _py_major_minor = get_binding_version() _driver_ver = handle_return(cuda.cuDriverGetVersion()) _use_ex = (_driver_ver >= 11080) and (_py_major_minor >= (11, 8)) _inited = True diff --git a/cuda_core/cuda/core/experimental/_module.py b/cuda_core/cuda/core/experimental/_module.py index 5dc2801b7e..89f31b9f4d 100644 --- a/cuda_core/cuda/core/experimental/_module.py +++ b/cuda_core/cuda/core/experimental/_module.py @@ -2,10 +2,9 @@ # # SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE -import importlib.metadata from cuda import cuda -from cuda.core.experimental._utils import handle_return, precondition +from cuda.core.experimental._utils import get_binding_version, handle_return, precondition _backend = { "old": { @@ -30,7 +29,7 @@ def _lazy_init(): global _py_major_ver, _driver_ver, _kernel_ctypes # binding availability depends on cuda-python version - _py_major_ver = int(importlib.metadata.version("cuda-python").split(".")[0]) + _py_major_ver, _ = get_binding_version() if _py_major_ver >= 12: _backend["new"] = { "file": cuda.cuLibraryLoadFromFile, diff --git a/cuda_core/cuda/core/experimental/_utils.py b/cuda_core/cuda/core/experimental/_utils.py index 9cb47a33ef..b672b4acc3 100644 --- a/cuda_core/cuda/core/experimental/_utils.py +++ b/cuda_core/cuda/core/experimental/_utils.py @@ -3,6 +3,7 @@ # SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE import functools +import importlib.metadata from collections import namedtuple from typing import Callable, Dict @@ -134,3 +135,11 @@ def get_device_from_ctx(ctx_handle) -> int: assert ctx_handle == handle_return(cuda.cuCtxPopCurrent()) handle_return(cuda.cuCtxPushCurrent(prev_ctx)) return device_id + + +def get_binding_version(): + try: + major_minor = importlib.metadata.version("cuda-bindings").split(".")[:2] + except importlib.metadata.PackageNotFoundError: + major_minor = importlib.metadata.version("cuda-python").split(".")[:2] + return tuple(int(v) for v in major_minor) diff --git a/cuda_core/pyproject.toml b/cuda_core/pyproject.toml index 6573d91186..8d7bc74a98 100644 --- a/cuda_core/pyproject.toml +++ b/cuda_core/pyproject.toml @@ -47,9 +47,8 @@ dependencies = [ ] [project.optional-dependencies] -# TODO: change this once cuda-bindings is packaged, see NVIDIA/cuda-python#105 -cu11 = ["cuda-python==11.8.*"] -cu12 = ["cuda-python==12.*"] +cu11 = ["cuda-bindings==11.8.*"] +cu12 = ["cuda-bindings==12.*"] [project.urls] homepage = "https://nvidia.github.io/cuda-python/" diff --git a/cuda_python/LICENSE b/cuda_python/LICENSE new file mode 120000 index 0000000000..ea5b60640b --- /dev/null +++ b/cuda_python/LICENSE @@ -0,0 +1 @@ +../LICENSE \ No newline at end of file diff --git a/cuda_python/README.md b/cuda_python/README.md new file mode 120000 index 0000000000..32d46ee883 --- /dev/null +++ b/cuda_python/README.md @@ -0,0 +1 @@ +../README.md \ No newline at end of file diff --git a/cuda_python/pyproject.toml b/cuda_python/pyproject.toml new file mode 100644 index 0000000000..9566bcf924 --- /dev/null +++ b/cuda_python/pyproject.toml @@ -0,0 +1,41 @@ +# Copyright 2023-2025 NVIDIA Corporation. All rights reserved. +# +# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE + +[build-system] +requires = ["setuptools",] +build-backend = "setuptools.build_meta" + +[project] +name = "cuda-python" +description = "CUDA Python: Performance meets Productivity" +readme = {file = "README.md", content-type = "text/markdown"} +authors = [{name = "NVIDIA Corporation", email = "cuda-python-conduct@nvidia.com"},] +license = {file = "LICENSE"} +classifiers = [ + "Operating System :: POSIX :: Linux", + "Operating System :: Microsoft :: Windows", + "Topic :: Software Development :: Libraries", + "Topic :: Education", + "Topic :: Scientific/Engineering", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Intended Audience :: End Users/Desktop", + "License :: Other/Proprietary License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", + "Environment :: GPU :: NVIDIA CUDA", + "Environment :: GPU :: NVIDIA CUDA :: 12", +] +dynamic = ["version", "dependencies", "optional-dependencies"] + +[project.urls] +homepage = "https://nvidia.github.io/cuda-python/" +documentation = "https://nvidia.github.io/cuda-python/" +repository = "https://github.com/NVIDIA/cuda-python/" +issues = "https://github.com/NVIDIA/cuda-python/issues/" diff --git a/cuda_python/setup.py b/cuda_python/setup.py new file mode 100644 index 0000000000..7cddd8fd1a --- /dev/null +++ b/cuda_python/setup.py @@ -0,0 +1,23 @@ +# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED. +# +# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE + +from setuptools import setup + +# We want to keep the version in sync with cuda.bindings, but setuptools would not let +# us to refer to any files outside of the project root, so we have to employ our own +# run-time lookup using setup()... +with open("../cuda_bindings/cuda/bindings/_version.py") as f: + exec(f.read()) +version = __version__ # noqa: F821 +del __version__ # noqa: F821 + +setup( + version=version, + install_requires=[ + f"cuda-bindings~={version}", + ], + extras_require={ + "all": [f"cuda-bindings[all]~={version}"], + }, +)