Coverage for cuda / pathfinder / _static_libs / find_static_lib.py: 98.73%
79 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-08 01:07 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-08 01:07 +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_home_or_path
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_path: 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_path": os.path.join("lib", "x64") 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: 1facdb
64 raise ValueError(f"Unknown static library: '{name}'. Supported: {', '.join(SUPPORTED_STATIC_LIBS)}") 1f
65 self.name: str = name 1acdb
66 self.config: _StaticLibInfo = _SUPPORTED_STATIC_LIBS_INFO[name] 1acdb
67 self.filename: str = self.config["filename"] 1acdb
68 self.ctk_rel_paths: tuple[str, ...] = self.config["ctk_rel_paths"] 1acdb
69 self.conda_rel_path: str = self.config["conda_rel_path"] 1acdb
70 self.site_packages_dirs: tuple[str, ...] = self.config["site_packages_dirs"] 1acdb
71 self.error_messages: list[str] = [] 1acdb
72 self.attachments: list[str] = [] 1acdb
74 def try_site_packages(self) -> str | None:
75 for rel_dir in self.site_packages_dirs: 1acdb
76 sub_dir = tuple(rel_dir.split("/")) 1acdb
77 for abs_dir in find_sub_dirs_all_sitepackages(sub_dir): 1acdb
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 1acdb
83 def try_with_conda_prefix(self) -> str | None:
84 conda_prefix = os.environ.get("CONDA_PREFIX") 1acdb
85 if not conda_prefix: 1acdb
86 return None 1acd
88 anchor = os.path.join(conda_prefix, "Library") if IS_WINDOWS else conda_prefix 1b
89 file_path = os.path.join(anchor, self.conda_rel_path, self.filename) 1b
90 if os.path.isfile(file_path): 1b
91 return file_path 1b
92 return None 1b
94 def try_with_cuda_home(self) -> str | None:
95 cuda_home = get_cuda_home_or_path() 1acdb
96 if cuda_home is None: 1acdb
97 self.error_messages.append("CUDA_HOME/CUDA_PATH not set") 1c
98 return None 1c
100 for rel_path in self.ctk_rel_paths: 1adb
101 file_path = os.path.join(cuda_home, rel_path, self.filename) 1adb
102 if os.path.isfile(file_path): 1adb
103 return file_path 1db
105 _no_such_file_in_dir( 1a
106 os.path.join(cuda_home, self.ctk_rel_paths[0]),
107 self.filename,
108 self.error_messages,
109 self.attachments,
110 )
111 return None 1a
113 def raise_not_found_error(self) -> NoReturn:
114 err = ", ".join(self.error_messages) if self.error_messages else "No search paths available" 1ac
115 att = "\n".join(self.attachments) if self.attachments else "" 1ac
116 raise StaticLibNotFoundError(f'Failure finding "{self.filename}": {err}\n{att}') 1ac
119def locate_static_lib(name: str) -> LocatedStaticLib:
120 """Locate a static library by name.
122 Raises:
123 ValueError: If ``name`` is not a supported static library.
124 StaticLibNotFoundError: If the static library cannot be found.
125 """
126 finder = _FindStaticLib(name) 1facdb
128 abs_path = finder.try_site_packages() 1acdb
129 if abs_path is not None: 1acdb
130 return LocatedStaticLib( 1b
131 name=name,
132 abs_path=abs_path,
133 filename=finder.filename,
134 found_via="site-packages",
135 )
137 abs_path = finder.try_with_conda_prefix() 1acdb
138 if abs_path is not None: 1acdb
139 return LocatedStaticLib( 1b
140 name=name,
141 abs_path=abs_path,
142 filename=finder.filename,
143 found_via="conda",
144 )
146 abs_path = finder.try_with_cuda_home() 1acdb
147 if abs_path is not None: 1acdb
148 return LocatedStaticLib( 1db
149 name=name,
150 abs_path=abs_path,
151 filename=finder.filename,
152 found_via="CUDA_HOME",
153 )
155 finder.raise_not_found_error() 1ac
158@functools.cache
159def find_static_lib(name: str) -> str:
160 """Find the absolute path to a static library.
162 Raises:
163 ValueError: If ``name`` is not a supported static library.
164 StaticLibNotFoundError: If the static library cannot be found.
165 """
166 return locate_static_lib(name).abs_path 1acd