Coverage for cuda/core/_linker.pyx: 66.67%

426 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-16 01:23 +0000

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

2# 

3# SPDX-License-Identifier: Apache-2.0 

4"""Linking machinery for combining object codes. 

5  

6This module provides :class:`Linker` for linking one or more 

7:class:`~cuda.core.ObjectCode` objects, with :class:`LinkerOptions` for 

8configuration. 

9""" 

10  

11from __future__ import annotations 

12  

13from cpython.bytearray cimport PyByteArray_AS_STRING 

14from libc.stdint cimport intptr_t, uint32_t 

15from libcpp.vector cimport vector 

16from cuda.bindings cimport cydriver 

17from cuda.bindings cimport cynvjitlink 

18  

19from ._rt cimport ( 

20 as_cu, 

21 as_py, 

22 create_culink_handle, 

23 create_nvjitlink_handle, 

24) 

25from cuda.core._utils.cuda_utils cimport HANDLE_RETURN, HANDLE_RETURN_NVJITLINK 

26  

27import sys 

28from dataclasses import dataclass 

29from typing import TYPE_CHECKING, Union 

30from warnings import warn 

31  

32from cuda.pathfinder import DynamicLibNotFoundError 

33from cuda.bindings import nvjitlink as _nvjitlink_bindings 

34from cuda.core._device import Device 

35from cuda.core._module import ObjectCode 

36from cuda.core._utils.clear_error_support import assert_type 

37from cuda.core._utils.cuda_utils import ( 

38 CUDAError, 

39 check_or_create_options, 

40 driver, 

41 is_sequence, 

42) 

43from cuda.core.typing import CompilerBackendType, ObjectCodeFormatType 

44  

45if TYPE_CHECKING: 

46 import cuda.bindings.driver # no-cython-lint 

47 import cuda.bindings.nvjitlink # no-cython-lint 

48  

49# Module-level annotations to ensure stubgen-pyx keeps the above imports in 

50# the generated `.pyi` so that the LinkerHandleT forward references resolve. 

51# These names are not assigned, so they only affect __annotations__. 

52_keep_driver_in_stub: "cuda.bindings.driver.CUlinkState" 

53_keep_nvjitlink_in_stub: "cuda.bindings.nvjitlink.nvJitLinkHandle" 

54  

55ctypedef const char* const_char_ptr 

56  

57__all__ = ["Linker", "LinkerOptions"] 

58  

59LinkerHandleT = Union["cuda.bindings.nvjitlink.nvJitLinkHandle", "cuda.bindings.driver.CUlinkState"] 

60  

61  

62# ============================================================================= 

63# Principal class 

64# ============================================================================= 

65  

66  

67cdef inline int Linker_check_open(Linker self) except -1: 

68 if self.is_closed: 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJqrsfcghijkdl

69 raise RuntimeError("Linker has been closed") 1m

70 return 0 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJqrsfcghijkdl

71  

72  

73cdef class Linker: 

74 """Represent a linking machinery to link one or more object codes into 

75 :class:`~cuda.core.ObjectCode`. 

76  

77 This object provides a unified interface to multiple underlying 

78 linker libraries (such as nvJitLink or cuLink* from the CUDA driver). 

79  

80 Parameters 

81 ---------- 

82 object_codes : :class:`~cuda.core.ObjectCode` 

83 One or more ObjectCode objects to be linked. 

84 options : :class:`LinkerOptions`, optional 

85 Options for the linker. If not provided, default options will be used. 

86 """ 

87  

88 def __init__(self, *object_codes: ObjectCode, options: LinkerOptions | None = None): 

89 Linker_init(self, object_codes, options) 2m b p } Z e a ebW y 3 V z K L A M B N t u n O P Q R S T C v D E w F U 5 G 1 H o x X Y 0 I J 2 q r s f c g h i j k d l

90  

91 @property 

92 def is_closed(self) -> bool: 

93 """Whether this linker has been closed.""" 

94 if self._use_nvjitlink: 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJqrsfcghijkdl

95 return self._nvjitlink_handle.get() == NULL 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJqrsfcghijkdl

96 return self._culink_handle.get() == NULL 

97  

98 def link(self, target_type: ObjectCodeFormatType | str) -> ObjectCode: 

99 """Link the provided object codes into a single output of the specified target type. 

100  

101 Parameters 

102 ---------- 

103 target_type : ObjectCodeFormatType | str 

104 The type of the target output. Must be "cubin", "ptx", or 

105 "ltoir". Linked LTOIR output requires 

106 ``link_time_optimization=True`` and nvJitLink 13.3 or newer. 

107  

108 Returns 

109 ------- 

110 :class:`~cuda.core.ObjectCode` 

111 The linked object code of the specified target type. 

112  

113 .. note:: 

114  

115 Ensure that input object codes were compiled with appropriate 

116 flags for linking (e.g., relocatable device code enabled). 

117  

118 A CUBIN produced with ``incremental=True`` can be passed directly 

119 to another :class:`Linker`, but it can still contain unresolved 

120 device references and should be finalized before execution. 

121  

122 ``"ltoir"`` output contains only the LTOIR carried by the inputs. 

123 Direct PTX and CUBIN inputs are rejected because they carry no 

124 LTOIR. FATBIN, host object, and library inputs are accepted but 

125 may carry no LTOIR, in which case they contribute nothing to the 

126 output. 

127 """ 

128 Linker_check_open(self) 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJqrsfcghijkdl

129 return Linker_link(self, str(target_type)) 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJqrsfcghijkdl

130  

131 def get_error_log(self) -> str: 

132 """Get the error log generated by the linker. 

133  

134 Returns 

135 ------- 

136 str 

137 The error log. 

138 """ 

139 # After link(), the decoded log is cached here. 

140 if self._error_log is not None: 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

141 return self._error_log 1mx

142 Linker_check_open(self) 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

143 cdef cynvjitlink.nvJitLinkHandle c_h 

144 cdef size_t c_log_size = 0 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

145 cdef char* c_log_ptr 

146 if self._use_nvjitlink: 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

147 c_h = as_cu(self._nvjitlink_handle) 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

148 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetErrorLogSize(c_h, &c_log_size)) 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

149 log = bytearray(c_log_size) 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

150 if c_log_size > 0: 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

151 c_log_ptr = <char*>(<bytearray>log) 1W

152 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetErrorLog(c_h, c_log_ptr)) 1W

153 return log.decode("utf-8", errors="backslashreplace") 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

154 else: 

155 return (<bytearray>self._drv_log_bufs[2]).decode( 

156 "utf-8", errors="backslashreplace").rstrip('\x00') 

157  

158 def get_info_log(self) -> str: 

159 """Get the info log generated by the linker. 

160  

161 Returns 

162 ------- 

163 str 

164 The info log. 

165 """ 

166 # After link(), the decoded log is cached here. 

167 if self._info_log is not None: 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

168 return self._info_log 1myx

169 Linker_check_open(self) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

170 cdef cynvjitlink.nvJitLinkHandle c_h 

171 cdef size_t c_log_size = 0 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

172 cdef char* c_log_ptr 

173 if self._use_nvjitlink: 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

174 c_h = as_cu(self._nvjitlink_handle) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

175 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetInfoLogSize(c_h, &c_log_size)) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

176 log = bytearray(c_log_size) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

177 if c_log_size > 0: 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

178 c_log_ptr = <char*>(<bytearray>log) 1beazABtnocd

179 HANDLE_RETURN_NVJITLINK(c_h, cynvjitlink.nvJitLinkGetInfoLog(c_h, c_log_ptr)) 1beazABtnocd

180 return log.decode("utf-8", errors="backslashreplace") 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

181 else: 

182 return (<bytearray>self._drv_log_bufs[0]).decode( 

183 "utf-8", errors="backslashreplace").rstrip('\x00') 

184  

185 def close(self) -> None: 

186 """Destroy this linker.""" 

187 cdef vector[cydriver.CUjit_option] empty_keys 

188 cdef vector[void*] empty_values 

189 if self._use_nvjitlink: 1m2fcghijkdl

190 self._nvjitlink_handle.reset() 1m2fcghijkdl

191 else: 

192 if self._drv_log_bufs is not None: 

193 if self._info_log is None: 

194 self._info_log = self.get_info_log() 

195 if self._error_log is None: 

196 self._error_log = self.get_error_log() 

197 # Destroy the CUlinkState before releasing storage referenced by it. 

198 self._culink_handle.reset() 

199 self._drv_jit_keys.swap(empty_keys) 

200 self._drv_jit_values.swap(empty_values) 

201 self._drv_log_bufs = None 

202  

203 @property 

204 def handle(self) -> LinkerHandleT: 

205 """Return the underlying handle object. 

206  

207 .. note:: 

208  

209 The type of the returned object depends on the backend. 

210  

211 .. caution:: 

212  

213 This handle is a Python object. To get the memory address of the underlying C 

214 handle, call ``int(Linker.handle)``. 

215 """ 

216 if self._use_nvjitlink: 132

217 return as_py(self._nvjitlink_handle) 132

218 else: 

219 return as_py(self._culink_handle) 

220  

221 @classmethod 

222 def which_backend(cls) -> CompilerBackendType: 

223 """Return which linking backend will be used. 

224  

225 Returns :attr:`~CompilerBackendType.NVJITLINK` when the nvJitLink 

226 library is available and meets the minimum version requirement, 

227 otherwise :attr:`~CompilerBackendType.DRIVER`. 

228  

229 .. note:: 

230  

231 Prefer letting :class:`Linker` decide. Query ``which_backend()`` 

232 only when you need to dispatch based on input format (for 

233 example: choose PTX vs. LTOIR before constructing a 

234 ``Linker``). The returned value names an implementation 

235 detail whose support matrix may shift across CTK releases. 

236 """ 

237 return CompilerBackendType.DRIVER if _decide_nvjitlink_or_driver() else CompilerBackendType.NVJITLINK 2{ ^ ] IbfbgbV z K L A M B N t u n O P Q R S T C v D E w F U 2 q r s f c g h i j k d l

238  

239  

240# ============================================================================= 

241# Supporting classes 

242# ============================================================================= 

243  

244@dataclass 

245class LinkerOptions: 

246 """Customizable options for configuring :class:`Linker`. 

247  

248 Since the linker may choose to use nvJitLink or the driver APIs as the linking backend, 

249 not all options are applicable. When the system's installed nvJitLink is too old (<12.3), 

250 or not installed, the driver APIs (cuLink) will be used instead. 

251  

252 Attributes 

253 ---------- 

254 name : str, optional 

255 Name of the linker. If the linking succeeds, the name is passed down to the generated :class:`ObjectCode`. 

256 arch : str, optional 

257 Pass the SM architecture value, such as ``sm_<CC>`` (for generating CUBIN) or 

258 ``compute_<CC>`` (for generating PTX). If not provided, the current device's architecture 

259 will be used. 

260 max_register_count : int, optional 

261 Maximum register count. 

262 time : bool, optional 

263 Print timing information to the info log. 

264 Default: False. 

265 verbose : bool, optional 

266 Print verbose messages to the info log. 

267 Default: False. 

268 link_time_optimization : bool, optional 

269 Perform link time optimization. 

270 Default: False. 

271 incremental : bool, optional 

272 Perform an incremental link. The result can be passed 

273 directly to a later :class:`Linker`. Requires nvJitLink 13.2 or newer 

274 and is not supported by the driver linker backend. 

275 Default: False. 

276 ptx : bool, optional 

277 Emit PTX after linking instead of CUBIN; only supported with ``link_time_optimization=True``. 

278 Default: False. 

279 optimization_level : int, optional 

280 Set optimization level. Only 0 and 3 are accepted. 

281 debug : bool, optional 

282 Generate debug information. 

283 Default: False. 

284 lineinfo : bool, optional 

285 Generate line information. 

286 Default: False. 

287 ftz : bool, optional 

288 Flush denormal values to zero. 

289 Default: False. 

290 prec_div : bool, optional 

291 Use precise division. 

292 Default: True. 

293 prec_sqrt : bool, optional 

294 Use precise square root. 

295 Default: True. 

296 fma : bool, optional 

297 Use fast multiply-add. 

298 Default: True. 

299 kernels_used : [str | tuple[str] | list[str]], optional 

300 Pass a kernel or sequence of kernels that are used; any not in the list can be removed. 

301 variables_used : [str | tuple[str] | list[str]], optional 

302 Pass a variable or sequence of variables that are used; any not in the list can be removed. 

303 optimize_unused_variables : bool, optional 

304 Assume that if a variable is not referenced in device code, it can be removed. 

305 Default: False. 

306 ptxas_options : [str | tuple[str] | list[str]], optional 

307 Pass options to PTXAS. 

308 split_compile : int, optional 

309 Split compilation maximum thread count. Use 0 to use all available processors. Value of 1 disables split 

310 compilation (default). 

311 Default: 1. 

312 split_compile_extended : int, optional 

313 A more aggressive form of split compilation available in LTO mode only. Accepts a maximum thread count value. 

314 Use 0 to use all available processors. Value of 1 disables extended split compilation (default). Note: This 

315 option can potentially impact performance of the compiled binary. 

316 Default: 1. 

317 no_cache : bool, optional 

318 Do not cache the intermediate steps of nvJitLink. 

319 Default: False. 

320 numba_debug : bool, optional 

321 Non-functional. ``numba_debug`` is an NVVM/NVRTC *compiler* option; 

322 neither nvJitLink nor the driver's cuLink API recognizes it, so no 

323 linking backend can honor it and the value is ignored. 

324 Default: None. 

325  

326 .. deprecated:: 1.2.0 

327 Setting this option emits a :class:`DeprecationWarning`. It has never 

328 had an effect on any linking backend and will be removed in 

329 ``cuda.core`` 2.0.0. Use 

330 :attr:`ProgramOptions.numba_debug` on an NVVM or NVRTC compilation 

331 path instead. 

332 """ 

333  

334 name: str | None = "<default linker>" 

335 arch: str | None = None 

336 max_register_count: int | None = None 

337 time: bool | None = None 

338 verbose: bool | None = None 

339 link_time_optimization: bool | None = None 

340 ptx: bool | None = None 

341 optimization_level: int | None = None 

342 debug: bool | None = None 

343 lineinfo: bool | None = None 

344 ftz: bool | None = None 

345 prec_div: bool | None = None 

346 prec_sqrt: bool | None = None 

347 fma: bool | None = None 

348 kernels_used: str | tuple[str] | list[str] | None = None 

349 variables_used: str | tuple[str] | list[str] | None = None 

350 optimize_unused_variables: bool | None = None 

351 ptxas_options: str | tuple[str] | list[str] | None = None 

352 split_compile: int | None = None 

353 split_compile_extended: int | None = None 

354 no_cache: bool | None = None 

355 numba_debug: bool | None = None 

356 incremental: bool | None = None 

357  

358 def __post_init__(self) -> None: 

359 _lazy_init() 2= abm b p } Z e a W y 3 5 G 1 H o x bbcb7 * + ( : X Y 0 6 ; - . 4 8 9 ! # $ % ' @ [ ? / , ) I J 2 q r s f c g h i j k d l

360 self._name = self.name.encode() 2= abm b p } Z e a W y 3 5 G 1 H o x bbcb7 * + ( : X Y 0 6 ; - . 4 8 9 ! # $ % ' @ [ ? / , ) I J 2 q r s f c g h i j k d l

361 # No linking backend reads ``numba_debug``, so warn where the value is 

362 # supplied rather than in the option builders -- the user learns once, 

363 # at the call site that set it, instead of once per link. The gate is 

364 # ``is not None`` (unlike the ignore-warning on the PTX compile path): 

365 # it is the *field* that is going away, so any explicit value earns the 

366 # notice, including ``False``. 

367 if self.numba_debug is not None: 2= abm b p } Z e a W y 3 5 G 1 H o x bbcb7 * + ( : X Y 0 6 ; - . 4 8 9 ! # $ % ' @ [ ? / , ) I J 2 q r s f c g h i j k d l

368 warn( 16-.

369 "numba_debug is not supported by any linking backend and is ignored. " 

370 "LinkerOptions.numba_debug is deprecated and will be removed in " 

371 "cuda.core 2.0.0; use ProgramOptions.numba_debug on an NVVM or NVRTC " 

372 "compilation path instead.", 

373 DeprecationWarning, 16-.

374 stacklevel=3, 

375 ) 

376  

377 def _prepare_nvjitlink_options(self, as_bytes: bool = False) -> list[bytes] | list[str]: 

378 options = [] 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

379  

380 if self.arch is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

381 options.append(f"-arch={self.arch}") 1mbpZeaWy3zKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

382 else: 

383 options.append("-arch=sm_" + "".join(f"{i}" for i in Device().compute_capability)) 1V

384 if self.max_register_count is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

385 options.append(f"-maxrregcount={self.max_register_count}") 1K7f

386 if self.time is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

387 options.append("-time") 1Bd

388 if self.verbose: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

389 options.append("-verbose") 1z

390 if self.link_time_optimization: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

391 options.append("-lto") 1beaoXY

392 if self.incremental: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

393 options.append("-r") 1pZea(XY

394 if self.ptx: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

395 options.append("-ptx") 15o

396 if self.optimization_level is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

397 options.append(f"-O{self.optimization_level}") 1L

398 if self.debug: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

399 options.append("-g") 1A7:;-.c

400 if self.lineinfo: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

401 options.append("-lineinfo") 1M:g

402 if self.ftz is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

403 options.append(f"-ftz={'true' if self.ftz else 'false'}") 1Q7h

404 if self.prec_div is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

405 options.append(f"-prec-div={'true' if self.prec_div else 'false'}") 1Ri

406 if self.prec_sqrt is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

407 options.append(f"-prec-sqrt={'true' if self.prec_sqrt else 'false'}") 1Sj

408 if self.fma is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

409 options.append(f"-fma={'true' if self.fma else 'false'}") 1Tk

410 if self.kernels_used is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

411 if isinstance(self.kernels_used, str): 1CvD

412 options.append(f"-kernels-used={self.kernels_used}") 1C

413 elif isinstance(self.kernels_used, list): 1vD

414 for kernel in self.kernels_used: 1v

415 options.append(f"-kernels-used={kernel}") 1v

416 if self.variables_used is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

417 if isinstance(self.variables_used, str): 1EwF

418 options.append(f"-variables-used={self.variables_used}") 1E

419 elif isinstance(self.variables_used, list): 1wF

420 for variable in self.variables_used: 1w

421 options.append(f"-variables-used={variable}") 1w

422 if self.optimize_unused_variables is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

423 options.append("-optimize-unused-variables") 1N

424 if self.ptxas_options is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

425 if isinstance(self.ptxas_options, str): 1tun

426 options.append(f"-Xptxas={self.ptxas_options}") 1t

427 elif is_sequence(self.ptxas_options): 1un

428 for opt in self.ptxas_options: 1un

429 options.append(f"-Xptxas={opt}") 1un

430 if self.split_compile is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

431 options.append(f"-split-compile={self.split_compile}") 1Ol

432 if self.split_compile_extended is not None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

433 options.append(f"-split-compile-extended={self.split_compile_extended}") 1P

434 if self.no_cache is True: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

435 options.append("-no-cache") 1U

436  

437 if as_bytes: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl

438 return [o.encode() for o in options] 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(XY0;-.IJ2qrsfcghijkdl

439 else: 

440 return options 1:

441  

442 def _prepare_driver_options(self) -> tuple[list[object], list[object]]: 

443 formatted_options = [] 16489!#$%'@[?/,)

444 option_keys = [] 16489!#$%'@[?/,)

445  

446 # allocate a fixed-sized buffer for each info/error log 

447 size = 4194304 16489!#$%'@[?/,)

448 formatted_options.extend((bytearray(size), size, bytearray(size), size)) 16489!#$%'@[?/,)

449 option_keys.extend( 16489!#$%'@[?/,)

450 ( 

451 _driver.CUjit_option.CU_JIT_INFO_LOG_BUFFER, 16489!#$%'@[?/,)

452 _driver.CUjit_option.CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES, 16489!#$%'@[?/,)

453 _driver.CUjit_option.CU_JIT_ERROR_LOG_BUFFER, 16489!#$%'@[?/,)

454 _driver.CUjit_option.CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES, 16489!#$%'@[?/,)

455 ) 

456 ) 

457  

458 if self.arch is not None: 16489!#$%'@[?/,)

459 arch = self.arch.split("_")[-1].upper() 164

460 formatted_options.append(getattr(_driver.CUjit_target, f"CU_TARGET_COMPUTE_{arch}")) 164

461 option_keys.append(_driver.CUjit_option.CU_JIT_TARGET) 164

462 if self.max_register_count is not None: 16489!#$%'@[?/,)

463 formatted_options.append(self.max_register_count) 14

464 option_keys.append(_driver.CUjit_option.CU_JIT_MAX_REGISTERS) 14

465 if self.time is not None: 16489!#$%'@[?/,)

466 raise ValueError("time option is not supported by the driver API") 1[

467 if self.verbose: 16489!#$%'@?/,)

468 formatted_options.append(1) 14

469 option_keys.append(_driver.CUjit_option.CU_JIT_LOG_VERBOSE) 14

470 if self.link_time_optimization: 16489!#$%'@?/,)

471 formatted_options.append(1) 14

472 option_keys.append(_driver.CUjit_option.CU_JIT_LTO) 14

473 if self.incremental: 16489!#$%'@?/,)

474 raise ValueError("incremental option is not supported by the driver API") 1@

475 if self.ptx: 16489!#$%'?/,)

476 raise ValueError("ptx option is not supported by the driver API") 1?

477 if self.optimization_level is not None: 16489!#$%'/,)

478 formatted_options.append(self.optimization_level) 14

479 option_keys.append(_driver.CUjit_option.CU_JIT_OPTIMIZATION_LEVEL) 14

480 if self.debug: 16489!#$%'/,)

481 formatted_options.append(1) 14

482 option_keys.append(_driver.CUjit_option.CU_JIT_GENERATE_DEBUG_INFO) 14

483 if self.lineinfo: 16489!#$%'/,)

484 formatted_options.append(1) 14

485 option_keys.append(_driver.CUjit_option.CU_JIT_GENERATE_LINE_INFO) 14

486 if self.ftz is not None: 16489!#$%'/,)

487 warn("ftz option is deprecated in the driver API", DeprecationWarning, stacklevel=3) 18

488 if self.prec_div is not None: 16489!#$%'/,)

489 warn("prec_div option is deprecated in the driver API", DeprecationWarning, stacklevel=3) 19

490 if self.prec_sqrt is not None: 16489!#$%'/,)

491 warn("prec_sqrt option is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1!

492 if self.fma is not None: 16489!#$%'/,)

493 warn("fma options is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1#

494 if self.kernels_used is not None: 16489!#$%'/,)

495 warn("kernels_used is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1$

496 if self.variables_used is not None: 16489!#$%'/,)

497 warn("variables_used is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1%

498 if self.optimize_unused_variables is not None: 16489!#$%'/,)

499 warn("optimize_unused_variables is deprecated in the driver API", DeprecationWarning, stacklevel=3) 1'

500 if self.ptxas_options is not None: 16489!#$%'/,)

501 raise ValueError("ptxas_options option is not supported by the driver API") 1/

502 if self.split_compile is not None: 16489!#$%',)

503 raise ValueError("split_compile option is not supported by the driver API") 1,

504 if self.split_compile_extended is not None: 16489!#$%')

505 raise ValueError("split_compile_extended option is not supported by the driver API") 1)

506 if self.no_cache is True: 16489!#$%'

507 formatted_options.append(_driver.CUjit_cacheMode.CU_JIT_CACHE_OPTION_NONE) 14

508 option_keys.append(_driver.CUjit_option.CU_JIT_CACHE_MODE) 14

509  

510 return formatted_options, option_keys 16489!#$%'

511  

512 def as_bytes(self, backend: str = "nvjitlink") -> list[bytes]: 

513 """Convert linker options to bytes format for the nvjitlink backend. 

514  

515 Parameters 

516 ---------- 

517 backend : str, optional 

518 The linker backend. Only "nvjitlink" is supported. Default is "nvjitlink". 

519  

520 Returns 

521 ------- 

522 list[bytes] 

523 List of option strings encoded as bytes. 

524  

525 Raises 

526 ------ 

527 ValueError 

528 If an unsupported backend is specified. 

529 RuntimeError 

530 If nvJitLink backend is not available. 

531 """ 

532 backend = backend.lower() 2abbbcb7 * + (

533 if backend != "nvjitlink": 2abbbcb7 * + (

534 raise ValueError(f"as_bytes() only supports 'nvjitlink' backend, got '{backend}'") 2bbcb

535 if not _use_nvjitlink_backend: 2ab7 * + (

536 raise RuntimeError("nvJitLink backend is not available") 2ab

537 return self._prepare_nvjitlink_options(as_bytes=True) 17*+(

538  

539  

540# ============================================================================= 

541# Private implementation: cdef inline helpers 

542# ============================================================================= 

543  

544cdef inline int Linker_init(Linker self, tuple object_codes, object options) except -1: 

545 """Initialize a Linker instance.""" 

546 if len(object_codes) == 0: 2m b p } Z e a ebW y 3 V z K L A M B N t u n O P Q R S T C v D E w F U 5 G 1 H o x X Y 0 I J 2 q r s f c g h i j k d l

547 raise ValueError("At least one ObjectCode object must be provided") 2eb

548  

549 cdef cynvjitlink.nvJitLinkHandle c_raw_nvjitlink 

550 cdef cydriver.CUlinkState c_raw_culink 

551 cdef Py_ssize_t c_num_opts, i 

552 cdef vector[const_char_ptr] c_str_opts 

553 cdef cydriver.CUjit_option* c_drv_jit_keys_ptr 

554 cdef void** c_drv_jit_values_ptr 

555  

556 self._options = options = check_or_create_options(LinkerOptions, options, "Linker options") 1mbp}ZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

557 self._has_ptx_or_cubin_input = False 1mbp}ZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

558 if options.incremental and options.ptx: 1mbp}ZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

559 raise ValueError("incremental and ptx output options cannot be used together") 1}

560  

561 if _use_nvjitlink_backend: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

562 if options.incremental: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

563 _require_nvjitlink_version((13, 2), "incremental linking") 1pZeaXY

564 self._use_nvjitlink = True 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

565 options_bytes = options._prepare_nvjitlink_options(as_bytes=True) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

566 c_num_opts = len(options_bytes) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

567 c_str_opts.resize(c_num_opts) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

568 for i in range(c_num_opts): 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

569 c_str_opts[i] = <const char*>(<bytes>options_bytes[i]) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

570 with nogil: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

571 HANDLE_RETURN_NVJITLINK(NULL, cynvjitlink.nvJitLinkCreate( 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1HoxXY0IJ2qrsfcghijkdl

572 &c_raw_nvjitlink, <uint32_t>c_num_opts, c_str_opts.data())) 

573 self._nvjitlink_handle = create_nvjitlink_handle(c_raw_nvjitlink) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

574 else: 

575 self._use_nvjitlink = False 

576 formatted_options, option_keys = options._prepare_driver_options() 

577 # Keep the formatted_options list alive: it contains bytearrays that 

578 # the driver writes into via raw pointers during linking operations. 

579 self._drv_log_bufs = formatted_options 

580 c_num_opts = len(option_keys) 

581 self._drv_jit_keys.resize(c_num_opts) 

582 self._drv_jit_values.resize(c_num_opts) 

583 for i in range(c_num_opts): 

584 self._drv_jit_keys[i] = <cydriver.CUjit_option><int>option_keys[i] 

585 val = formatted_options[i] 

586 if isinstance(val, bytearray): 

587 self._drv_jit_values[i] = <void*>PyByteArray_AS_STRING(val) 

588 else: 

589 self._drv_jit_values[i] = <void*><intptr_t>int(val) 

590 c_drv_jit_keys_ptr = self._drv_jit_keys.data() 

591 c_drv_jit_values_ptr = self._drv_jit_values.data() 

592 try: 

593 with nogil: 

594 HANDLE_RETURN(cydriver.cuLinkCreate( 

595 <unsigned int>c_num_opts, 

596 c_drv_jit_keys_ptr, 

597 c_drv_jit_values_ptr, 

598 &c_raw_culink)) 

599 except CUDAError as e: 

600 Linker_annotate_error_log(self, e) 

601 raise 

602 self._culink_handle = create_culink_handle(c_raw_culink) 

603  

604 for code in object_codes: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

605 assert_type(code, ObjectCode) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

606 Linker_add_code_object(self, code) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

607 return 0 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

608  

609  

610cdef inline void Linker_add_code_object(Linker self, object object_code) except *: 

611 """Add a single ObjectCode to the linker.""" 

612 data = object_code.code 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

613 cdef cynvjitlink.nvJitLinkHandle c_nvjitlink_h 

614 cdef cydriver.CUlinkState c_culink_state 

615 cdef cynvjitlink.nvJitLinkInputType c_nv_input_type 

616 cdef cydriver.CUjitInputType c_drv_input_type 

617 cdef const char* c_data_ptr 

618 cdef size_t c_data_size 

619 cdef const char* c_file_ptr 

620  

621 name_bytes = f"{object_code.name}".encode() 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

622 cdef const char* c_name_ptr = <const char*>name_bytes 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

623  

624 input_types = _nvjitlink_input_types if self._use_nvjitlink else _driver_input_types 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

625 py_input_type = input_types.get(object_code.code_type) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

626 if py_input_type is None: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

627 raise ValueError(f"Unknown code_type associated with ObjectCode: {object_code.code_type}") 

628  

629 if self._use_nvjitlink: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

630 c_nvjitlink_h = as_cu(self._nvjitlink_handle) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

631 c_nv_input_type = <cynvjitlink.nvJitLinkInputType><int>py_input_type 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

632 if isinstance(data, bytes): 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

633 c_data_ptr = <const char*>(<bytes>data) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

634 c_data_size = len(data) 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

635 with nogil: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

636 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, cynvjitlink.nvJitLinkAddData( 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

637 c_nvjitlink_h, c_nv_input_type, <const void*>c_data_ptr, c_data_size, c_name_ptr)) 

638 elif isinstance(data, str): 

639 file_bytes = data.encode() 

640 c_file_ptr = <const char*>file_bytes 

641 with nogil: 

642 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, cynvjitlink.nvJitLinkAddFile( 

643 c_nvjitlink_h, c_nv_input_type, c_file_ptr)) 

644 else: 

645 raise TypeError(f"Expected bytes or str, but got {type(data).__name__}") 

646 else: 

647 c_culink_state = as_cu(self._culink_handle) 

648 c_drv_input_type = <cydriver.CUjitInputType><int>py_input_type 

649 try: 

650 if isinstance(data, bytes): 

651 c_data_ptr = <const char*>(<bytes>data) 

652 c_data_size = len(data) 

653 with nogil: 

654 HANDLE_RETURN(cydriver.cuLinkAddData( 

655 c_culink_state, c_drv_input_type, <void*>c_data_ptr, c_data_size, c_name_ptr, 

656 0, NULL, NULL)) 

657 elif isinstance(data, str): 

658 file_bytes = data.encode() 

659 c_file_ptr = <const char*>file_bytes 

660 with nogil: 

661 HANDLE_RETURN(cydriver.cuLinkAddFile( 

662 c_culink_state, c_drv_input_type, c_file_ptr, 0, NULL, NULL)) 

663 else: 

664 raise TypeError(f"Expected bytes or str, but got {type(data).__name__}") 

665 except CUDAError as e: 

666 Linker_annotate_error_log(self, e) 

667 raise 

668  

669 if object_code.code_type in ("ptx", "cubin"): 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl

670 self._has_ptx_or_cubin_input = True 1mpZeWy3VzKLAMBNtunOPQRSTCvDEwFUG1HxXY0IJ2qrsfcghijkdl

671  

672  

673cdef inline object Linker_link(Linker self, str target_type): 

674 """Complete linking and return the result as ObjectCode.""" 

675 if target_type not in ("cubin", "ptx", "ltoir"): 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJqrsfcghijkdl

676 raise ValueError(f"Unsupported target type: {target_type}") 11

677 if self._options.incremental and target_type == "ptx": 1mbpZeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxXY0IJqrsfcghijkdl

678 raise ValueError("PTX output is not supported for incremental linking") 1Z

679 if target_type == "ltoir": 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxXY0IJqrsfcghijkdl

680 if not self._use_nvjitlink: 1baXY0

681 raise ValueError("LTOIR output is not supported by the driver API") 

682 if not self._options.link_time_optimization: 1baXY0

683 raise ValueError("LTOIR output requires link_time_optimization=True") 10

684 if self._has_ptx_or_cubin_input: 1baXY

685 raise ValueError( 1XY

686 'LTOIR output is not supported with "ptx" or "cubin" inputs; ' 

687 "they carry no LTOIR and would be omitted from the output" 

688 ) 

689 _require_nvjitlink_version((13, 3), "LTOIR output") 1ba

690  

691 cdef cynvjitlink.nvJitLinkHandle c_nvjitlink_h 

692 cdef cydriver.CUlinkState c_culink_state 

693 cdef size_t c_output_size = 0 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

694 cdef char* c_code_ptr 

695 cdef void* c_cubin_out = NULL 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

696  

697 if self._use_nvjitlink: 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

698 c_nvjitlink_h = as_cu(self._nvjitlink_handle) 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

699 with nogil: 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

700 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, cynvjitlink.nvJitLinkComplete(c_nvjitlink_h)) 1mbpeaWyVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

701 if target_type == "cubin": 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

702 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHxIJqrsfcghijkdl

703 cynvjitlink.nvJitLinkGetLinkedCubinSize(c_nvjitlink_h, &c_output_size)) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHxIJqrsfcghijkdl

704 code = bytearray(c_output_size) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHxIJqrsfcghijkdl

705 c_code_ptr = <char*>(<bytearray>code) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHxIJqrsfcghijkdl

706 with nogil: 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHxIJqrsfcghijkdl

707 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHxIJqrsfcghijkdl

708 cynvjitlink.nvJitLinkGetLinkedCubin(c_nvjitlink_h, c_code_ptr)) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHxIJqrsfcghijkdl

709 elif target_type == "ptx": 1bao

710 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1o

711 cynvjitlink.nvJitLinkGetLinkedPtxSize(c_nvjitlink_h, &c_output_size)) 1o

712 code = bytearray(c_output_size) 1o

713 c_code_ptr = <char*>(<bytearray>code) 1o

714 with nogil: 1o

715 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1o

716 cynvjitlink.nvJitLinkGetLinkedPtx(c_nvjitlink_h, c_code_ptr)) 1o

717 else: 

718 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1ba

719 cynvjitlink.nvJitLinkGetLinkedLTOIRSize(c_nvjitlink_h, &c_output_size)) 1ba

720 code = bytearray(c_output_size) 1ba

721 c_code_ptr = <char*>(<bytearray>code) 1ba

722 with nogil: 1ba

723 HANDLE_RETURN_NVJITLINK(c_nvjitlink_h, 1ba

724 cynvjitlink.nvJitLinkGetLinkedLTOIR(c_nvjitlink_h, c_code_ptr)) 1ba

725 else: 

726 c_culink_state = as_cu(self._culink_handle) 

727 try: 

728 with nogil: 

729 HANDLE_RETURN(cydriver.cuLinkComplete(c_culink_state, &c_cubin_out, &c_output_size)) 

730 except CUDAError as e: 

731 Linker_annotate_error_log(self, e) 

732 raise 

733 code = (<char*>c_cubin_out)[:c_output_size] 

734  

735 # Linking is complete; cache the decoded logs. cuLinkDestroy may still 

736 # dereference the raw log-buffer pointers, so retain them until close(). 

737 self._info_log = self.get_info_log() 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

738 self._error_log = self.get_error_log() 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

739  

740 return ObjectCode._init(bytes(code), target_type, name=self._options.name) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl

741  

742  

743cdef inline void Linker_annotate_error_log(Linker self, object e): 

744 """Annotate a CUDAError with the driver linker error log.""" 

745 error_log = self.get_error_log() 

746 if error_log: 

747 e.args = (e.args[0] + f"\nLinker error log: {error_log}", *e.args[1:]) 

748  

749  

750# ============================================================================= 

751# Private implementation: module-level state and initialization 

752# ============================================================================= 

753  

754# TODO: revisit this treatment for py313t builds 

755_driver = None # populated if nvJitLink cannot be used 

756_nvjitlink_version = None 

757_inited = False 

758_use_nvjitlink_backend = None # set by _decide_nvjitlink_or_driver() 

759  

760# Input type mappings populated by _lazy_init() with C-level enum ints. 

761_nvjitlink_input_types = None 

762_driver_input_types = None 

763  

764  

765def _require_nvjitlink_version(minimum_version: tuple[int, int], feature: str) -> None: 

766 """Check that the cached nvJitLink runtime meets a feature's requirement.""" 

767 if _nvjitlink_version < minimum_version: 2b p Z e a X Y Jbdb

768 required = ".".join(str(component) for component in minimum_version) 2db

769 detected = ".".join(str(component) for component in _nvjitlink_version) 2db

770 raise RuntimeError(f"{feature} requires nvJitLink {required} or newer; found {detected}") 2db

771  

772  

773def _nvjitlink_has_version_symbol(nvjitlink) -> bool: 

774 # This condition is equivalent to testing for version >= 12.3 

775 return bool(nvjitlink._inspect_function_pointer("__nvJitLinkVersion")) 

776  

777  

778# Note: this function is reused in the tests 

779def _decide_nvjitlink_or_driver() -> bool: 

780 """Return True if falling back to the cuLink* driver APIs.""" 

781 global _driver, _nvjitlink_version, _use_nvjitlink_backend 

782 if _use_nvjitlink_backend is not None: 2= { ^ ] fbgbV z K L A M B N t u n O P Q R S T C v D E w F U _ | ` ~ 2 q r s f c g h i j k d l hbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHb

783 return not _use_nvjitlink_backend 2= { fbgbV z K L A M B N t u n O P Q R S T C v D E w F U 2 q r s f c g h i j k d l hbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHb

784  

785 _nvjitlink_version = None 1={^]_|`~

786  

787 warn_txt_common = ( 

788 "the driver APIs will be used instead, which do not support" 1={^]_|`~

789 " minor version compatibility or linking LTO IRs." 

790 " For best results, consider upgrading to a recent version of" 

791 ) 

792  

793 # Every cuda-bindings that cuda.core accepts provides cuda.bindings.nvjitlink. 

794 # Only the nvJitLink library itself can be missing or too old. 

795 from cuda.bindings._internal import nvjitlink 1={^]_|`~

796  

797 try: 1={^]_|`~

798 has_version_symbol = _nvjitlink_has_version_symbol(nvjitlink) 1={^]_|`~

799 except DynamicLibNotFoundError: 1^|

800 warn_txt = ( 

801 f"cuda.bindings.nvjitlink is not available, therefore {warn_txt_common} cuda-bindings." 1^|

802 ) 

803 else: 

804 if has_version_symbol: 1={]_`~

805 _nvjitlink_version = _nvjitlink_bindings.version() 1={~

806 _use_nvjitlink_backend = True 1={~

807 return False # Use nvjitlink 1={~

808 warn_txt = ( 

809 f"{'nvJitLink*.dll' if sys.platform == 'win32' else 'libnvJitLink.so*'} is too old (<12.3)." 1]_`

810 f" Therefore cuda.bindings.nvjitlink is not usable and {warn_txt_common} nvJitLink." 1]_`

811 ) 

812  

813 warn(warn_txt, stacklevel=2, category=RuntimeWarning) 1^]_|`

814 _driver = driver 1^]_|`

815 _use_nvjitlink_backend = False 1^]_|`

816 return True 1^]_|`

817  

818  

819def _lazy_init() -> None: 

820 global _inited, _nvjitlink_input_types, _driver_input_types 

821 if _inited: 2= abm b p } Z e a W y 3 5 G 1 H o x bbcb7 * + ( : X Y 0 6 ; - . 4 8 9 ! # $ % ' @ [ ? / , ) I J 2 q r s f c g h i j k d l

822 return 2= abm b p } Z e a W y 3 5 G 1 H o x bbcb7 * + ( : X Y 0 6 ; - . 4 8 9 ! # $ % ' @ [ ? / , ) I J 2 q r s f c g h i j k d l

823  

824 _decide_nvjitlink_or_driver() 

825 if _use_nvjitlink_backend: 

826 _nvjitlink_input_types = { 

827 "ptx": <int>cynvjitlink.NVJITLINK_INPUT_PTX, 

828 "cubin": <int>cynvjitlink.NVJITLINK_INPUT_CUBIN, 

829 "fatbin": <int>cynvjitlink.NVJITLINK_INPUT_FATBIN, 

830 "ltoir": <int>cynvjitlink.NVJITLINK_INPUT_LTOIR, 

831 "object": <int>cynvjitlink.NVJITLINK_INPUT_OBJECT, 

832 "library": <int>cynvjitlink.NVJITLINK_INPUT_LIBRARY, 

833 } 

834 else: 

835 _driver_input_types = { 

836 "ptx": <int>cydriver.CU_JIT_INPUT_PTX, 

837 "cubin": <int>cydriver.CU_JIT_INPUT_CUBIN, 

838 "fatbin": <int>cydriver.CU_JIT_INPUT_FATBINARY, 

839 "object": <int>cydriver.CU_JIT_INPUT_OBJECT, 

840 "library": <int>cydriver.CU_JIT_INPUT_LIBRARY, 

841 } 

842 _inited = True