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

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 typing import NoReturn, TypedDict 

8 

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 

12 

13 

14class StaticLibNotFoundError(RuntimeError): 

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

16 

17 

18@dataclass(frozen=True) 

19class LocatedStaticLib: 

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

21 

22 name: str 

23 abs_path: str 

24 filename: str 

25 found_via: str 

26 

27 

28class _StaticLibInfo(TypedDict): 

29 filename: str 

30 ctk_rel_paths: tuple[str, ...] 

31 conda_rel_paths: tuple[str, ...] 

32 site_packages_dirs: tuple[str, ...] 

33 

34 

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} 

47 

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

49 

50 

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}"') 

59 

60 

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

73 

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

82 

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

87 

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

94 

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

100 

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

105 

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

113 

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

118 

119 

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

121 """Locate a static library by name. 

122 

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

128 

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 ) 

137 

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 ) 

146 

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 ) 

155 

156 finder.raise_not_found_error() 1ac

157 

158 

159@functools.cache 

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

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

162 

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