Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import os

import pytest

# Import centralized CUDA environment variable handling
try:
from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path
except ImportError as e:
raise ImportError(
"Failed to import cuda.pathfinder. Please ensure cuda-pathfinder is installed: pip install cuda-pathfinder"
) from e


def pytest_collection_modifyitems(config, items):
cuda_home = os.environ.get("CUDA_HOME")
cuda_home = get_cuda_home_or_path()
for item in items:
nodeid = item.nodeid.replace("\\", "/")

Expand Down
2 changes: 1 addition & 1 deletion cuda_bindings/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ To run these tests:

Cython tests are located in `tests/cython` and need to be built. These builds have the same CUDA Toolkit header requirements as [Installing from Source](https://nvidia.github.io/cuda-python/cuda-bindings/latest/install.html#requirements) where the major.minor version must match `cuda.bindings`. To build them:

1. Setup environment variable `CUDA_HOME` with the path to the CUDA Toolkit installation.
1. Setup environment variable `CUDA_PATH` (or `CUDA_HOME`) with the path to the CUDA Toolkit installation. Note: If both are set, `CUDA_PATH` takes precedence (see `cuda.pathfinder._utils.env_vars.CUDA_ENV_VARS_ORDERED`).
2. Run `build_tests` script located in `test/cython` appropriate to your platform. This will both cythonize the tests and build them.

To run these tests:
Expand Down
17 changes: 16 additions & 1 deletion cuda_bindings/docs/source/environment_variables.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,22 @@ Runtime Environment Variables
Build-Time Environment Variables
--------------------------------

- ``CUDA_HOME`` or ``CUDA_PATH``: Specifies the location of the CUDA Toolkit.
- ``CUDA_PATH`` or ``CUDA_HOME``: Specifies the location of the CUDA Toolkit. If both are set, ``CUDA_PATH`` takes precedence. This search order is defined in :py:data:`cuda.pathfinder._utils.env_vars.CUDA_ENV_VARS_ORDERED`.

.. note::
**Breaking Change in v1.4.0**: The priority order changed from ``CUDA_HOME`` > ``CUDA_PATH`` to ``CUDA_PATH`` > ``CUDA_HOME``.

**Migration Guide**:

- If you only set one variable, no changes are needed
- If you set both variables to the same location, no changes are needed
- If you set both variables to different locations and relied on ``CUDA_HOME`` taking precedence, you should either:

- Switch to using only ``CUDA_PATH`` (recommended)
- Ensure both variables point to the same CUDA Toolkit installation
- Be aware that ``CUDA_PATH`` will now be used

A warning will be issued if both variables are set but point to different locations.

- ``CUDA_PYTHON_PARSER_CACHING`` : bool, toggles the caching of parsed header files during the cuda-bindings build process. If caching is enabled (``CUDA_PYTHON_PARSER_CACHING`` is True), the cache path is set to ./cache_<library_name>, where <library_name> is derived from the cuda toolkit libraries used to build cuda-bindings.

Expand Down
4 changes: 2 additions & 2 deletions cuda_bindings/docs/source/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ Requirements

[^2]: The CUDA Runtime static library (``libcudart_static.a`` on Linux, ``cudart_static.lib`` on Windows) is part of the CUDA Toolkit. If using conda packages, it is contained in the ``cuda-cudart-static`` package.

Source builds require that the provided CUDA headers are of the same major.minor version as the ``cuda.bindings`` you're trying to build. Despite this requirement, note that the minor version compatibility is still maintained. Use the ``CUDA_HOME`` (or ``CUDA_PATH``) environment variable to specify the location of your headers. For example, if your headers are located in ``/usr/local/cuda/include``, then you should set ``CUDA_HOME`` with:
Source builds require that the provided CUDA headers are of the same major.minor version as the ``cuda.bindings`` you're trying to build. Despite this requirement, note that the minor version compatibility is still maintained. Use the ``CUDA_PATH`` (or ``CUDA_HOME``) environment variable to specify the location of your headers. If both are set, ``CUDA_PATH`` takes precedence (see :py:data:`cuda.pathfinder._utils.env_vars.CUDA_ENV_VARS_ORDERED`). For example, if your headers are located in ``/usr/local/cuda/include``, then you should set ``CUDA_PATH`` with:

.. code-block:: console

$ export CUDA_HOME=/usr/local/cuda
$ export CUDA_PATH=/usr/local/cuda

See `Environment Variables <environment_variables.rst>`_ for a description of other build-time environment variables.

Expand Down
12 changes: 3 additions & 9 deletions cuda_bindings/examples/common/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,13 @@
from cuda.bindings import driver as cuda
from cuda.bindings import nvrtc
from cuda.bindings import runtime as cudart


def get_cuda_home():
cuda_home = os.getenv("CUDA_HOME")
if cuda_home is None:
cuda_home = os.getenv("CUDA_PATH")
return cuda_home
from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path


def pytest_skipif_cuda_include_not_found():
import pytest

cuda_home = get_cuda_home()
cuda_home = get_cuda_home_or_path()
if cuda_home is None:
pytest.skip("CUDA_HOME/CUDA_PATH not set")
cuda_include = os.path.join(cuda_home, "include")
Expand All @@ -46,7 +40,7 @@ class KernelHelper:
def __init__(self, code, devID):
prog = checkCudaErrors(nvrtc.nvrtcCreateProgram(str.encode(code), b"sourceCode.cu", 0, None, None))

cuda_home = get_cuda_home()
cuda_home = get_cuda_home_or_path()
assert cuda_home is not None
cuda_include = os.path.join(cuda_home, "include")
assert os.path.isdir(cuda_include)
Expand Down
39 changes: 21 additions & 18 deletions cuda_bindings/pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion cuda_bindings/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ setuptools = ">=80"
setuptools-scm = ">=8"
cython = ">=3.2,<3.3"
pyclibrary = ">=0.1.7"
cuda-pathfinder = "*"
cuda-cudart-static = "*"
cuda-nvrtc-dev = "*"
cuda-profiler-api = "*"
Expand All @@ -114,7 +115,7 @@ cuda-crt-dev_win-64 = "*"

[package.run-dependencies]
python = "*"
cuda-pathfinder = ">=1.1,<2"
cuda-pathfinder = "*"
libnvjitlink = "*"
cuda-nvrtc = "*"
cuda-nvvm = "*"
Expand Down
1 change: 1 addition & 0 deletions cuda_bindings/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ requires = [
"setuptools_scm[simple]>=8",
"cython>=3.2,<3.3",
"pyclibrary>=0.1.7",
"cuda-pathfinder",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already on line 34 below. Having it there seemed to work reliably in all situations?

]
build-backend = "setuptools.build_meta"

Expand Down
11 changes: 9 additions & 2 deletions cuda_bindings/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,16 @@
# ----------------------------------------------------------------------
# Fetch configuration options

CUDA_HOME = os.environ.get("CUDA_HOME", os.environ.get("CUDA_PATH", None))
try:
from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path

CUDA_HOME = get_cuda_home_or_path()
except ImportError:
# Fallback for build environments where cuda-pathfinder may not be available
CUDA_HOME = os.environ.get("CUDA_HOME", os.environ.get("CUDA_PATH", None))

if not CUDA_HOME:
raise RuntimeError("Environment variable CUDA_HOME or CUDA_PATH is not set")
raise RuntimeError("Environment variable CUDA_PATH or CUDA_HOME is not set")

CUDA_HOME = CUDA_HOME.split(os.pathsep)

Expand Down
2 changes: 1 addition & 1 deletion cuda_core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Alternatively, from the repository root you can use a simple script:

Cython tests are located in `tests/cython` and need to be built. These builds have the same CUDA Toolkit header requirements as [those of cuda.bindings](https://nvidia.github.io/cuda-python/cuda-bindings/latest/install.html#requirements) where the major.minor version must match `cuda.bindings`. To build them:

1. Set up environment variable `CUDA_HOME` with the path to the CUDA Toolkit installation.
1. Set up environment variable `CUDA_PATH` (or `CUDA_HOME`) with the path to the CUDA Toolkit installation. Note: If both are set, `CUDA_PATH` takes precedence (see `cuda.pathfinder._utils.env_vars.CUDA_ENV_VARS_ORDERED`).
2. Run `build_tests` script located in `tests/cython` appropriate to your platform. This will both cythonize the tests and build them.

To run these tests:
Expand Down
33 changes: 18 additions & 15 deletions cuda_core/pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cuda_core/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ setuptools-scm = ">=8"
cython = ">=3.2,<3.3"
cuda-cudart-dev = "*"
cuda-profiler-api = "*"
cuda-pathfinder = "*"
# this doesn't work because Cython cannot find editable-installed build-time
# dependencies https://github.com/cython/cython/issues/7326
# cuda-bindings = { path = "../cuda_bindings" }
Expand Down
3 changes: 2 additions & 1 deletion cuda_core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
requires = [
"setuptools>=80",
"setuptools-scm[simple]>=8",
"Cython>=3.2,<3.3"
"Cython>=3.2,<3.3",
"cuda-pathfinder"
]
build-backend = "build_hooks"
backend-path = ["."]
Expand Down
3 changes: 2 additions & 1 deletion cuda_core/tests/helpers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
from typing import Union

from cuda.core._utils.cuda_utils import handle_return
from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path

CUDA_PATH = os.environ.get("CUDA_PATH")
CUDA_PATH = get_cuda_home_or_path()
CUDA_INCLUDE_PATH = None
CCCL_INCLUDE_PATHS = None
if CUDA_PATH is not None:
Expand Down
26 changes: 26 additions & 0 deletions cuda_core/tests/test_build_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,29 @@ def test_missing_cuda_path_raises_error(self):
pytest.raises(RuntimeError, match="CUDA_PATH or CUDA_HOME"),
):
build_hooks._determine_cuda_major_version()

def test_multiple_cuda_paths(self):
"""Multiple CUDA paths separated by os.pathsep are correctly handled."""
with tempfile.TemporaryDirectory() as tmpdir1, tempfile.TemporaryDirectory() as tmpdir2:
# Create mock CUDA installations in both directories
for tmpdir in [tmpdir1, tmpdir2]:
include_dir = Path(tmpdir) / "include"
include_dir.mkdir()
cuda_h = include_dir / "cuda.h"
cuda_h.write_text("#define CUDA_VERSION 12080\n")

build_hooks._get_cuda_paths.cache_clear()
build_hooks._determine_cuda_major_version.cache_clear()

# Set CUDA_PATH with multiple paths
multiple_paths = os.pathsep.join([tmpdir1, tmpdir2])
with mock.patch.dict(os.environ, {"CUDA_PATH": multiple_paths}, clear=True):
# Should return list of both paths
paths = build_hooks._get_cuda_paths()
assert len(paths) == 2
assert paths[0] == tmpdir1
assert paths[1] == tmpdir2

# Version detection should use first path
result = build_hooks._determine_cuda_major_version()
assert result == "12"
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def _load_lib_no_cache(libname: str) -> LoadedDL:
if abs_path is None:
finder.raise_not_found_error()
else:
found_via = "CUDA_HOME"
found_via = "CUDA_PATH"

return load_with_abs_path(libname, abs_path, found_via)

Expand Down Expand Up @@ -121,7 +121,8 @@ def load_nvidia_dynamic_lib(libname: str) -> LoadedDL:

4. **Environment variables**

- If set, use ``CUDA_HOME`` or ``CUDA_PATH`` (in that order).
- If set, use ``CUDA_PATH`` or ``CUDA_HOME`` (in that order, as defined by
:py:data:`cuda.pathfinder._utils.env_vars.CUDA_ENV_VARS_ORDERED`).

Notes:
The search is performed **per library**. There is currently no mechanism to
Expand Down
Loading
Loading