Coverage for cuda / pathfinder / _static_libs / find_static_lib.py: 98.75%
80 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-22 01:37 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-22 01:37 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2# SPDX-License-Identifier: Apache-2.0
4import functools
5import os
6from dataclasses import dataclass
7from typing import NoReturn, TypedDict
9from cuda.pathfinder._utils.env_vars import get_cuda_path_or_home
10from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages
11from cuda.pathfinder._utils.platform_aware import IS_WINDOWS
14class StaticLibNotFoundError(RuntimeError):
15 """Raised when a static library cannot be found."""
18@dataclass(frozen=True)
19class LocatedStaticLib:
20 """Information about a located static library."""
22 name: str
23 abs_path: str
24 filename: str
25 found_via: str
28class _StaticLibInfo(TypedDict):
29 filename: str
30 ctk_rel_paths: tuple[str, ...]
31 conda_rel_paths: tuple[str, ...]
32 site_packages_dirs: tuple[str, ...]
35_SUPPORTED_STATIC_LIBS_INFO: dict[str, _StaticLibInfo] = {
36 "cudadevrt": {
37 "filename": "cudadevrt.lib" if IS_WINDOWS else "libcudadevrt.a",
38 "ctk_rel_paths": (os.path.join("lib", "x64"),) if IS_WINDOWS else ("lib64", "lib"),
39 "conda_rel_paths": ((os.path.join("lib", "x64"), "lib") if IS_WINDOWS else ("lib",)),
40 "site_packages_dirs": (
41 ("nvidia/cu13/lib/x64", "nvidia/cuda_runtime/lib/x64")
42 if IS_WINDOWS
43 else ("nvidia/cu13/lib", "nvidia/cuda_runtime/lib")
44 ),
45 },
46}
48SUPPORTED_STATIC_LIBS: tuple[str, ...] = tuple(sorted(_SUPPORTED_STATIC_LIBS_INFO.keys()))
51def _no_such_file_in_dir(dir_path: str, filename: str, error_messages: list[str], attachments: list[str]) -> None:
52 error_messages.append(f"No such file: {os.path.join(dir_path, filename)}") 1a
53 if os.path.isdir(dir_path): 1a
54 attachments.append(f' listdir("{dir_path}"):') 1a
55 for node in sorted(os.listdir(dir_path)): 1a
56 attachments.append(f" {node}") 1a
57 else:
58 attachments.append(f' Directory does not exist: "{dir_path}"')
61class _FindStaticLib:
62 def __init__(self, name: str) -> None:
63 if name not in _SUPPORTED_STATIC_LIBS_INFO: 1gacdeb
64 raise ValueError(f"Unknown static library: '{name}'. Supported: {', '.join(SUPPORTED_STATIC_LIBS)}") 1g
65 self.name: str = name 1acdeb
66 self.config: _StaticLibInfo = _SUPPORTED_STATIC_LIBS_INFO[name] 1acdeb
67 self.filename: str = self.config["filename"] 1acdeb
68 self.ctk_rel_paths: tuple[str, ...] = self.config["ctk_rel_paths"] 1acdeb
69 self.conda_rel_paths: tuple[str, ...] = self.config["conda_rel_paths"] 1acdeb
70 self.site_packages_dirs: tuple[str, ...] = self.config["site_packages_dirs"] 1acdeb
71 self.error_messages: list[str] = [] 1acdeb
72 self.attachments: list[str] = [] 1acdeb
74 def try_site_packages(self) -> str | None:
75 for rel_dir in self.site_packages_dirs: 1acdeb
76 sub_dir = tuple(rel_dir.split("/")) 1acdeb
77 for abs_dir in find_sub_dirs_all_sitepackages(sub_dir): 1acdeb
78 file_path = os.path.join(abs_dir, self.filename) 1b
79 if os.path.isfile(file_path): 1b
80 return file_path 1b
81 return None 1acdeb
83 def try_with_conda_prefix(self) -> str | None:
84 conda_prefix = os.environ.get("CONDA_PREFIX") 1acdeb
85 if not conda_prefix: 1acdeb
86 return None 1acd
88 anchor = os.path.join(conda_prefix, "Library") if IS_WINDOWS else conda_prefix 1eb
89 for rel_path in self.conda_rel_paths: 1eb
90 file_path = os.path.join(anchor, rel_path, self.filename) 1eb
91 if os.path.isfile(file_path): 1eb
92 return file_path 1eb
93 return None 1b
95 def try_with_cuda_home(self) -> str | None:
96 cuda_home = get_cuda_path_or_home() 1acdb
97 if cuda_home is None: 1acdb
98 self.error_messages.append("CUDA_HOME/CUDA_PATH not set") 1c
99 return None 1c
101 for rel_path in self.ctk_rel_paths: 1adb
102 file_path = os.path.join(cuda_home, rel_path, self.filename) 1adb
103 if os.path.isfile(file_path): 1adb
104 return file_path 1db
106 _no_such_file_in_dir( 1a
107 os.path.join(cuda_home, self.ctk_rel_paths[0]),
108 self.filename,
109 self.error_messages,
110 self.attachments,
111 )
112 return None 1a
114 def raise_not_found_error(self) -> NoReturn:
115 err = ", ".join(self.error_messages) if self.error_messages else "No search paths available" 1ac
116 att = "\n".join(self.attachments) if self.attachments else "" 1ac
117 raise StaticLibNotFoundError(f'Failure finding "{self.filename}": {err}\n{att}') 1ac
120def locate_static_lib(name: str) -> LocatedStaticLib:
121 """Locate a static library by name.
123 Raises:
124 ValueError: If ``name`` is not a supported static library.
125 StaticLibNotFoundError: If the static library cannot be found.
126 """
127 finder = _FindStaticLib(name) 1gacdeb
129 abs_path = finder.try_site_packages() 1acdeb
130 if abs_path is not None: 1acdeb
131 return LocatedStaticLib( 1b
132 name=name,
133 abs_path=abs_path,
134 filename=finder.filename,
135 found_via="site-packages",
136 )
138 abs_path = finder.try_with_conda_prefix() 1acdeb
139 if abs_path is not None: 1acdeb
140 return LocatedStaticLib( 1eb
141 name=name,
142 abs_path=abs_path,
143 filename=finder.filename,
144 found_via="conda",
145 )
147 abs_path = finder.try_with_cuda_home() 1acdb
148 if abs_path is not None: 1acdb
149 return LocatedStaticLib( 1db
150 name=name,
151 abs_path=abs_path,
152 filename=finder.filename,
153 found_via="CUDA_PATH",
154 )
156 finder.raise_not_found_error() 1ac
159@functools.cache
160def find_static_lib(name: str) -> str:
161 """Find the absolute path to a static library.
163 Raises:
164 ValueError: If ``name`` is not a supported static library.
165 StaticLibNotFoundError: If the static library cannot be found.
166 """
167 return locate_static_lib(name).abs_path 1acd