From c4955e444ac7847619009b52db4f5bba20d19ffe Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 8 Sep 2025 17:01:35 -0700 Subject: [PATCH 01/31] New supported_nvidia_headers.py, starting with just SUPPORTED_HEADERS_CTK, SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK dicts. --- .../_headers/supported_nvidia_headers.py | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py new file mode 100644 index 0000000000..84432bd33c --- /dev/null +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +SUPPORTED_HEADERS_CTK = { + "cub": "cub/cub.cuh", + "cublas": "cublas.h", + "cudart": "cuda_runtime.h", + "cufft": "cufft.h", + "cufile": "cufile.h", + "curand": "curand.h", + "cusolver": "cusolver_common.h", + "cusparse": "cusparse.h", + "libcudacxx": "cuda/std/version", + "npp": "npp.h", + "nvcc": "fatbinary_section.h", + "nvfatbin": "nvFatbin.h", + "nvjitlink": "nvJitLink.h", + "nvjpeg": "nvjpeg.h", + "nvrtc": "nvrtc.h", + "nvvm": "nvvm.h", + "thrust": "thrust/version.h", +} + +SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK = { + "cub": ("cuda/cccl/headers/include",), + "cublas": ("nvidia/cu13/include", "nvidia/cublas/include"), + "cudart": ("nvidia/cu13/include", "nvidia/cuda_runtime/include"), + "cufft": ("nvidia/cu13/include", "nvidia/cufft/include"), + "cufile": ("nvidia/cu13/include", "nvidia/cufile/include"), + "curand": ("nvidia/cu13/include", "nvidia/curand/include"), + "cusolver": ("nvidia/cu13/include", "nvidia/cusolver/include"), + "cusparse": ("nvidia/cu13/include", "nvidia/cusparse/include"), + "libcudacxx": ("cuda/cccl/headers/include",), + "npp": ("nvidia/cu13/include", "nvidia/npp/include"), + "nvcc": ("nvidia/cu13/include", "nvidia/cuda_nvcc/include"), + "nvfatbin": ("nvidia/cu13/include", "nvidia/nvfatbin/include"), + "nvjitlink": ("nvidia/cu13/include", "nvidia/nvjitlink/include"), + "nvjpeg": ("nvidia/cu13/include", "nvidia/nvjpeg/include"), + "nvrtc": ("nvidia/cu13/include", "nvidia/cuda_nvrtc/include"), + "nvvm": ("nvidia/cu13/include", "nvidia/cuda_nvcc/nvvm/include"), + "thrust": ("cuda/cccl/headers/include",), +} From d3b1a9884860dc111f69d866cef26179d795f1e8 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 09:41:20 -0700 Subject: [PATCH 02/31] Add _find_ctk_header_directory(), currently for site-packages only. --- .../_headers/find_nvidia_headers.py | 35 +++++++++++++++---- .../tests/test_find_nvidia_headers.py | 20 +++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index cc2c8654cb..254f4720c6 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -7,15 +7,12 @@ from typing import Optional from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS +from cuda.pathfinder._headers import supported_nvidia_headers from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages -@functools.cache -def find_nvidia_header_directory(libname: str) -> Optional[str]: - if libname != "nvshmem": - raise RuntimeError(f"UNKNOWN {libname=}") - - if libname == "nvshmem" and IS_WINDOWS: +def _find_nvshmem_header_directory() -> Optional[str]: + if IS_WINDOWS: # nvshmem has no Windows support. return None @@ -40,3 +37,29 @@ def find_nvidia_header_directory(libname: str) -> Optional[str]: return hdr_dir return None + + +def _find_ctk_header_directory(libname: str) -> Optional[str]: + h_basename = supported_nvidia_headers.SUPPORTED_HEADERS_CTK[libname] + candidate_dirs = supported_nvidia_headers.SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK[libname] + + # Installed from a wheel + for cdir in candidate_dirs: + hdr_dir: str # help mypy + for hdr_dir in find_sub_dirs_all_sitepackages(tuple(cdir.split("/"))): + h_path = os.path.join(hdr_dir, h_basename) + if os.path.isfile(h_path): + return hdr_dir + + return None + + +@functools.cache +def find_nvidia_header_directory(libname: str) -> Optional[str]: + if libname == "nvshmem": + return _find_nvshmem_header_directory() + + if libname in supported_nvidia_headers.SUPPORTED_HEADERS_CTK: + return _find_ctk_header_directory(libname) + + raise RuntimeError(f"UNKNOWN {libname=}") diff --git a/cuda_pathfinder/tests/test_find_nvidia_headers.py b/cuda_pathfinder/tests/test_find_nvidia_headers.py index 2d432b0f21..561181fd5c 100644 --- a/cuda_pathfinder/tests/test_find_nvidia_headers.py +++ b/cuda_pathfinder/tests/test_find_nvidia_headers.py @@ -22,6 +22,10 @@ from cuda.pathfinder import _find_nvidia_header_directory as find_nvidia_header_directory from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS +from cuda.pathfinder._headers.supported_nvidia_headers import ( + SUPPORTED_HEADERS_CTK, + SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK, +) STRICTNESS = os.environ.get("CUDA_PATHFINDER_TEST_FIND_NVIDIA_HEADERS_STRICTNESS", "see_what_works") assert STRICTNESS in ("see_what_works", "all_must_work") @@ -58,3 +62,19 @@ def test_find_libname_nvshmem(info_summary_append): assert hdr_dir.startswith(conda_prefix) else: assert hdr_dir.startswith("/usr/include/nvshmem_") + + +def test_supported_supported_headers_site_packages_ctk_consistency(): + assert tuple(sorted(SUPPORTED_HEADERS_CTK)) == tuple(sorted(SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK.keys())) + + +@pytest.mark.parametrize("libname", SUPPORTED_HEADERS_CTK.keys()) +def test_find_ctk_headers(info_summary_append, libname): + hdr_dir = find_nvidia_header_directory(libname) + info_summary_append(f"{hdr_dir=!r}") + if hdr_dir: + assert os.path.isdir(hdr_dir) + h_filename = SUPPORTED_HEADERS_CTK[libname] + assert os.path.isfile(os.path.join(hdr_dir, h_filename)) + if STRICTNESS == "all_must_work": + assert hdr_dir is not None From 12beef69dfdb7a23717a59c0d534e612aeb73798 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 10:16:46 -0700 Subject: [PATCH 03/31] Factor out get_cuda_home_or_path() into new cuda/pathfinder/_utils/env_vars.py --- .../_dynamic_libs/find_nvidia_dynamic_lib.py | 10 ++-------- cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py diff --git a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/find_nvidia_dynamic_lib.py b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/find_nvidia_dynamic_lib.py index 18708a2b3e..d9567207ea 100644 --- a/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/find_nvidia_dynamic_lib.py +++ b/cuda_pathfinder/cuda/pathfinder/_dynamic_libs/find_nvidia_dynamic_lib.py @@ -14,6 +14,7 @@ SITE_PACKAGES_LIBDIRS_WINDOWS, is_suppressed_dll_file, ) +from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs, find_sub_dirs_all_sitepackages @@ -79,15 +80,8 @@ def _find_dll_using_nvidia_bin_dirs( return None -def _get_cuda_home() -> Optional[str]: - cuda_home = os.environ.get("CUDA_HOME") - if cuda_home is None: - cuda_home = os.environ.get("CUDA_PATH") - return cuda_home - - def _find_lib_dir_using_cuda_home(libname: str) -> Optional[str]: - cuda_home = _get_cuda_home() + cuda_home = get_cuda_home_or_path() if cuda_home is None: return None subdirs_list: tuple[tuple[str, ...], ...] diff --git a/cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py b/cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py new file mode 100644 index 0000000000..77f4a7d1ea --- /dev/null +++ b/cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py @@ -0,0 +1,12 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import os +from typing import Optional + + +def get_cuda_home_or_path() -> Optional[str]: + cuda_home = os.environ.get("CUDA_HOME") + if cuda_home is None: + cuda_home = os.environ.get("CUDA_PATH") + return cuda_home From a37d132967a4e5d7dddbeabd28c09bdcd23fe66b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 10:34:55 -0700 Subject: [PATCH 04/31] Add CUDA_HOME code in find_nvidia_headers.py --- .../_headers/find_nvidia_headers.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 254f4720c6..169be911ae 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -8,6 +8,7 @@ from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS from cuda.pathfinder._headers import supported_nvidia_headers +from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages @@ -51,6 +52,24 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: if os.path.isfile(h_path): return hdr_dir + cuda_home = get_cuda_home_or_path() + if cuda_home: + if libname == "nvvm": + idir = os.path.join(cuda_home, "nvvm", "include") + h_path = os.path.join(idir, h_basename) + if os.path.isfile(h_path): + return idir + else: + idir = os.path.join(cuda_home, "include") + if libname in ("cub", "libcudacxx", "thrust"): + cdir = os.path.join(idir, "cccl") + h_path = os.path.join(cdir, h_basename) + if os.path.isfile(h_path): + return cdir + h_path = os.path.join(idir, h_basename) + if os.path.isfile(h_path): + return idir + return None From 2a397b6ded79b62fb4a4ed8561851f0d2019623e Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 10:40:26 -0700 Subject: [PATCH 05/31] Formalize supported_nvidia_headers.CCCL_LIBNAMES --- .../cuda/pathfinder/_headers/find_nvidia_headers.py | 2 +- .../cuda/pathfinder/_headers/supported_nvidia_headers.py | 2 ++ cuda_pathfinder/tests/test_find_nvidia_headers.py | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 169be911ae..797b6e2513 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -61,7 +61,7 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: return idir else: idir = os.path.join(cuda_home, "include") - if libname in ("cub", "libcudacxx", "thrust"): + if libname in supported_nvidia_headers.CCCL_LIBNAMES: cdir = os.path.join(idir, "cccl") h_path = os.path.join(cdir, h_basename) if os.path.isfile(h_path): diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index 84432bd33c..4197e3ea81 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -40,3 +40,5 @@ "nvvm": ("nvidia/cu13/include", "nvidia/cuda_nvcc/nvvm/include"), "thrust": ("cuda/cccl/headers/include",), } + +CCCL_LIBNAMES = ("cub", "libcudacxx", "thrust") diff --git a/cuda_pathfinder/tests/test_find_nvidia_headers.py b/cuda_pathfinder/tests/test_find_nvidia_headers.py index 561181fd5c..603e28a0f4 100644 --- a/cuda_pathfinder/tests/test_find_nvidia_headers.py +++ b/cuda_pathfinder/tests/test_find_nvidia_headers.py @@ -23,6 +23,7 @@ from cuda.pathfinder import _find_nvidia_header_directory as find_nvidia_header_directory from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS from cuda.pathfinder._headers.supported_nvidia_headers import ( + CCCL_LIBNAMES, SUPPORTED_HEADERS_CTK, SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK, ) @@ -64,10 +65,14 @@ def test_find_libname_nvshmem(info_summary_append): assert hdr_dir.startswith("/usr/include/nvshmem_") -def test_supported_supported_headers_site_packages_ctk_consistency(): +def test_supported_headers_site_packages_ctk_consistency(): assert tuple(sorted(SUPPORTED_HEADERS_CTK)) == tuple(sorted(SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK.keys())) +def test_supported_headers_cccl_libnames_consistency(): + assert set(CCCL_LIBNAMES).issubset(set(SUPPORTED_HEADERS_CTK.keys())) + + @pytest.mark.parametrize("libname", SUPPORTED_HEADERS_CTK.keys()) def test_find_ctk_headers(info_summary_append, libname): hdr_dir = find_nvidia_header_directory(libname) From e0a22fa0b1e250de36fdd9305ab8e8b908741c28 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 10:51:31 -0700 Subject: [PATCH 06/31] Add CONDA_PREFIX code in find_nvidia_headers.py --- .../_headers/find_nvidia_headers.py | 44 ++++++++++++------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 797b6e2513..cc9880d3ef 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -40,6 +40,26 @@ def _find_nvshmem_header_directory() -> Optional[str]: return None +def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) -> Optional[str]: + if libname == "nvvm": + idir = os.path.join(anchor_point, "nvvm", "include") + h_path = os.path.join(idir, h_basename) + if os.path.isfile(h_path): + return idir + else: + idir = os.path.join(anchor_point, "include") + if libname in supported_nvidia_headers.CCCL_LIBNAMES: + cdir = os.path.join(idir, "cccl") + h_path = os.path.join(cdir, h_basename) + if os.path.isfile(h_path): + return cdir + h_path = os.path.join(idir, h_basename) + if os.path.isfile(h_path): + return idir + + return None + + def _find_ctk_header_directory(libname: str) -> Optional[str]: h_basename = supported_nvidia_headers.SUPPORTED_HEADERS_CTK[libname] candidate_dirs = supported_nvidia_headers.SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK[libname] @@ -52,23 +72,15 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: if os.path.isfile(h_path): return hdr_dir + conda_prefix = os.getenv("CONDA_PREFIX") + if conda_prefix: # noqa: SIM102 + if result := _find_based_on_ctk_layout(libname, h_basename, conda_prefix): + return result + cuda_home = get_cuda_home_or_path() - if cuda_home: - if libname == "nvvm": - idir = os.path.join(cuda_home, "nvvm", "include") - h_path = os.path.join(idir, h_basename) - if os.path.isfile(h_path): - return idir - else: - idir = os.path.join(cuda_home, "include") - if libname in supported_nvidia_headers.CCCL_LIBNAMES: - cdir = os.path.join(idir, "cccl") - h_path = os.path.join(cdir, h_basename) - if os.path.isfile(h_path): - return cdir - h_path = os.path.join(idir, h_basename) - if os.path.isfile(h_path): - return idir + if cuda_home: # noqa: SIM102 + if result := _find_based_on_ctk_layout(libname, h_basename, cuda_home): + return result return None From 160d8a4714f0c69175806b55308b78861759b334 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 14:02:17 -0700 Subject: [PATCH 07/31] Add `shutil.which("nvcc")` code in find_nvidia_headers.py --- .../pathfinder/_headers/find_nvidia_headers.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index cc9880d3ef..d9d472f361 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -4,6 +4,7 @@ import functools import glob import os +import shutil from typing import Optional from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS @@ -60,6 +61,18 @@ def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) return None +@functools.cache +def _get_nvcc_home() -> Optional[str]: + # Fall back to the directory that owns nvcc (works for most local installs) + nvcc_path = shutil.which("nvcc") + if not nvcc_path: + return None + flds = nvcc_path.split(os.path.sep) + if len(flds) < 3: + return None + return os.path.sep.join(flds[:-2]) + + def _find_ctk_header_directory(libname: str) -> Optional[str]: h_basename = supported_nvidia_headers.SUPPORTED_HEADERS_CTK[libname] candidate_dirs = supported_nvidia_headers.SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK[libname] @@ -82,6 +95,11 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: if result := _find_based_on_ctk_layout(libname, h_basename, cuda_home): return result + nvcc_home = _get_nvcc_home() + if nvcc_home: # noqa: SIM102 + if result := _find_based_on_ctk_layout(libname, h_basename, nvcc_home): + return result + return None From 946721fd98d4d5afa6eba21f8959a64fc4b880a0 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 14:17:40 -0700 Subject: [PATCH 08/31] Cleanup: add _joined_isfile() helper --- .../_headers/find_nvidia_headers.py | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index d9d472f361..036cc0f98f 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -13,6 +13,10 @@ from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages +def _joined_isfile(dirpath: str, basename: str) -> bool: + return os.path.isfile(os.path.join(dirpath, basename)) + + def _find_nvshmem_header_directory() -> Optional[str]: if IS_WINDOWS: # nvshmem has no Windows support. @@ -22,20 +26,17 @@ def _find_nvshmem_header_directory() -> Optional[str]: nvidia_sub_dirs = ("nvidia", "nvshmem", "include") hdr_dir: str # help mypy for hdr_dir in find_sub_dirs_all_sitepackages(nvidia_sub_dirs): - nvshmem_h_path = os.path.join(hdr_dir, "nvshmem.h") - if os.path.isfile(nvshmem_h_path): + if _joined_isfile(hdr_dir, "nvshmem.h"): return hdr_dir conda_prefix = os.environ.get("CONDA_PREFIX") if conda_prefix and os.path.isdir(conda_prefix): hdr_dir = os.path.join(conda_prefix, "include") - nvshmem_h_path = os.path.join(hdr_dir, "nvshmem.h") - if os.path.isfile(nvshmem_h_path): + if _joined_isfile(hdr_dir, "nvshmem.h"): return hdr_dir for hdr_dir in sorted(glob.glob("/usr/include/nvshmem_*"), reverse=True): - nvshmem_h_path = os.path.join(hdr_dir, "nvshmem.h") - if os.path.isfile(nvshmem_h_path): + if _joined_isfile(hdr_dir, "nvshmem.h"): return hdr_dir return None @@ -44,18 +45,15 @@ def _find_nvshmem_header_directory() -> Optional[str]: def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) -> Optional[str]: if libname == "nvvm": idir = os.path.join(anchor_point, "nvvm", "include") - h_path = os.path.join(idir, h_basename) - if os.path.isfile(h_path): + if _joined_isfile(idir, h_basename): return idir else: idir = os.path.join(anchor_point, "include") if libname in supported_nvidia_headers.CCCL_LIBNAMES: cdir = os.path.join(idir, "cccl") - h_path = os.path.join(cdir, h_basename) - if os.path.isfile(h_path): + if _joined_isfile(cdir, h_basename): return cdir - h_path = os.path.join(idir, h_basename) - if os.path.isfile(h_path): + if _joined_isfile(idir, h_basename): return idir return None @@ -81,8 +79,7 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: for cdir in candidate_dirs: hdr_dir: str # help mypy for hdr_dir in find_sub_dirs_all_sitepackages(tuple(cdir.split("/"))): - h_path = os.path.join(hdr_dir, h_basename) - if os.path.isfile(h_path): + if _joined_isfile(hdr_dir, h_basename): return hdr_dir conda_prefix = os.getenv("CONDA_PREFIX") From 656a30dfa2a29d9a32afc31ef4e4ef815013266c Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 14:28:57 -0700 Subject: [PATCH 09/31] find_nvidia_header_directory(): return _abs_norm() --- .../cuda/pathfinder/_headers/find_nvidia_headers.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 036cc0f98f..3f47e599de 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -13,6 +13,12 @@ from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages +def _abs_norm(path: Optional[str]) -> Optional[str]: + if path: + return os.path.normpath(os.path.abspath(path)) + return None + + def _joined_isfile(dirpath: str, basename: str) -> bool: return os.path.isfile(os.path.join(dirpath, basename)) @@ -103,9 +109,9 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: @functools.cache def find_nvidia_header_directory(libname: str) -> Optional[str]: if libname == "nvshmem": - return _find_nvshmem_header_directory() + return _abs_norm(_find_nvshmem_header_directory()) if libname in supported_nvidia_headers.SUPPORTED_HEADERS_CTK: - return _find_ctk_header_directory(libname) + return _abs_norm(_find_ctk_header_directory(libname)) raise RuntimeError(f"UNKNOWN {libname=}") From 0d4e5a8eff75f600b238fa9446c05fd004cb43aa Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 14:37:20 -0700 Subject: [PATCH 10/31] Bump pathfinder version to 1.2.3a0 --- cuda_pathfinder/cuda/pathfinder/_version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_version.py b/cuda_pathfinder/cuda/pathfinder/_version.py index 70aa6255c8..87dfcc13d2 100644 --- a/cuda_pathfinder/cuda/pathfinder/_version.py +++ b/cuda_pathfinder/cuda/pathfinder/_version.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -__version__ = "1.2.2" +__version__ = "1.2.3a0" From 0629da25c2d2563356dc8eb769b57b922641f7ad Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 15:43:37 -0700 Subject: [PATCH 11/31] Replace libcudacxx,cub,thrust with cccl. Add cuda-toolkit[cccl] to nvidia_wheels_cu12, nvidia_wheels_cu13 --- .../pathfinder/_headers/find_nvidia_headers.py | 2 +- .../_headers/supported_nvidia_headers.py | 14 ++++++-------- cuda_pathfinder/pyproject.toml | 4 ++-- cuda_pathfinder/tests/test_find_nvidia_headers.py | 5 ----- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 3f47e599de..d573f08eef 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -55,7 +55,7 @@ def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) return idir else: idir = os.path.join(anchor_point, "include") - if libname in supported_nvidia_headers.CCCL_LIBNAMES: + if libname == "cccl": cdir = os.path.join(idir, "cccl") if _joined_isfile(cdir, h_basename): return cdir diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index 4197e3ea81..7b22659960 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -2,7 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 SUPPORTED_HEADERS_CTK = { - "cub": "cub/cub.cuh", + "cccl": "cuda/std/version", "cublas": "cublas.h", "cudart": "cuda_runtime.h", "cufft": "cufft.h", @@ -10,7 +10,6 @@ "curand": "curand.h", "cusolver": "cusolver_common.h", "cusparse": "cusparse.h", - "libcudacxx": "cuda/std/version", "npp": "npp.h", "nvcc": "fatbinary_section.h", "nvfatbin": "nvFatbin.h", @@ -18,11 +17,14 @@ "nvjpeg": "nvjpeg.h", "nvrtc": "nvrtc.h", "nvvm": "nvvm.h", - "thrust": "thrust/version.h", } SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK = { - "cub": ("cuda/cccl/headers/include",), + "cccl": ( + "cuda/cccl/headers/include", # cuda-cccl + "nvidia/cu13/include/cccl", # cuda-toolkit[cccl]==13.* + "nvidia/cuda_cccl/include", # cuda-toolkit[cccl]==12.* + ), "cublas": ("nvidia/cu13/include", "nvidia/cublas/include"), "cudart": ("nvidia/cu13/include", "nvidia/cuda_runtime/include"), "cufft": ("nvidia/cu13/include", "nvidia/cufft/include"), @@ -30,7 +32,6 @@ "curand": ("nvidia/cu13/include", "nvidia/curand/include"), "cusolver": ("nvidia/cu13/include", "nvidia/cusolver/include"), "cusparse": ("nvidia/cu13/include", "nvidia/cusparse/include"), - "libcudacxx": ("cuda/cccl/headers/include",), "npp": ("nvidia/cu13/include", "nvidia/npp/include"), "nvcc": ("nvidia/cu13/include", "nvidia/cuda_nvcc/include"), "nvfatbin": ("nvidia/cu13/include", "nvidia/nvfatbin/include"), @@ -38,7 +39,4 @@ "nvjpeg": ("nvidia/cu13/include", "nvidia/nvjpeg/include"), "nvrtc": ("nvidia/cu13/include", "nvidia/cuda_nvrtc/include"), "nvvm": ("nvidia/cu13/include", "nvidia/cuda_nvcc/nvvm/include"), - "thrust": ("cuda/cccl/headers/include",), } - -CCCL_LIBNAMES = ("cub", "libcudacxx", "thrust") diff --git a/cuda_pathfinder/pyproject.toml b/cuda_pathfinder/pyproject.toml index bffb42a828..e19244e3ea 100644 --- a/cuda_pathfinder/pyproject.toml +++ b/cuda_pathfinder/pyproject.toml @@ -15,7 +15,7 @@ test = [ "pytest>=6.2.4", ] nvidia_wheels_cu12 = [ - "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg]==12.*", + "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl]==12.*", "cuda-toolkit[cufile]==12.*; sys_platform != 'win32'", "nvidia-cudss-cu12", "nvidia-cufftmp-cu12; sys_platform != 'win32'", @@ -24,7 +24,7 @@ nvidia_wheels_cu12 = [ "nvidia-nvshmem-cu12; sys_platform != 'win32'", ] nvidia_wheels_cu13 = [ - "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,nvvm]==13.*", + "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl,nvvm]==13.*", "cuda-toolkit[cufile]==13.*; sys_platform != 'win32'", "nvidia-nccl-cu13; sys_platform != 'win32'", "nvidia-nvshmem-cu13; sys_platform != 'win32'", diff --git a/cuda_pathfinder/tests/test_find_nvidia_headers.py b/cuda_pathfinder/tests/test_find_nvidia_headers.py index 603e28a0f4..8532d84354 100644 --- a/cuda_pathfinder/tests/test_find_nvidia_headers.py +++ b/cuda_pathfinder/tests/test_find_nvidia_headers.py @@ -23,7 +23,6 @@ from cuda.pathfinder import _find_nvidia_header_directory as find_nvidia_header_directory from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS from cuda.pathfinder._headers.supported_nvidia_headers import ( - CCCL_LIBNAMES, SUPPORTED_HEADERS_CTK, SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK, ) @@ -69,10 +68,6 @@ def test_supported_headers_site_packages_ctk_consistency(): assert tuple(sorted(SUPPORTED_HEADERS_CTK)) == tuple(sorted(SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK.keys())) -def test_supported_headers_cccl_libnames_consistency(): - assert set(CCCL_LIBNAMES).issubset(set(SUPPORTED_HEADERS_CTK.keys())) - - @pytest.mark.parametrize("libname", SUPPORTED_HEADERS_CTK.keys()) def test_find_ctk_headers(info_summary_append, libname): hdr_dir = find_nvidia_header_directory(libname) From c7cabd863033f9c6583089124cec9c91742e2470 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 9 Sep 2025 16:09:24 -0700 Subject: [PATCH 12/31] SUPPORTED_HEADERS_CTK_LINUX_ONLY etc. (for cufile) --- .../_headers/find_nvidia_headers.py | 2 +- .../_headers/supported_nvidia_headers.py | 20 +++++++++++++++++-- .../tests/test_find_nvidia_headers.py | 5 +++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index d573f08eef..f9c8df8cfc 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -7,8 +7,8 @@ import shutil from typing import Optional -from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS from cuda.pathfinder._headers import supported_nvidia_headers +from cuda.pathfinder._headers.supported_nvidia_headers import IS_WINDOWS from cuda.pathfinder._utils.env_vars import get_cuda_home_or_path from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index 7b22659960..ce813f9a11 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -1,12 +1,15 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -SUPPORTED_HEADERS_CTK = { +import sys + +IS_WINDOWS = sys.platform == "win32" + +SUPPORTED_HEADERS_CTK_COMMON = { "cccl": "cuda/std/version", "cublas": "cublas.h", "cudart": "cuda_runtime.h", "cufft": "cufft.h", - "cufile": "cufile.h", "curand": "curand.h", "cusolver": "cusolver_common.h", "cusparse": "cusparse.h", @@ -19,6 +22,19 @@ "nvvm": "nvvm.h", } +SUPPORTED_HEADERS_CTK_LINUX_ONLY = { + "cufile": "cufile.h", +} +SUPPORTED_HEADERS_CTK_LINUX = SUPPORTED_HEADERS_CTK_COMMON | SUPPORTED_HEADERS_CTK_LINUX_ONLY + +SUPPORTED_HEADERS_CTK_WINDOWS_ONLY: dict[str, str] = {} +SUPPORTED_HEADERS_CTK_WINDOWS = SUPPORTED_HEADERS_CTK_COMMON | SUPPORTED_HEADERS_CTK_WINDOWS_ONLY + +SUPPORTED_HEADERS_CTK_ALL = ( + SUPPORTED_HEADERS_CTK_COMMON | SUPPORTED_HEADERS_CTK_LINUX_ONLY | SUPPORTED_HEADERS_CTK_WINDOWS_ONLY +) +SUPPORTED_HEADERS_CTK = SUPPORTED_HEADERS_CTK_WINDOWS if IS_WINDOWS else SUPPORTED_HEADERS_CTK_LINUX + SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK = { "cccl": ( "cuda/cccl/headers/include", # cuda-cccl diff --git a/cuda_pathfinder/tests/test_find_nvidia_headers.py b/cuda_pathfinder/tests/test_find_nvidia_headers.py index 8532d84354..4f4ce422d8 100644 --- a/cuda_pathfinder/tests/test_find_nvidia_headers.py +++ b/cuda_pathfinder/tests/test_find_nvidia_headers.py @@ -21,9 +21,10 @@ import pytest from cuda.pathfinder import _find_nvidia_header_directory as find_nvidia_header_directory -from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import IS_WINDOWS from cuda.pathfinder._headers.supported_nvidia_headers import ( + IS_WINDOWS, SUPPORTED_HEADERS_CTK, + SUPPORTED_HEADERS_CTK_ALL, SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK, ) @@ -65,7 +66,7 @@ def test_find_libname_nvshmem(info_summary_append): def test_supported_headers_site_packages_ctk_consistency(): - assert tuple(sorted(SUPPORTED_HEADERS_CTK)) == tuple(sorted(SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK.keys())) + assert tuple(sorted(SUPPORTED_HEADERS_CTK_ALL)) == tuple(sorted(SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK.keys())) @pytest.mark.parametrize("libname", SUPPORTED_HEADERS_CTK.keys()) From 72db46d90ff73bd742fc2f83549bf0bcec79bf40 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 10 Sep 2025 16:10:28 -0700 Subject: [PATCH 13/31] Insert _find_based_on_conda_layout() --- .../cuda/pathfinder/_headers/find_nvidia_headers.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index f9c8df8cfc..8f3e185243 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -65,6 +65,14 @@ def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) return None +def _find_based_on_conda_layout(libname: str, h_basename: str, conda_prefix: str) -> Optional[str]: + targets_include_path = glob.glob(os.path.join(conda_prefix, "targets", "*", "include")) + if len(targets_include_path) != 1: + return None # Conda does not support multiple architectures. + anchor_point = os.path.dirname(targets_include_path[0]) + return _find_based_on_ctk_layout(libname, h_basename, anchor_point) + + @functools.cache def _get_nvcc_home() -> Optional[str]: # Fall back to the directory that owns nvcc (works for most local installs) @@ -90,7 +98,7 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: conda_prefix = os.getenv("CONDA_PREFIX") if conda_prefix: # noqa: SIM102 - if result := _find_based_on_ctk_layout(libname, h_basename, conda_prefix): + if result := _find_based_on_conda_layout(libname, h_basename, conda_prefix): return result cuda_home = get_cuda_home_or_path() From 62340000f8126a917dfe312836ee6f954539f518 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 10 Sep 2025 21:39:32 -0700 Subject: [PATCH 14/31] Remove `shutil.which("nvcc")` code (it finds all includes on Windows with conda) --- .../pathfinder/_headers/find_nvidia_headers.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 8f3e185243..68cf568c0f 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -4,7 +4,6 @@ import functools import glob import os -import shutil from typing import Optional from cuda.pathfinder._headers import supported_nvidia_headers @@ -73,18 +72,6 @@ def _find_based_on_conda_layout(libname: str, h_basename: str, conda_prefix: str return _find_based_on_ctk_layout(libname, h_basename, anchor_point) -@functools.cache -def _get_nvcc_home() -> Optional[str]: - # Fall back to the directory that owns nvcc (works for most local installs) - nvcc_path = shutil.which("nvcc") - if not nvcc_path: - return None - flds = nvcc_path.split(os.path.sep) - if len(flds) < 3: - return None - return os.path.sep.join(flds[:-2]) - - def _find_ctk_header_directory(libname: str) -> Optional[str]: h_basename = supported_nvidia_headers.SUPPORTED_HEADERS_CTK[libname] candidate_dirs = supported_nvidia_headers.SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK[libname] @@ -106,11 +93,6 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: if result := _find_based_on_ctk_layout(libname, h_basename, cuda_home): return result - nvcc_home = _get_nvcc_home() - if nvcc_home: # noqa: SIM102 - if result := _find_based_on_ctk_layout(libname, h_basename, nvcc_home): - return result - return None From 4d4ff77d2dff93e3534692e4a4cf8bd2490f630b Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 10 Sep 2025 21:41:48 -0700 Subject: [PATCH 15/31] Remove cccl code --- .../cuda/pathfinder/_headers/find_nvidia_headers.py | 4 ---- .../cuda/pathfinder/_headers/supported_nvidia_headers.py | 6 ------ 2 files changed, 10 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 68cf568c0f..b6dc8af492 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -54,10 +54,6 @@ def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) return idir else: idir = os.path.join(anchor_point, "include") - if libname == "cccl": - cdir = os.path.join(idir, "cccl") - if _joined_isfile(cdir, h_basename): - return cdir if _joined_isfile(idir, h_basename): return idir diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index ce813f9a11..7c4d2fbbc9 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -6,7 +6,6 @@ IS_WINDOWS = sys.platform == "win32" SUPPORTED_HEADERS_CTK_COMMON = { - "cccl": "cuda/std/version", "cublas": "cublas.h", "cudart": "cuda_runtime.h", "cufft": "cufft.h", @@ -36,11 +35,6 @@ SUPPORTED_HEADERS_CTK = SUPPORTED_HEADERS_CTK_WINDOWS if IS_WINDOWS else SUPPORTED_HEADERS_CTK_LINUX SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK = { - "cccl": ( - "cuda/cccl/headers/include", # cuda-cccl - "nvidia/cu13/include/cccl", # cuda-toolkit[cccl]==13.* - "nvidia/cuda_cccl/include", # cuda-toolkit[cccl]==12.* - ), "cublas": ("nvidia/cu13/include", "nvidia/cublas/include"), "cudart": ("nvidia/cu13/include", "nvidia/cuda_runtime/include"), "cufft": ("nvidia/cu13/include", "nvidia/cufft/include"), From 03bdbadc24becbc7898237794dcbfba4530874a9 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 10 Sep 2025 21:47:56 -0700 Subject: [PATCH 16/31] conda windows support --- .../pathfinder/_headers/find_nvidia_headers.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index b6dc8af492..c153bd0061 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -61,10 +61,19 @@ def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) def _find_based_on_conda_layout(libname: str, h_basename: str, conda_prefix: str) -> Optional[str]: - targets_include_path = glob.glob(os.path.join(conda_prefix, "targets", "*", "include")) - if len(targets_include_path) != 1: - return None # Conda does not support multiple architectures. - anchor_point = os.path.dirname(targets_include_path[0]) + if IS_WINDOWS: + anchor_point = os.path.join(conda_prefix, "Library") + if not os.path.isdir(anchor_point): + return None + else: + targets_include_path = glob.glob(os.path.join(conda_prefix, "targets", "*", "include")) + if not targets_include_path: + return None + if len(targets_include_path) != 1: + # Conda does not support multiple architectures. + # QUESTION(PR#956): Do we want to issue a warning? + return None + anchor_point = os.path.dirname(targets_include_path[0]) return _find_based_on_ctk_layout(libname, h_basename, anchor_point) From 0c5f6c21e6000afea25a5553d9ce5a15c677c2bd Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 10 Sep 2025 22:26:15 -0700 Subject: [PATCH 17/31] =?UTF-8?q?Replace=20cusolver=5Fcommon.h=20=E2=86=92?= =?UTF-8?q?=20cusolverDn.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cuda/pathfinder/_headers/supported_nvidia_headers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index 7c4d2fbbc9..d633e7025f 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -10,7 +10,7 @@ "cudart": "cuda_runtime.h", "cufft": "cufft.h", "curand": "curand.h", - "cusolver": "cusolver_common.h", + "cusolver": "cusolverDn.h", "cusparse": "cusparse.h", "npp": "npp.h", "nvcc": "fatbinary_section.h", From 1876f160c23e6af0404c42cf977e9a88c1793990 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Wed, 10 Sep 2025 23:06:20 -0700 Subject: [PATCH 18/31] UserWarning: Both CUDA_HOME and CUDA_PATH are set but differ --- .../cuda/pathfinder/_utils/env_vars.py | 46 ++++- cuda_pathfinder/tests/test_utils_env_vars.py | 181 ++++++++++++++++++ 2 files changed, 224 insertions(+), 3 deletions(-) create mode 100644 cuda_pathfinder/tests/test_utils_env_vars.py diff --git a/cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py b/cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py index 77f4a7d1ea..3a7de992c0 100644 --- a/cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py +++ b/cuda_pathfinder/cuda/pathfinder/_utils/env_vars.py @@ -2,11 +2,51 @@ # SPDX-License-Identifier: Apache-2.0 import os +import warnings from typing import Optional +def _paths_differ(a: str, b: str) -> bool: + """ + Return True if paths are observably different. + + Strategy: + 1) Compare os.path.normcase(os.path.normpath(...)) for quick, robust textual equality. + - Handles trailing slashes and case-insensitivity on Windows. + 2) If still different AND both exist, use os.path.samefile to resolve symlinks/junctions. + 3) Otherwise (nonexistent paths or samefile unavailable), treat as different. + """ + norm_a = os.path.normcase(os.path.normpath(a)) + norm_b = os.path.normcase(os.path.normpath(b)) + if norm_a == norm_b: + return False + + try: + if os.path.exists(a) and os.path.exists(b): + # samefile raises on non-existent paths; only call when both exist. + return not os.path.samefile(a, b) + except OSError: + # Fall through to "different" if samefile isn't applicable/available. + pass + + # If normalized strings differ and we couldn't prove they're the same entry, treat as different. + return True + + def get_cuda_home_or_path() -> Optional[str]: cuda_home = os.environ.get("CUDA_HOME") - if cuda_home is None: - cuda_home = os.environ.get("CUDA_PATH") - return cuda_home + cuda_path = os.environ.get("CUDA_PATH") + + if cuda_home and cuda_path and _paths_differ(cuda_home, cuda_path): + warnings.warn( + "Both CUDA_HOME and CUDA_PATH are set but differ:\n" + f" CUDA_HOME={cuda_home}\n" + f" CUDA_PATH={cuda_path}\n" + "Using CUDA_HOME (higher priority).", + UserWarning, + stacklevel=2, + ) + + if cuda_home is not None: + return cuda_home + return cuda_path diff --git a/cuda_pathfinder/tests/test_utils_env_vars.py b/cuda_pathfinder/tests/test_utils_env_vars.py new file mode 100644 index 0000000000..40c7d4930d --- /dev/null +++ b/cuda_pathfinder/tests/test_utils_env_vars.py @@ -0,0 +1,181 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +import os +import pathlib +import sys +import warnings + +import pytest + +from cuda.pathfinder._utils.env_vars import _paths_differ, get_cuda_home_or_path + +skip_symlink_tests = pytest.mark.skipif( + sys.platform == "win32", + reason="Exercising symlinks intentionally omitted for simplicity", +) + + +def unset_env(monkeypatch): + """Helper to clear both env vars for each test.""" + monkeypatch.delenv("CUDA_HOME", raising=False) + monkeypatch.delenv("CUDA_PATH", raising=False) + + +def test_returns_none_when_unset(monkeypatch): + unset_env(monkeypatch) + assert get_cuda_home_or_path() is None + + +def test_empty_cuda_home_preserved(monkeypatch): + # empty string is returned as-is if set. + monkeypatch.setenv("CUDA_HOME", "") + monkeypatch.setenv("CUDA_PATH", "/does/not/matter") + assert get_cuda_home_or_path() == "" + + +def test_prefers_cuda_home_over_cuda_path(monkeypatch, tmp_path): + unset_env(monkeypatch) + home = tmp_path / "home" + path = tmp_path / "path" + home.mkdir() + path.mkdir() + + monkeypatch.setenv("CUDA_HOME", str(home)) + monkeypatch.setenv("CUDA_PATH", str(path)) + + # Different directories -> warning + prefer CUDA_HOME + with pytest.warns(UserWarning, match="Both CUDA_HOME and CUDA_PATH are set but differ"): + result = get_cuda_home_or_path() + assert pathlib.Path(result) == home + + +def test_uses_cuda_path_if_home_missing(monkeypatch, tmp_path): + unset_env(monkeypatch) + only_path = tmp_path / "path" + only_path.mkdir() + monkeypatch.setenv("CUDA_PATH", str(only_path)) + assert pathlib.Path(get_cuda_home_or_path()) == only_path + + +def test_no_warning_when_textually_equal_after_normalization(monkeypatch, tmp_path): + """ + Trailing slashes should not trigger a warning, thanks to normpath. + This works cross-platform. + """ + unset_env(monkeypatch) + d = tmp_path / "cuda" + d.mkdir() + + with_slash = str(d) + ("/" if os.sep == "/" else "\\") + monkeypatch.setenv("CUDA_HOME", str(d)) + monkeypatch.setenv("CUDA_PATH", with_slash) + + # No warning; same logical directory + with warnings.catch_warnings(record=True) as record: + result = get_cuda_home_or_path() + assert pathlib.Path(result) == d + assert len(record) == 0 + + +@pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific case-folding check") +def test_no_warning_on_windows_case_only_difference(monkeypatch, tmp_path): + """ + On Windows, paths differing only by case should not warn because normcase collapses case. + """ + unset_env(monkeypatch) + d = tmp_path / "Cuda" + d.mkdir() + + upper = str(d).upper() + lower = str(d).lower() + monkeypatch.setenv("CUDA_HOME", upper) + monkeypatch.setenv("CUDA_PATH", lower) + + with warnings.catch_warnings(record=True) as record: + warnings.simplefilter("always") + result = get_cuda_home_or_path() + assert pathlib.Path(result).samefile(d) + assert len(record) == 0 + + +def test_warning_when_both_exist_and_are_different(monkeypatch, tmp_path): + unset_env(monkeypatch) + a = tmp_path / "a" + b = tmp_path / "b" + a.mkdir() + b.mkdir() + + monkeypatch.setenv("CUDA_HOME", str(a)) + monkeypatch.setenv("CUDA_PATH", str(b)) + + # Different actual dirs -> warning + with pytest.warns(UserWarning, match="Both CUDA_HOME and CUDA_PATH are set but differ"): + result = get_cuda_home_or_path() + assert pathlib.Path(result) == a + + +def test_nonexistent_paths_fall_back_to_text_comparison(monkeypatch, tmp_path): + """ + If one or both paths don't exist, we compare normalized strings. + Different strings should warn. + """ + unset_env(monkeypatch) + a = tmp_path / "does_not_exist_a" + b = tmp_path / "does_not_exist_b" + + monkeypatch.setenv("CUDA_HOME", str(a)) + monkeypatch.setenv("CUDA_PATH", str(b)) + + with pytest.warns(UserWarning, match="Both CUDA_HOME and CUDA_PATH are set but differ"): + result = get_cuda_home_or_path() + assert pathlib.Path(result) == a + + +@skip_symlink_tests +def test_samefile_equivalence_via_symlink_when_possible(monkeypatch, tmp_path): + """ + If both paths exist and one is a symlink/junction to the other, we should NOT warn. + """ + unset_env(monkeypatch) + real_dir = tmp_path / "real" + real_dir.mkdir() + + link_dir = tmp_path / "alias" + + os.symlink(str(real_dir), str(link_dir), target_is_directory=True) + + # Set env vars to real and alias + monkeypatch.setenv("CUDA_HOME", str(real_dir)) + monkeypatch.setenv("CUDA_PATH", str(link_dir)) + + # Because they resolve to the same entry, no warning should be raised + with warnings.catch_warnings(record=True) as record: + warnings.simplefilter("always") + result = get_cuda_home_or_path() + assert pathlib.Path(result) == real_dir + assert len(record) == 0 + + +# --- unit tests for the helper itself (optional but nice to have) --- + + +def test_paths_differ_text_only(tmp_path): + a = tmp_path / "x" + b = tmp_path / "x" / ".." / "x" # normalizes to same + assert _paths_differ(str(a), str(b)) is False + + a = tmp_path / "x" + b = tmp_path / "y" + assert _paths_differ(str(a), str(b)) is True + + +@skip_symlink_tests +def test_paths_differ_samefile(tmp_path): + real_dir = tmp_path / "r" + real_dir.mkdir() + alias = tmp_path / "alias" + os.symlink(str(real_dir), str(alias), target_is_directory=True) + + # Should detect equivalence via samefile + assert _paths_differ(str(real_dir), str(alias)) is False From 826398db17305486fa6668163fe4a3860f82995e Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 11 Sep 2025 09:55:36 -0700 Subject: [PATCH 19/31] Remove `cccl` again in pyproject.toml --- cuda_pathfinder/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/pyproject.toml b/cuda_pathfinder/pyproject.toml index e19244e3ea..bffb42a828 100644 --- a/cuda_pathfinder/pyproject.toml +++ b/cuda_pathfinder/pyproject.toml @@ -15,7 +15,7 @@ test = [ "pytest>=6.2.4", ] nvidia_wheels_cu12 = [ - "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl]==12.*", + "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg]==12.*", "cuda-toolkit[cufile]==12.*; sys_platform != 'win32'", "nvidia-cudss-cu12", "nvidia-cufftmp-cu12; sys_platform != 'win32'", @@ -24,7 +24,7 @@ nvidia_wheels_cu12 = [ "nvidia-nvshmem-cu12; sys_platform != 'win32'", ] nvidia_wheels_cu13 = [ - "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl,nvvm]==13.*", + "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,nvvm]==13.*", "cuda-toolkit[cufile]==13.*; sys_platform != 'win32'", "nvidia-nccl-cu13; sys_platform != 'win32'", "nvidia-nvshmem-cu13; sys_platform != 'win32'", From c023a0132634e7b04845eaa8ec3e9ece974ed5f9 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 15 Sep 2025 17:00:27 -0700 Subject: [PATCH 20/31] Revert "Remove `cccl` again in pyproject.toml" This reverts commit 826398db17305486fa6668163fe4a3860f82995e. --- cuda_pathfinder/pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/pyproject.toml b/cuda_pathfinder/pyproject.toml index 96ad7fb6aa..adfff29bb8 100644 --- a/cuda_pathfinder/pyproject.toml +++ b/cuda_pathfinder/pyproject.toml @@ -15,7 +15,7 @@ test = [ "pytest>=6.2.4", ] test_nvidia_wheels_cu12 = [ - "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg]==12.*", + "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl]==12.*", "cuda-toolkit[cufile]==12.*; sys_platform != 'win32'", "nvidia-cudss-cu12", "nvidia-cufftmp-cu12; sys_platform != 'win32'", @@ -24,7 +24,7 @@ test_nvidia_wheels_cu12 = [ "nvidia-nvshmem-cu12; sys_platform != 'win32'", ] test_nvidia_wheels_cu13 = [ - "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,nvvm]==13.*", + "cuda-toolkit[nvcc,cublas,nvrtc,cudart,cufft,curand,cusolver,cusparse,npp,nvfatbin,nvjitlink,nvjpeg,cccl,nvvm]==13.*", "cuda-toolkit[cufile]==13.*; sys_platform != 'win32'", "nvidia-nccl-cu13; sys_platform != 'win32'", "nvidia-nvshmem-cu13; sys_platform != 'win32'", From 476da62bcfaabeac94ea8960da56fa57decb937a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 15 Sep 2025 17:01:36 -0700 Subject: [PATCH 21/31] Revert "Remove cccl code" This reverts commit 4d4ff77d2dff93e3534692e4a4cf8bd2490f630b. --- .../cuda/pathfinder/_headers/find_nvidia_headers.py | 4 ++++ .../cuda/pathfinder/_headers/supported_nvidia_headers.py | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index c153bd0061..daf65596fb 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -54,6 +54,10 @@ def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) return idir else: idir = os.path.join(anchor_point, "include") + if libname == "cccl": + cdir = os.path.join(idir, "cccl") + if _joined_isfile(cdir, h_basename): + return cdir if _joined_isfile(idir, h_basename): return idir diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index d633e7025f..75d766c72f 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -6,6 +6,7 @@ IS_WINDOWS = sys.platform == "win32" SUPPORTED_HEADERS_CTK_COMMON = { + "cccl": "cuda/std/version", "cublas": "cublas.h", "cudart": "cuda_runtime.h", "cufft": "cufft.h", @@ -35,6 +36,11 @@ SUPPORTED_HEADERS_CTK = SUPPORTED_HEADERS_CTK_WINDOWS if IS_WINDOWS else SUPPORTED_HEADERS_CTK_LINUX SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK = { + "cccl": ( + "cuda/cccl/headers/include", # cuda-cccl + "nvidia/cu13/include/cccl", # cuda-toolkit[cccl]==13.* + "nvidia/cuda_cccl/include", # cuda-toolkit[cccl]==12.* + ), "cublas": ("nvidia/cu13/include", "nvidia/cublas/include"), "cudart": ("nvidia/cu13/include", "nvidia/cuda_runtime/include"), "cufft": ("nvidia/cu13/include", "nvidia/cufft/include"), From d42465e885fdb8cbecc24c39dcdbfe5d93cd770a Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 15 Sep 2025 17:05:22 -0700 Subject: [PATCH 22/31] Remove `cuda-cccl` include path in SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK --- .../cuda/pathfinder/_headers/supported_nvidia_headers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index 75d766c72f..69b3ffbf58 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -37,7 +37,6 @@ SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK = { "cccl": ( - "cuda/cccl/headers/include", # cuda-cccl "nvidia/cu13/include/cccl", # cuda-toolkit[cccl]==13.* "nvidia/cuda_cccl/include", # cuda-toolkit[cccl]==12.* ), From 17221d60d20dd2eeeb9b965fd971df62f45901d1 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 15 Sep 2025 17:19:51 -0700 Subject: [PATCH 23/31] Apply reviewer suggestion: https://github.com/NVIDIA/cuda-python/pull/956#discussion_r2350273284 --- .../_headers/find_nvidia_headers.py | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index daf65596fb..7d60821647 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -48,19 +48,17 @@ def _find_nvshmem_header_directory() -> Optional[str]: def _find_based_on_ctk_layout(libname: str, h_basename: str, anchor_point: str) -> Optional[str]: + parts = [anchor_point] if libname == "nvvm": - idir = os.path.join(anchor_point, "nvvm", "include") - if _joined_isfile(idir, h_basename): - return idir - else: - idir = os.path.join(anchor_point, "include") - if libname == "cccl": - cdir = os.path.join(idir, "cccl") - if _joined_isfile(cdir, h_basename): - return cdir - if _joined_isfile(idir, h_basename): - return idir - + parts.append(libname) + parts.append("include") + idir = os.path.join(*parts) + if libname == "cccl": + cdir = os.path.join(idir, "cccl") # CTK 13 + if _joined_isfile(cdir, h_basename): + return cdir + if _joined_isfile(idir, h_basename): + return idir return None From aea31bb6055acc65cc29849f2c43851f8482172f Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 15 Sep 2025 21:03:13 -0700 Subject: [PATCH 24/31] Add find_nvidia_header_directory docstring. --- .../_headers/find_nvidia_headers.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py index 7d60821647..f97f12c06a 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/find_nvidia_headers.py @@ -105,6 +105,42 @@ def _find_ctk_header_directory(libname: str) -> Optional[str]: @functools.cache def find_nvidia_header_directory(libname: str) -> Optional[str]: + """Locate the header directory for a supported NVIDIA library. + + Args: + libname (str): The short name of the library whose headers are needed + (e.g., ``"nvrtc"``, ``"cusolver"``, ``"nvshmem"``). + + Returns: + str or None: Absolute path to the discovered header directory, or ``None`` + if the headers cannot be found. + + Raises: + RuntimeError: If ``libname`` is not in the supported set. + + Search order: + 1. **NVIDIA Python wheels** + + - Scan installed distributions (``site-packages``) for header layouts + shipped in NVIDIA wheels (e.g., ``cuda-toolkit[nvrtc]``). + + 2. **Conda environments** + + - Check Conda-style installation prefixes, which use platform-specific + include directory layouts. + + 3. **CUDA Toolkit environment variables** + + - Use ``CUDA_HOME`` or ``CUDA_PATH`` (in that order). + + Notes: + - The ``SUPPORTED_HEADERS_CTK`` dictionary maps each supported CUDA Toolkit + (CTK) library to the name of its canonical header (e.g., ``"cublas" → + "cublas.h"``). This is used to verify that the located directory is valid. + + - The only supported non-CTK library at present is ``nvshmem``. + """ + if libname == "nvshmem": return _abs_norm(_find_nvshmem_header_directory()) From 57744710f51c77d5754a131e997e9d2cc7289880 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 15 Sep 2025 22:10:15 -0700 Subject: [PATCH 25/31] Add _SUPPORTED_HEADERS_CTK to public API --- cuda_pathfinder/cuda/pathfinder/__init__.py | 3 +++ .../cuda/pathfinder/_headers/supported_nvidia_headers.py | 9 ++++++++- cuda_pathfinder/docs/source/api.rst | 6 +++++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/__init__.py b/cuda_pathfinder/cuda/pathfinder/__init__.py index 53f2527c71..ef46d4b3b1 100644 --- a/cuda_pathfinder/cuda/pathfinder/__init__.py +++ b/cuda_pathfinder/cuda/pathfinder/__init__.py @@ -10,4 +10,7 @@ from cuda.pathfinder._headers.find_nvidia_headers import ( find_nvidia_header_directory as _find_nvidia_header_directory, # noqa: F401 ) +from cuda.pathfinder._headers.supported_nvidia_headers import ( + SUPPORTED_HEADERS_CTK as _SUPPORTED_HEADERS_CTK, # noqa: F401 +) from cuda.pathfinder._version import __version__ as __version__ diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index 69b3ffbf58..3636d9460b 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: Apache-2.0 import sys +from typing import Final IS_WINDOWS = sys.platform == "win32" @@ -33,7 +34,13 @@ SUPPORTED_HEADERS_CTK_ALL = ( SUPPORTED_HEADERS_CTK_COMMON | SUPPORTED_HEADERS_CTK_LINUX_ONLY | SUPPORTED_HEADERS_CTK_WINDOWS_ONLY ) -SUPPORTED_HEADERS_CTK = SUPPORTED_HEADERS_CTK_WINDOWS if IS_WINDOWS else SUPPORTED_HEADERS_CTK_LINUX +#: Mapping from short CUDA Toolkit (CTK) library names to their canonical +#: header basenames (used to validate a discovered include directory). +#: Example: ``"cublas" → "cublas.h"``. The key set is platform-aware +#: (e.g., ``"cufile"`` may be Linux-only). +SUPPORTED_HEADERS_CTK: Final[dict[str, str]] = ( + SUPPORTED_HEADERS_CTK_WINDOWS if IS_WINDOWS else SUPPORTED_HEADERS_CTK_LINUX +) SUPPORTED_SITE_PACKAGE_HEADER_DIRS_CTK = { "cccl": ( diff --git a/cuda_pathfinder/docs/source/api.rst b/cuda_pathfinder/docs/source/api.rst index 1870711a1e..c56c9661ac 100644 --- a/cuda_pathfinder/docs/source/api.rst +++ b/cuda_pathfinder/docs/source/api.rst @@ -6,7 +6,8 @@ ``cuda.pathfinder`` API Reference ================================= -The ``cuda.pathfinder`` module provides utilities for loading NVIDIA dynamic libraries. +The ``cuda.pathfinder`` module provides utilities for loading NVIDIA dynamic libraries, +and experimental APIs for locating NVIDIA C/C++ header directories. Public API ----------- @@ -18,3 +19,6 @@ Public API load_nvidia_dynamic_lib LoadedDL DynamicLibNotFoundError + + _SUPPORTED_HEADERS_CTK + _find_nvidia_header_directory From 306684d4c99ad6e00df28172b99fc0f361b4838d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Mon, 15 Sep 2025 22:16:33 -0700 Subject: [PATCH 26/31] Add cuda_pathfinder 1.2.3 Release notes --- cuda_pathfinder/docs/nv-versions.json | 4 ++++ cuda_pathfinder/docs/source/release.rst | 1 + .../docs/source/release/1.2.3-notes.rst | 17 +++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 cuda_pathfinder/docs/source/release/1.2.3-notes.rst diff --git a/cuda_pathfinder/docs/nv-versions.json b/cuda_pathfinder/docs/nv-versions.json index eb5b96a0a1..9fcc3f0ab1 100644 --- a/cuda_pathfinder/docs/nv-versions.json +++ b/cuda_pathfinder/docs/nv-versions.json @@ -3,6 +3,10 @@ "version": "latest", "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/latest/" }, + { + "version": "1.2.3", + "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/1.2.3/" + }, { "version": "1.2.2", "url": "https://nvidia.github.io/cuda-python/cuda-pathfinder/1.2.2/" diff --git a/cuda_pathfinder/docs/source/release.rst b/cuda_pathfinder/docs/source/release.rst index b7c0ff6e19..62dbf7ad6a 100644 --- a/cuda_pathfinder/docs/source/release.rst +++ b/cuda_pathfinder/docs/source/release.rst @@ -7,6 +7,7 @@ Release Notes .. toctree:: :maxdepth: 3 + 1.2.3 1.2.2 1.2.1 1.2.0 diff --git a/cuda_pathfinder/docs/source/release/1.2.3-notes.rst b/cuda_pathfinder/docs/source/release/1.2.3-notes.rst new file mode 100644 index 0000000000..7e097e10e3 --- /dev/null +++ b/cuda_pathfinder/docs/source/release/1.2.3-notes.rst @@ -0,0 +1,17 @@ +.. SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +.. SPDX-License-Identifier: Apache-2.0 + +.. module:: cuda.pathfinder + +``cuda-pathfinder`` 1.2.3 Release notes +======================================= + +Released on Sep 18, 2025 + + +Highlights +---------- + +* Extend experimental ``cuda.pathfinder._find_nvidia_headers`` API + to support CTK library headers + (`PR #956 `_) From caf4e52bf8cdd0e5cd7853677cda57863893310d Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 16 Sep 2025 14:09:39 -0700 Subject: [PATCH 27/31] Remove leading underscores: _SUPPORTED_HEADERS_CTK, _find_nvidia_header_directory --- cuda_pathfinder/cuda/pathfinder/__init__.py | 11 +++++------ cuda_pathfinder/docs/source/api.rst | 4 ++-- cuda_pathfinder/tests/test_find_nvidia_headers.py | 2 +- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/__init__.py b/cuda_pathfinder/cuda/pathfinder/__init__.py index ef46d4b3b1..bb6eb925de 100644 --- a/cuda_pathfinder/cuda/pathfinder/__init__.py +++ b/cuda_pathfinder/cuda/pathfinder/__init__.py @@ -7,10 +7,9 @@ from cuda.pathfinder._dynamic_libs.supported_nvidia_libs import ( SUPPORTED_LIBNAMES as SUPPORTED_NVIDIA_LIBNAMES, # noqa: F401 ) -from cuda.pathfinder._headers.find_nvidia_headers import ( - find_nvidia_header_directory as _find_nvidia_header_directory, # noqa: F401 -) -from cuda.pathfinder._headers.supported_nvidia_headers import ( - SUPPORTED_HEADERS_CTK as _SUPPORTED_HEADERS_CTK, # noqa: F401 -) +from cuda.pathfinder._headers.find_nvidia_headers import find_nvidia_header_directory as find_nvidia_header_directory +from cuda.pathfinder._headers.supported_nvidia_headers import SUPPORTED_HEADERS_CTK as SUPPORTED_HEADERS_CTK from cuda.pathfinder._version import __version__ as __version__ + +# Backward compatibility with release 1.2.2. To be removed in release 1.2.4. +_find_nvidia_header_directory = find_nvidia_header_directory diff --git a/cuda_pathfinder/docs/source/api.rst b/cuda_pathfinder/docs/source/api.rst index c56c9661ac..dbf8dd173d 100644 --- a/cuda_pathfinder/docs/source/api.rst +++ b/cuda_pathfinder/docs/source/api.rst @@ -20,5 +20,5 @@ Public API LoadedDL DynamicLibNotFoundError - _SUPPORTED_HEADERS_CTK - _find_nvidia_header_directory + SUPPORTED_HEADERS_CTK + find_nvidia_header_directory diff --git a/cuda_pathfinder/tests/test_find_nvidia_headers.py b/cuda_pathfinder/tests/test_find_nvidia_headers.py index 4f4ce422d8..da0f0e01e5 100644 --- a/cuda_pathfinder/tests/test_find_nvidia_headers.py +++ b/cuda_pathfinder/tests/test_find_nvidia_headers.py @@ -20,7 +20,7 @@ import pytest -from cuda.pathfinder import _find_nvidia_header_directory as find_nvidia_header_directory +from cuda.pathfinder import find_nvidia_header_directory from cuda.pathfinder._headers.supported_nvidia_headers import ( IS_WINDOWS, SUPPORTED_HEADERS_CTK, From 3faea76f6c12934a7db9d1c2bd7eb895e1f4b4f8 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 16 Sep 2025 14:32:46 -0700 Subject: [PATCH 28/31] docstring in __init__.py, using `#: ` Sphinx-specific markup A triple-quoted docstring worked for Sphinx but tripped up the check-docstring-first pre-commit check. --- cuda_pathfinder/cuda/pathfinder/__init__.py | 11 ++++++++++- .../pathfinder/_headers/supported_nvidia_headers.py | 4 ---- toolshed/setup-docs-env.sh | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/__init__.py b/cuda_pathfinder/cuda/pathfinder/__init__.py index bb6eb925de..729324f6e6 100644 --- a/cuda_pathfinder/cuda/pathfinder/__init__.py +++ b/cuda_pathfinder/cuda/pathfinder/__init__.py @@ -1,6 +1,8 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +"""cuda.pathfinder public APIs""" + from cuda.pathfinder._dynamic_libs.load_dl_common import DynamicLibNotFoundError as DynamicLibNotFoundError from cuda.pathfinder._dynamic_libs.load_dl_common import LoadedDL as LoadedDL from cuda.pathfinder._dynamic_libs.load_nvidia_dynamic_lib import load_nvidia_dynamic_lib as load_nvidia_dynamic_lib @@ -8,8 +10,15 @@ SUPPORTED_LIBNAMES as SUPPORTED_NVIDIA_LIBNAMES, # noqa: F401 ) from cuda.pathfinder._headers.find_nvidia_headers import find_nvidia_header_directory as find_nvidia_header_directory -from cuda.pathfinder._headers.supported_nvidia_headers import SUPPORTED_HEADERS_CTK as SUPPORTED_HEADERS_CTK +from cuda.pathfinder._headers.supported_nvidia_headers import SUPPORTED_HEADERS_CTK as _SUPPORTED_HEADERS_CTK from cuda.pathfinder._version import __version__ as __version__ +# Indirection to help Sphinx find the docstring. +#: Mapping from short CUDA Toolkit (CTK) library names to their canonical +#: header basenames (used to validate a discovered include directory). +#: Example: ``"cublas" → "cublas.h"``. The key set is platform-aware +#: (e.g., ``"cufile"`` may be Linux-only). +SUPPORTED_HEADERS_CTK = _SUPPORTED_HEADERS_CTK + # Backward compatibility with release 1.2.2. To be removed in release 1.2.4. _find_nvidia_header_directory = find_nvidia_header_directory diff --git a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py index 3636d9460b..afd9067de2 100644 --- a/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py +++ b/cuda_pathfinder/cuda/pathfinder/_headers/supported_nvidia_headers.py @@ -34,10 +34,6 @@ SUPPORTED_HEADERS_CTK_ALL = ( SUPPORTED_HEADERS_CTK_COMMON | SUPPORTED_HEADERS_CTK_LINUX_ONLY | SUPPORTED_HEADERS_CTK_WINDOWS_ONLY ) -#: Mapping from short CUDA Toolkit (CTK) library names to their canonical -#: header basenames (used to validate a discovered include directory). -#: Example: ``"cublas" → "cublas.h"``. The key set is platform-aware -#: (e.g., ``"cufile"`` may be Linux-only). SUPPORTED_HEADERS_CTK: Final[dict[str, str]] = ( SUPPORTED_HEADERS_CTK_WINDOWS if IS_WINDOWS else SUPPORTED_HEADERS_CTK_LINUX ) diff --git a/toolshed/setup-docs-env.sh b/toolshed/setup-docs-env.sh index 9d4768156e..16378725e9 100755 --- a/toolshed/setup-docs-env.sh +++ b/toolshed/setup-docs-env.sh @@ -65,4 +65,4 @@ echo "Build docs with e.g.:" echo " conda activate ${ENV_NAME}" echo " cd cuda_pathfinder/" echo " pip install -e ." -echo " (cd docs/ && rm -rf build && ./build_docs.sh)" +echo " (cd docs/ && rm -rf build source/generated && ./build_docs.sh)" From 5e1146c0f8ed4d9ebc9f2867df77f9d6b6133701 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 16 Sep 2025 15:22:19 -0700 Subject: [PATCH 29/31] Bump pathfinder version to 1.2.3 (for release) and change release date to Sep 17 --- cuda_pathfinder/cuda/pathfinder/_version.py | 2 +- cuda_pathfinder/docs/source/release/1.2.3-notes.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cuda_pathfinder/cuda/pathfinder/_version.py b/cuda_pathfinder/cuda/pathfinder/_version.py index 87dfcc13d2..001da9389f 100644 --- a/cuda_pathfinder/cuda/pathfinder/_version.py +++ b/cuda_pathfinder/cuda/pathfinder/_version.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 -__version__ = "1.2.3a0" +__version__ = "1.2.3" diff --git a/cuda_pathfinder/docs/source/release/1.2.3-notes.rst b/cuda_pathfinder/docs/source/release/1.2.3-notes.rst index 7e097e10e3..93128b2341 100644 --- a/cuda_pathfinder/docs/source/release/1.2.3-notes.rst +++ b/cuda_pathfinder/docs/source/release/1.2.3-notes.rst @@ -6,7 +6,7 @@ ``cuda-pathfinder`` 1.2.3 Release notes ======================================= -Released on Sep 18, 2025 +Released on Sep 17, 2025 Highlights From 59de4898ab7705739c97de514c8d4f9e723758db Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 16 Sep 2025 21:04:31 -0700 Subject: [PATCH 30/31] Make comment less ambiguous. --- cuda_pathfinder/cuda/pathfinder/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cuda_pathfinder/cuda/pathfinder/__init__.py b/cuda_pathfinder/cuda/pathfinder/__init__.py index 729324f6e6..d931a264cf 100644 --- a/cuda_pathfinder/cuda/pathfinder/__init__.py +++ b/cuda_pathfinder/cuda/pathfinder/__init__.py @@ -20,5 +20,6 @@ #: (e.g., ``"cufile"`` may be Linux-only). SUPPORTED_HEADERS_CTK = _SUPPORTED_HEADERS_CTK -# Backward compatibility with release 1.2.2. To be removed in release 1.2.4. +# Backward compatibility: _find_nvidia_header_directory was added in release 1.2.2. +# It will be removed in release 1.2.4. _find_nvidia_header_directory = find_nvidia_header_directory From 410d866d136605291544a68935398955d3cd8b57 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Tue, 16 Sep 2025 21:18:22 -0700 Subject: [PATCH 31/31] Remove subtitle as suggested by reviewer. --- cuda_pathfinder/docs/source/api.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/cuda_pathfinder/docs/source/api.rst b/cuda_pathfinder/docs/source/api.rst index dbf8dd173d..3cae4b6f70 100644 --- a/cuda_pathfinder/docs/source/api.rst +++ b/cuda_pathfinder/docs/source/api.rst @@ -9,9 +9,6 @@ The ``cuda.pathfinder`` module provides utilities for loading NVIDIA dynamic libraries, and experimental APIs for locating NVIDIA C/C++ header directories. -Public API ------------ - .. autosummary:: :toctree: generated/