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

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_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 

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_path: 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_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} 

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: 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

73 

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

82 

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

87 

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

93 

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

99 

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

104 

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

112 

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

117 

118 

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

120 """Locate a static library by name. 

121 

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

127 

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 ) 

136 

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 ) 

145 

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 ) 

154 

155 finder.raise_not_found_error() 1ac

156 

157 

158@functools.cache 

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

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

161 

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