Coverage for cuda / pathfinder / _static_libs / find_bitcode_lib.py: 98.70%
77 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) 2025-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 BitcodeLibNotFoundError(RuntimeError):
15 """Raised when a bitcode library cannot be found."""
18@dataclass(frozen=True)
19class LocatedBitcodeLib:
20 """Information about a located bitcode library."""
22 name: str
23 abs_path: str
24 filename: str
25 found_via: str
28class _BitcodeLibInfo(TypedDict):
29 filename: str
30 rel_path: str
31 site_packages_dirs: tuple[str, ...]
34_SUPPORTED_BITCODE_LIBS_INFO: dict[str, _BitcodeLibInfo] = {
35 "device": {
36 "filename": "libdevice.10.bc",
37 "rel_path": os.path.join("nvvm", "libdevice"),
38 "site_packages_dirs": (
39 "nvidia/cu13/nvvm/libdevice",
40 "nvidia/cuda_nvcc/nvvm/libdevice",
41 ),
42 },
43}
45# Public API: just the supported library names
46SUPPORTED_BITCODE_LIBS: tuple[str, ...] = tuple(sorted(_SUPPORTED_BITCODE_LIBS_INFO.keys()))
49def _no_such_file_in_dir(dir_path: str, filename: str, error_messages: list[str], attachments: list[str]) -> None:
50 error_messages.append(f"No such file: {os.path.join(dir_path, filename)}") 1a
51 if os.path.isdir(dir_path): 1a
52 attachments.append(f' listdir("{dir_path}"):') 1a
53 for node in sorted(os.listdir(dir_path)): 1a
54 attachments.append(f" {node}") 1a
55 else:
56 attachments.append(f' Directory does not exist: "{dir_path}"')
59class _FindBitcodeLib:
60 def __init__(self, name: str) -> None:
61 if name not in _SUPPORTED_BITCODE_LIBS_INFO: # Updated reference 1facdb
62 raise ValueError(f"Unknown bitcode library: '{name}'. Supported: {', '.join(SUPPORTED_BITCODE_LIBS)}") 1f
63 self.name: str = name 1acdb
64 self.config: _BitcodeLibInfo = _SUPPORTED_BITCODE_LIBS_INFO[name] # Updated reference 1acdb
65 self.filename: str = self.config["filename"] 1acdb
66 self.rel_path: str = self.config["rel_path"] 1acdb
67 self.site_packages_dirs: tuple[str, ...] = self.config["site_packages_dirs"] 1acdb
68 self.error_messages: list[str] = [] 1acdb
69 self.attachments: list[str] = [] 1acdb
71 def try_site_packages(self) -> str | None:
72 for rel_dir in self.site_packages_dirs: 1acdb
73 sub_dir = tuple(rel_dir.split("/")) 1acdb
74 for abs_dir in find_sub_dirs_all_sitepackages(sub_dir): 1acdb
75 file_path = os.path.join(abs_dir, self.filename) 1b
76 if os.path.isfile(file_path): 1b
77 return file_path 1b
78 return None 1acdb
80 def try_with_conda_prefix(self) -> str | None:
81 conda_prefix = os.environ.get("CONDA_PREFIX") 1acdb
82 if not conda_prefix: 1acdb
83 return None 1acd
85 anchor = os.path.join(conda_prefix, "Library") if IS_WINDOWS else conda_prefix 1b
86 file_path = os.path.join(anchor, self.rel_path, self.filename) 1b
87 if os.path.isfile(file_path): 1b
88 return file_path 1b
89 return None 1b
91 def try_with_cuda_home(self) -> str | None:
92 cuda_home = get_cuda_home_or_path() 1acdb
93 if cuda_home is None: 1acdb
94 self.error_messages.append("CUDA_HOME/CUDA_PATH not set") 1c
95 return None 1c
97 file_path = os.path.join(cuda_home, self.rel_path, self.filename) 1adb
98 if os.path.isfile(file_path): 1adb
99 return file_path 1db
101 _no_such_file_in_dir( 1a
102 os.path.join(cuda_home, self.rel_path),
103 self.filename,
104 self.error_messages,
105 self.attachments,
106 )
107 return None 1a
109 def raise_not_found_error(self) -> NoReturn:
110 err = ", ".join(self.error_messages) if self.error_messages else "No search paths available" 1ac
111 att = "\n".join(self.attachments) if self.attachments else "" 1ac
112 raise BitcodeLibNotFoundError(f'Failure finding "{self.filename}": {err}\n{att}') 1ac
115def locate_bitcode_lib(name: str) -> LocatedBitcodeLib:
116 """Locate a bitcode library by name.
118 Raises:
119 ValueError: If ``name`` is not a supported bitcode library.
120 BitcodeLibNotFoundError: If the bitcode library cannot be found.
121 """
122 finder = _FindBitcodeLib(name) 1facdb
124 abs_path = finder.try_site_packages() 1acdb
125 if abs_path is not None: 1acdb
126 return LocatedBitcodeLib( 1b
127 name=name,
128 abs_path=abs_path,
129 filename=finder.filename,
130 found_via="site-packages",
131 )
133 abs_path = finder.try_with_conda_prefix() 1acdb
134 if abs_path is not None: 1acdb
135 return LocatedBitcodeLib( 1b
136 name=name,
137 abs_path=abs_path,
138 filename=finder.filename,
139 found_via="conda",
140 )
142 abs_path = finder.try_with_cuda_home() 1acdb
143 if abs_path is not None: 1acdb
144 return LocatedBitcodeLib( 1db
145 name=name,
146 abs_path=abs_path,
147 filename=finder.filename,
148 found_via="CUDA_HOME",
149 )
151 finder.raise_not_found_error() 1ac
154@functools.cache
155def find_bitcode_lib(name: str) -> str:
156 """Find the absolute path to a bitcode library.
158 Raises:
159 ValueError: If ``name`` is not a supported bitcode library.
160 BitcodeLibNotFoundError: If the bitcode library cannot be found.
161 """
162 return locate_bitcode_lib(name).abs_path 1acd