Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Turn cuda-python into a pure Python wheel that depends on the cuda-bindings wheel #356

Merged
merged 14 commits into from
Jan 14, 2025
Merged
31 changes: 29 additions & 2 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/build-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -102,6 +113,8 @@ jobs:
pip install *.whl
popd

pip install cuda_python*.whl

- name: Build all (latest) docs
id: build
run: |
Expand Down
25 changes: 24 additions & 1 deletion .github/workflows/test-wheel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,21 @@ 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
with:
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 }}
Expand All @@ -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
Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion cuda_bindings/cuda/bindings/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 1 addition & 1 deletion cuda_bindings/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "[email protected]"},]
license = {file = "LICENSE"}
Expand Down
6 changes: 3 additions & 3 deletions cuda_bindings/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -326,7 +326,7 @@ def build_extension(self, ext):
cmdclass = {
"bdist_wheel": WheelsBuildExtensions,
"build_ext": ParallelBuildExtensions,
}
}

# ----------------------------------------------------------------------
# Setup
Expand Down
4 changes: 1 addition & 3 deletions cuda_bindings/tests/test_nvjitlink.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
5 changes: 2 additions & 3 deletions cuda_core/cuda/core/experimental/_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE

import importlib.metadata
from dataclasses import dataclass
from typing import Optional, Union

Expand All @@ -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
Expand All @@ -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
Expand Down
5 changes: 2 additions & 3 deletions cuda_core/cuda/core/experimental/_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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,
Expand Down
9 changes: 9 additions & 0 deletions cuda_core/cuda/core/experimental/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)
5 changes: 2 additions & 3 deletions cuda_core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
Expand Down
1 change: 1 addition & 0 deletions cuda_python/LICENSE
1 change: 1 addition & 0 deletions cuda_python/README.md
41 changes: 41 additions & 0 deletions cuda_python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -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 = "[email protected]"},]
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/"
23 changes: 23 additions & 0 deletions cuda_python/setup.py
Original file line number Diff line number Diff line change
@@ -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}"],
},
)
Loading