@@ -10,6 +10,10 @@ This module provides :class:`Program` for compiling source code into
1010from __future__ import annotations
1111
1212from dataclasses import dataclass
13+ import os
14+ import re
15+ import sys
16+ import tempfile
1317import threading
1418from typing import TYPE_CHECKING
1519from warnings import warn
@@ -87,6 +91,49 @@ cdef class Program:
8791 # Reset handles - the C++ shared_ptr destructor handles cleanup
8892 self._h_nvrtc.reset()
8993 self._h_nvvm.reset()
94+ self._cleanup_debug_source()
95+
96+ def __dealloc__(self ):
97+ self ._cleanup_debug_source()
98+
99+ def _cleanup_debug_source (self ):
100+ path = self ._nvrtc_name.decode()
101+ self ._unlink_debug_source(path)
102+
103+ def _unlink_debug_source (self , path: str ) -> None:
104+ try:
105+ os.unlink(path )
106+ except OSError:
107+ pass
108+
109+ def _try_materialize_nvrtc_debug_source(self , code: str ) -> str | None:
110+ """Write *code* to a ``{caller}_{kernel}_XXXXXXXX.cu`` temp file for cuda-gdb.
111+
112+ ``caller`` is the Python file stem (no ``.py``). ``kernel`` is the first
113+ ``__global__`` function name , or ``kernel`` if none is found.
114+
115+ Returns None if the filesystem is not writable , so the caller can fall back
116+ to the label-only behavior instead of failing the compile.
117+ """
118+ frame = sys._getframe()
119+ while frame and frame.f_globals.get("__name__", "").startswith("cuda.core"):
120+ frame = frame.f_back
121+ caller = " program"
122+ if frame:
123+ caller = os.path.splitext(os.path.basename(frame.f_code.co_filename))[0 ]
124+ match = re.search(r " __global__. *? ( \w + ) \s * \( " , code, re.DOTALL)
125+ prefix = re.sub(r " \W " , " _" , f" {caller}_{match.group(1) if match else 'kernel'}_" )
126+ try :
127+ fd, path = tempfile.mkstemp(prefix = prefix, suffix = " .cu" )
128+ except OSError :
129+ return None
130+ try :
131+ with os.fdopen(fd, " w" , encoding = " utf-8" ) as f:
132+ f.write(code)
133+ return path
134+ except OSError :
135+ self ._unlink_debug_source(path)
136+ return None
90137
91138 def compile (
92139 self ,
@@ -223,7 +270,7 @@ cdef class Program:
223270 stacklevel = 2 ,
224271 category = RuntimeWarning ,
225272 )
226- return ObjectCode._init(hit_bytes, target_type, name = self ._options.name )
273+ return ObjectCode._init(hit_bytes, target_type, name = self ._nvrtc_name.decode() )
227274 compiled = _program_compile_uncached(self , target_type, name_expressions, logs)
228275 cache[key] = compiled
229276 return compiled
@@ -788,16 +835,22 @@ cdef inline int Program_init(Program self, object code, str code_type, object op
788835 self ._libdevice_added = False
789836
790837 self ._pch_status = None
838+ self ._nvrtc_name = options._name
791839
792840 if code_type == " c++" :
793841 assert_type(code, str )
794842 if options.extra_sources is not None :
795843 raise ValueError (" extra_sources is not supported by the NVRTC backend (C++ code_type)" )
796844
845+ if (options.debug or options.lineinfo) and options.name == " default_program" :
846+ debug_path = self ._try_materialize_nvrtc_debug_source(code)
847+ if debug_path is not None :
848+ self ._nvrtc_name = debug_path.encode()
849+
797850 # TODO: support pre-loaded headers & include names
798851 code_bytes = code.encode()
799852 code_ptr = < const char * > code_bytes
800- name_ptr = < const char * > options._name
853+ name_ptr = < const char * > self ._nvrtc_name
801854
802855 with nogil:
803856 HANDLE_RETURN_NVRTC(NULL , cynvrtc.nvrtcCreateProgram(
@@ -969,7 +1022,7 @@ cdef object Program_compile_nvrtc(Program self, str target_type, object name_exp
9691022 cdef list options_list = self ._options.as_bytes(" nvrtc" , target_type)
9701023
9711024 result = _nvrtc_compile_and_extract(
972- prog, target_type, name_expressions, logs, options_list, self ._options.name ,
1025+ prog, target_type, name_expressions, logs, options_list, self ._nvrtc_name.decode() ,
9731026 )
9741027
9751028 cdef bint pch_creation_possible = self ._options.create_pch or self ._options.pch
@@ -997,14 +1050,14 @@ cdef object Program_compile_nvrtc(Program self, str target_type, object name_exp
9971050
9981051 cdef cynvrtc.nvrtcProgram retry_prog
9991052 cdef const char * code_ptr = < const char * > self ._code
1000- cdef const char * name_ptr = < const char * > self ._options._name
1053+ cdef const char * name_ptr = < const char * > self ._nvrtc_name
10011054 with nogil:
10021055 HANDLE_RETURN_NVRTC(NULL , cynvrtc.nvrtcCreateProgram(
10031056 & retry_prog, code_ptr, name_ptr, 0 , NULL , NULL ))
10041057 self ._h_nvrtc = create_nvrtc_program_handle(retry_prog)
10051058
10061059 result = _nvrtc_compile_and_extract(
1007- retry_prog, target_type, name_expressions, logs, options_list, self ._options.name ,
1060+ retry_prog, target_type, name_expressions, logs, options_list, self ._nvrtc_name.decode() ,
10081061 )
10091062
10101063 status = _read_pch_status(retry_prog)
0 commit comments