55import os
66
77from cuda .pathfinder ._binaries import supported_nvidia_binaries
8+ from cuda .pathfinder ._utils .ctk_root_canary import CTK_ROOT_CANARY_ANCHOR_LIBNAMES
89from cuda .pathfinder ._utils .env_vars import get_cuda_path_or_home
910from cuda .pathfinder ._utils .find_sub_dirs import find_sub_dirs_all_sitepackages
1011from cuda .pathfinder ._utils .platform_aware import IS_WINDOWS
1112
12- # CUDA Toolkit canary library used to derive the toolkit root when it is only
13- # visible through the dynamic loader. ``cudart`` always ships with the CTK and
14- # matches the anchor used by the dynamic-library CTK-root canary flow.
15- _CTK_ROOT_CANARY_ANCHOR_LIBNAME = "cudart"
16-
1713
1814class UnsupportedBinaryError (Exception ):
1915 def __init__ (self , utility : str ) -> None :
@@ -37,7 +33,7 @@ def _is_executable_file(path: str) -> bool:
3733
3834 On Windows executability is determined by the file extension (the
3935 candidate name already carries one), so existence is sufficient. On POSIX
40- the execute permission bit must be set, matching ``shutil.which`` .
36+ the execute permission bit must be set.
4137 """
4238 if not os .path .isfile (path ):
4339 return False
@@ -47,11 +43,6 @@ def _is_executable_file(path: str) -> bool:
4743
4844
4945def _ctk_bin_subdirs (root : str ) -> list [str ]:
50- """Return the bin directories to search under a CUDA Toolkit ``root``.
51-
52- On Windows the CTK ships binaries under ``bin/x64`` (CTK 13), ``bin/x86_64``,
53- and ``bin`` (CTK 12); on Linux they live in ``bin``.
54- """
5546 if IS_WINDOWS :
5647 return [
5748 os .path .join (root , "bin" , "x64" ),
@@ -62,34 +53,19 @@ def _ctk_bin_subdirs(root: str) -> list[str]:
6253
6354
6455def _resolve_ctk_root_via_canary () -> str | None :
65- """Derive the CUDA Toolkit root from the ``cudart`` canary library.
66-
67- ``cudart`` is resolved by the OS dynamic loader, which honors
68- ``LD_LIBRARY_PATH`` on Linux and the native DLL search on Windows, and the
69- toolkit root is derived from its absolute path. The ambient ``PATH`` is
70- never consulted. The loader module is imported lazily to avoid pulling the
71- dynamic-library machinery in at import time.
72- """
7356 from cuda .pathfinder ._dynamic_libs .load_nvidia_dynamic_lib import resolve_ctk_root_via_canary
7457
75- ctk_root : str | None = resolve_ctk_root_via_canary (_CTK_ROOT_CANARY_ANCHOR_LIBNAME )
58+ ctk_root : str | None = resolve_ctk_root_via_canary (CTK_ROOT_CANARY_ANCHOR_LIBNAMES [ 0 ] )
7659 return ctk_root
7760
7861
7962def _resolve_in_trusted_dirs (normalized_name : str , dirs : list [str ]) -> str | None :
80- """Resolve ``normalized_name`` against ``dirs`` only, in order.
81-
82- Unlike ``shutil.which``, this never consults the current working directory
83- or the ambient ``PATH``. On Windows ``shutil.which`` prepends the process
84- CWD to the search even when an explicit ``path=`` is supplied, which lets a
85- binary sitting in an arbitrary CWD shadow the trusted CUDA / Conda / wheel
86- binary that pathfinder is contracted to discover. Searching the trusted
87- directories explicitly keeps the lookup deterministic and bounded.
88- """
63+ """Resolve ``normalized_name`` against ``dirs`` in order."""
8964 seen : set [str ] = set ()
9065 for directory in dirs :
91- if not directory or directory in seen :
66+ if directory in seen :
9267 continue
68+ assert directory
9369 seen .add (directory )
9470 candidate = os .path .join (directory , normalized_name )
9571 if _is_executable_file (candidate ):
@@ -137,11 +113,8 @@ def find_nvidia_binary_utility(utility_name: str) -> str | None:
137113 4. **CTK-root canary fallback**
138114
139115 - Only when steps 1-3 miss: resolve the ``cudart`` library through the
140- OS dynamic loader (which honors ``LD_LIBRARY_PATH`` on Linux and the
141- native DLL search on Windows), derive the CUDA Toolkit root from it,
142- and search that root's bin layout. This finds the utility for users
143- who follow the CUDA install guide and set ``LD_LIBRARY_PATH`` for
144- libraries without also setting ``CUDA_HOME`` / ``CUDA_PATH``.
116+ OS dynamic loader, derive the CUDA Toolkit root from it, and search
117+ that root's bin layout.
145118
146119 Note:
147120 Results are cached using ``@functools.cache`` for performance. The cache
@@ -152,8 +125,7 @@ def find_nvidia_binary_utility(utility_name: str) -> str | None:
152125 are identified by the ``X_OK`` (execute) permission bit.
153126
154127 Lookup is restricted to the trusted directories and the canary-derived
155- CTK root listed above; the process working directory and the ambient
156- ``PATH`` are never consulted.
128+ CTK root listed above.
157129
158130 Example:
159131 >>> from cuda.pathfinder import find_nvidia_binary_utility
@@ -187,9 +159,7 @@ def find_nvidia_binary_utility(utility_name: str) -> str | None:
187159 if found is not None :
188160 return found
189161
190- # 4. CTK-root canary fallback: only when the explicit trusted dirs above
191- # miss. Resolve cudart via the dynamic loader (honors LD_LIBRARY_PATH),
192- # derive the toolkit root, and search its bin layout. PATH is never used.
162+ # 4. CTK-root canary fallback.
193163 ctk_root = _resolve_ctk_root_via_canary ()
194164 if ctk_root is not None :
195165 return _resolve_in_trusted_dirs (normalized_name , _ctk_bin_subdirs (ctk_root ))
0 commit comments