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
« 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.
6This module provides :class:`Linker` for linking one or more
7:class:`~cuda.core.ObjectCode` objects, with :class:`LinkerOptions` for
8configuration.
9"""
11from __future__ import annotations
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
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
27import sys
28from dataclasses import dataclass
29from typing import TYPE_CHECKING, Union
30from warnings import warn
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
45if TYPE_CHECKING:
46 import cuda.bindings.driver # no-cython-lint
47 import cuda.bindings.nvjitlink # no-cython-lint
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"
55ctypedef const char* const_char_ptr
57__all__ = ["Linker", "LinkerOptions"]
59LinkerHandleT = Union["cuda.bindings.nvjitlink.nvJitLinkHandle", "cuda.bindings.driver.CUlinkState"]
62# =============================================================================
63# Principal class
64# =============================================================================
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
73cdef class Linker:
74 """Represent a linking machinery to link one or more object codes into
75 :class:`~cuda.core.ObjectCode`.
77 This object provides a unified interface to multiple underlying
78 linker libraries (such as nvJitLink or cuLink* from the CUDA driver).
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 """
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
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
98 def link(self, target_type: ObjectCodeFormatType | str) -> ObjectCode:
99 """Link the provided object codes into a single output of the specified target type.
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.
108 Returns
109 -------
110 :class:`~cuda.core.ObjectCode`
111 The linked object code of the specified target type.
113 .. note::
115 Ensure that input object codes were compiled with appropriate
116 flags for linking (e.g., relocatable device code enabled).
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.
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
131 def get_error_log(self) -> str:
132 """Get the error log generated by the linker.
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')
158 def get_info_log(self) -> str:
159 """Get the info log generated by the linker.
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')
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
203 @property
204 def handle(self) -> LinkerHandleT:
205 """Return the underlying handle object.
207 .. note::
209 The type of the returned object depends on the backend.
211 .. caution::
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)
221 @classmethod
222 def which_backend(cls) -> CompilerBackendType:
223 """Return which linking backend will be used.
225 Returns :attr:`~CompilerBackendType.NVJITLINK` when the nvJitLink
226 library is available and meets the minimum version requirement,
227 otherwise :attr:`~CompilerBackendType.DRIVER`.
229 .. note::
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
240# =============================================================================
241# Supporting classes
242# =============================================================================
244@dataclass
245class LinkerOptions:
246 """Customizable options for configuring :class:`Linker`.
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.
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.
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 """
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
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 )
377 def _prepare_nvjitlink_options(self, as_bytes: bool = False) -> list[bytes] | list[str]:
378 options = [] 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl
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
437 if as_bytes: 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(:XY0;-.IJ2qrsfcghijkdl
438 return [o.encode() for o in options] 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFU5G1Hox7*+(XY0;-.IJ2qrsfcghijkdl
439 else:
440 return options 1:
442 def _prepare_driver_options(self) -> tuple[list[object], list[object]]:
443 formatted_options = [] 16489!#$%'@[?/,)
444 option_keys = [] 16489!#$%'@[?/,)
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 )
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
510 return formatted_options, option_keys 16489!#$%'
512 def as_bytes(self, backend: str = "nvjitlink") -> list[bytes]:
513 """Convert linker options to bytes format for the nvjitlink backend.
515 Parameters
516 ----------
517 backend : str, optional
518 The linker backend. Only "nvjitlink" is supported. Default is "nvjitlink".
520 Returns
521 -------
522 list[bytes]
523 List of option strings encoded as bytes.
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*+(
540# =============================================================================
541# Private implementation: cdef inline helpers
542# =============================================================================
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
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
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}
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)
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
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
621 name_bytes = f"{object_code.name}".encode() 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl
622 cdef const char* c_name_ptr = <const char*>name_bytes 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl
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}")
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
669 if object_code.code_type in ("ptx", "cubin"): 1mbpZeaWy3VzKLAMBNtunOPQRSTCvDEwFUG1HoxXY0IJ2qrsfcghijkdl
670 self._has_ptx_or_cubin_input = True 1mpZeWy3VzKLAMBNtunOPQRSTCvDEwFUG1HxXY0IJ2qrsfcghijkdl
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
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
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]
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
740 return ObjectCode._init(bytes(code), target_type, name=self._options.name) 1mbpeayVzKLAMBNtunOPQRSTCvDEwFUGHoxIJqrsfcghijkdl
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:])
750# =============================================================================
751# Private implementation: module-level state and initialization
752# =============================================================================
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()
760# Input type mappings populated by _lazy_init() with C-level enum ints.
761_nvjitlink_input_types = None
762_driver_input_types = None
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
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"))
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
785 _nvjitlink_version = None 1={^]_|`~
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 )
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={^]_|`~
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 )
813 warn(warn_txt, stacklevel=2, category=RuntimeWarning) 1^]_|`
814 _driver = driver 1^]_|`
815 _use_nvjitlink_backend = False 1^]_|`
816 return True 1^]_|`
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
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