Skip to content

Commit 01f33cd

Browse files
committed
build: use cuda.pathfinder.get_cuda_path_or_home in build hooks
Pin cuda-pathfinder>=1.5 in both build-system.requires and project.dependencies. Made-with: Cursor
1 parent 8432c9d commit 01f33cd

5 files changed

Lines changed: 64 additions & 13 deletions

File tree

cuda_bindings/build_hooks.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,35 @@
3333
_extensions = None
3434

3535

36+
# Please keep in sync with the copy in cuda_core/build_hooks.py.
37+
def _import_get_cuda_path_or_home():
38+
"""Import get_cuda_path_or_home, working around PEP 517 namespace shadowing.
39+
40+
In isolated build environments, backend-path=["."] causes the ``cuda``
41+
namespace package to resolve to only the project's ``cuda/`` directory,
42+
hiding ``cuda.pathfinder`` installed in the build-env's site-packages.
43+
Fix by replacing ``cuda.__path__`` with a plain list that includes the
44+
site-packages ``cuda/`` directory.
45+
"""
46+
try:
47+
import cuda.pathfinder
48+
except ModuleNotFoundError:
49+
import cuda
50+
51+
for p in sys.path:
52+
sp_cuda = os.path.join(p, "cuda")
53+
if os.path.isdir(os.path.join(sp_cuda, "pathfinder")):
54+
cuda.__path__ = list(cuda.__path__) + [sp_cuda]
55+
break
56+
import cuda.pathfinder
57+
58+
return cuda.pathfinder.get_cuda_path_or_home
59+
60+
3661
@functools.cache
3762
def _get_cuda_path() -> str:
38-
# Not using cuda.pathfinder.get_cuda_path_or_home() here because this
39-
# build backend runs in an isolated venv where the cuda namespace package
40-
# from backend-path shadows the installed cuda-pathfinder. See #1803 for
41-
# a workaround to apply after cuda-pathfinder >= 1.5 is released.
42-
cuda_path = os.environ.get("CUDA_PATH", os.environ.get("CUDA_HOME"))
63+
get_cuda_path_or_home = _import_get_cuda_path_or_home()
64+
cuda_path = get_cuda_path_or_home()
4365
if not cuda_path:
4466
raise RuntimeError("Environment variable CUDA_PATH or CUDA_HOME is not set")
4567
print("CUDA path:", cuda_path)

cuda_bindings/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ requires = [
66
"setuptools_scm[simple]>=8",
77
"cython>=3.2,<3.3",
88
"pyclibrary>=0.1.7",
9+
"cuda-pathfinder>=1.5",
910
]
1011
build-backend = "build_hooks"
1112
backend-path = ["."]
@@ -31,7 +32,7 @@ classifiers = [
3132
"Environment :: GPU :: NVIDIA CUDA",
3233
]
3334
dynamic = ["version", "readme"]
34-
dependencies = ["cuda-pathfinder >=1.4.2"]
35+
dependencies = ["cuda-pathfinder >=1.5"]
3536

3637
[project.optional-dependencies]
3738
all = [

cuda_core/build_hooks.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,35 @@
2828
COMPILE_FOR_COVERAGE = bool(int(os.environ.get("CUDA_PYTHON_COVERAGE", "0")))
2929

3030

31+
# Please keep in sync with the copy in cuda_bindings/build_hooks.py.
32+
def _import_get_cuda_path_or_home():
33+
"""Import get_cuda_path_or_home, working around PEP 517 namespace shadowing.
34+
35+
In isolated build environments, backend-path=["."] causes the ``cuda``
36+
namespace package to resolve to only the project's ``cuda/`` directory,
37+
hiding ``cuda.pathfinder`` installed in the build-env's site-packages.
38+
Fix by replacing ``cuda.__path__`` with a plain list that includes the
39+
site-packages ``cuda/`` directory.
40+
"""
41+
try:
42+
import cuda.pathfinder
43+
except ModuleNotFoundError:
44+
import cuda
45+
46+
for p in sys.path:
47+
sp_cuda = os.path.join(p, "cuda")
48+
if os.path.isdir(os.path.join(sp_cuda, "pathfinder")):
49+
cuda.__path__ = list(cuda.__path__) + [sp_cuda]
50+
break
51+
import cuda.pathfinder
52+
53+
return cuda.pathfinder.get_cuda_path_or_home
54+
55+
3156
@functools.cache
3257
def _get_cuda_path() -> str:
33-
# Not using cuda.pathfinder.get_cuda_path_or_home() here because this
34-
# build backend runs in an isolated venv where the cuda namespace package
35-
# from backend-path shadows the installed cuda-pathfinder. See #1803 for
36-
# a workaround to apply after cuda-pathfinder >= 1.5 is released.
37-
cuda_path = os.environ.get("CUDA_PATH", os.environ.get("CUDA_HOME"))
58+
get_cuda_path_or_home = _import_get_cuda_path_or_home()
59+
cuda_path = get_cuda_path_or_home()
3860
if not cuda_path:
3961
raise RuntimeError("Environment variable CUDA_PATH or CUDA_HOME is not set")
4062
print("CUDA path:", cuda_path)

cuda_core/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ requires = [
77
"setuptools>=80",
88
"setuptools-scm[simple]>=8",
99
"Cython>=3.2,<3.3",
10+
"cuda-pathfinder>=1.5"
1011
]
1112
build-backend = "build_hooks"
1213
backend-path = ["."]
@@ -47,7 +48,7 @@ classifiers = [
4748
"Environment :: GPU :: NVIDIA CUDA :: 13",
4849
]
4950
dependencies = [
50-
"cuda-pathfinder >=1.4.2",
51+
"cuda-pathfinder >=1.5",
5152
"numpy",
5253
]
5354

cuda_core/tests/test_build_hooks.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
1+
# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: Apache-2.0
33

44
"""Tests for build_hooks.py build infrastructure.
@@ -24,6 +24,8 @@
2424

2525
import pytest
2626

27+
from cuda.pathfinder import get_cuda_path_or_home
28+
2729
# build_hooks.py imports Cython and setuptools at the top level, so skip if not available
2830
pytest.importorskip("Cython")
2931
pytest.importorskip("setuptools")
@@ -68,6 +70,7 @@ def _check_version_detection(
6870

6971
build_hooks._get_cuda_path.cache_clear()
7072
build_hooks._determine_cuda_major_version.cache_clear()
73+
get_cuda_path_or_home.cache_clear()
7174

7275
mock_env = {
7376
k: v
@@ -92,6 +95,7 @@ def test_env_var_override(self, version):
9295
"""CUDA_CORE_BUILD_MAJOR env var override works with various versions."""
9396
build_hooks._get_cuda_path.cache_clear()
9497
build_hooks._determine_cuda_major_version.cache_clear()
98+
get_cuda_path_or_home.cache_clear()
9599
with mock.patch.dict(os.environ, {"CUDA_CORE_BUILD_MAJOR": version}, clear=False):
96100
result = build_hooks._determine_cuda_major_version()
97101
assert result == version
@@ -125,6 +129,7 @@ def test_missing_cuda_path_raises_error(self):
125129
"""RuntimeError is raised when CUDA_PATH/CUDA_HOME not set and no env var override."""
126130
build_hooks._get_cuda_path.cache_clear()
127131
build_hooks._determine_cuda_major_version.cache_clear()
132+
get_cuda_path_or_home.cache_clear()
128133
with (
129134
mock.patch.dict(os.environ, {}, clear=True),
130135
pytest.raises(RuntimeError, match="CUDA_PATH or CUDA_HOME"),

0 commit comments

Comments
 (0)