Coverage for cuda/pathfinder/_static_libs/find_static_lib.py: 98.89%

90 statements  

« prev     ^ index     » next       coverage.py v7.16.0, created at 2026-09-03 02:41 +0000

1# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 

2# SPDX-License-Identifier: Apache-2.0 

3 

4import functools 

5import os 

6from dataclasses import dataclass 

7from pathlib import Path 

8from typing import NoReturn, TypedDict 

9 

10from cuda.pathfinder._utils.env_vars import get_cuda_path_or_home 

11from cuda.pathfinder._utils.find_sub_dirs import find_sub_dirs_all_sitepackages 

12from cuda.pathfinder._utils.platform_aware import IS_WINDOWS 

13from cuda.pathfinder._utils.windows_arch import windows_python_arch 

14 

15 

16class StaticLibNotFoundError(RuntimeError): 

17 """Raised when a static library cannot be found.""" 

18 

19 

20@dataclass(frozen=True) 

21class LocatedStaticLib: 

22 """Information about a located static library.""" 

23 

24 name: str 

25 abs_path: str 

26 filename: str 

27 found_via: str 

28 

29 

30class _StaticLibInfo(TypedDict): 

31 """Static-library metadata with ordered alternatives searched first-to-last.""" 

32 

33 filename: str 

34 ctk_rel_paths: tuple[str, ...] 

35 conda_rel_paths: tuple[str, ...] 

36 site_packages_dirs: tuple[str, ...] 

37 

38 

39def _cudadevrt_info() -> _StaticLibInfo: 

40 if not IS_WINDOWS: 1cgh

41 return { 

42 "filename": "libcudadevrt.a", 

43 "ctk_rel_paths": ("lib64", "lib"), 

44 "conda_rel_paths": ("lib",), 

45 "site_packages_dirs": ("nvidia/cu13/lib", "nvidia/cuda_runtime/lib"), 

46 } 

47 

48 arch_dir = windows_python_arch() 1cgh

49 component_wheel_dirs = ("nvidia/cuda_runtime/lib/x64",) if arch_dir == "x64" else () 1cgh

50 conda_fallback_dirs = ("lib",) if arch_dir == "x64" else () 1cgh

51 return { 1cgh

52 "filename": "cudadevrt.lib", 

53 "ctk_rel_paths": (str(Path("lib", arch_dir)),), 

54 "conda_rel_paths": (str(Path("lib", arch_dir)), *conda_fallback_dirs), 

55 "site_packages_dirs": (f"nvidia/cu13/lib/{arch_dir}", *component_wheel_dirs), 

56 } 

57 

58 

59_SUPPORTED_STATIC_LIBS_INFO: dict[str, _StaticLibInfo] = { 

60 "cudadevrt": _cudadevrt_info(), 

61} 

62 

63SUPPORTED_STATIC_LIBS: tuple[str, ...] = tuple(sorted(_SUPPORTED_STATIC_LIBS_INFO.keys())) 

64 

65 

66def _no_such_file_in_dir(directory: Path, filename: str, error_messages: list[str], attachments: list[str]) -> None: 

67 error_messages.append(f"No such file: {directory / filename}") 1a

68 if directory.is_dir(): 1a

69 attachments.append(f' listdir("{directory}"):') 1a

70 for node in sorted(node_path.name for node_path in directory.iterdir()): 1a

71 attachments.append(f" {node}") 1a

72 else: 

73 attachments.append(f' Directory does not exist: "{directory}"') 

74 

75 

76class _FindStaticLib: 

77 def __init__(self, name: str) -> None: 

78 if name not in _SUPPORTED_STATIC_LIBS_INFO: 1iadefb

79 raise ValueError(f"Unknown static library: '{name}'. Supported: {', '.join(SUPPORTED_STATIC_LIBS)}") 1i

80 self.name: str = name 1adefb

81 self.config: _StaticLibInfo = _SUPPORTED_STATIC_LIBS_INFO[name] 1adefb

82 self.filename: str = self.config["filename"] 1adefb

83 self.ctk_rel_paths: tuple[str, ...] = self.config["ctk_rel_paths"] 1adefb

84 self.conda_rel_paths: tuple[str, ...] = self.config["conda_rel_paths"] 1adefb

85 self.site_packages_dirs: tuple[str, ...] = self.config["site_packages_dirs"] 1adefb

86 self.error_messages: list[str] = [] 1adefb

87 self.attachments: list[str] = [] 1adefb

88 

89 def try_site_packages(self) -> Path | None: 

90 for rel_dir in self.site_packages_dirs: 1adefb

91 sub_dir = tuple(rel_dir.split("/")) 1adefb

92 for abs_dir in find_sub_dirs_all_sitepackages(sub_dir): 1adefb

93 file_path = Path(abs_dir, self.filename) 1b

94 if file_path.is_file(): 1b

95 return file_path 1b

96 return None 1adefb

97 

98 def try_with_conda_prefix(self) -> Path | None: 

99 conda_prefix = os.environ.get("CONDA_PREFIX") 1adefb

100 if not conda_prefix: 1adefb

101 return None 1ade

102 

103 anchor = Path(conda_prefix, "Library") if IS_WINDOWS else Path(conda_prefix) 1fb

104 for rel_path in self.conda_rel_paths: 1fb

105 file_path = anchor / rel_path / self.filename 1fb

106 if file_path.is_file(): 1fb

107 return file_path 1fb

108 return None 1b

109 

110 def try_with_cuda_home(self) -> Path | None: 

111 cuda_home = get_cuda_path_or_home() 1adeb

112 if cuda_home is None: 1adeb

113 self.error_messages.append("CUDA_HOME/CUDA_PATH not set") 1d

114 return None 1d

115 

116 anchor = Path(cuda_home) 1aeb

117 for rel_path in self.ctk_rel_paths: 1aeb

118 file_path = anchor / rel_path / self.filename 1aeb

119 if file_path.is_file(): 1aeb

120 return file_path 1eb

121 

122 _no_such_file_in_dir( 1a

123 anchor / self.ctk_rel_paths[0], 

124 self.filename, 

125 self.error_messages, 

126 self.attachments, 

127 ) 

128 return None 1a

129 

130 def raise_not_found_error(self) -> NoReturn: 

131 err = ", ".join(self.error_messages) if self.error_messages else "No search paths available" 1ad

132 att = "\n".join(self.attachments) if self.attachments else "" 1ad

133 raise StaticLibNotFoundError(f'Failure finding "{self.filename}": {err}\n{att}') 1ad

134 

135 

136def locate_static_lib(name: str) -> LocatedStaticLib: 

137 """Locate a static library by name. 

138 

139 Raises: 

140 ValueError: If ``name`` is not a supported static library. 

141 StaticLibNotFoundError: If the static library cannot be found. 

142 """ 

143 finder = _FindStaticLib(name) 1iadefb

144 

145 abs_path = finder.try_site_packages() 1adefb

146 if abs_path is not None: 1adefb

147 return LocatedStaticLib( 1b

148 name=name, 

149 abs_path=str(abs_path), 

150 filename=finder.filename, 

151 found_via="site-packages", 

152 ) 

153 

154 abs_path = finder.try_with_conda_prefix() 1adefb

155 if abs_path is not None: 1adefb

156 return LocatedStaticLib( 1fb

157 name=name, 

158 abs_path=str(abs_path), 

159 filename=finder.filename, 

160 found_via="conda", 

161 ) 

162 

163 abs_path = finder.try_with_cuda_home() 1adeb

164 if abs_path is not None: 1adeb

165 return LocatedStaticLib( 1eb

166 name=name, 

167 abs_path=str(abs_path), 

168 filename=finder.filename, 

169 found_via="CUDA_PATH", 

170 ) 

171 

172 finder.raise_not_found_error() 1ad

173 

174 

175@functools.cache 

176def find_static_lib(name: str) -> str: 

177 """Find the absolute path to a static library. 

178 

179 Raises: 

180 ValueError: If ``name`` is not a supported static library. 

181 StaticLibNotFoundError: If the static library cannot be found. 

182 

183 Windows on ARM (WoA) Note: 

184 On Windows, this API aims to return the path to a static library whose 

185 architecture matches the Python interpreter architecture. For example, 

186 x64 Python running on an Arm64 machine targets the x64 library, while 

187 native Arm64 Python targets the Arm64 library. This differs from 

188 ``find_nvidia_binary_utility``, which targets the native machine 

189 architecture when selecting architecture-specific executables. 

190 """ 

191 return locate_static_lib(name).abs_path 1ade