6 The current directory should contain a directory named 'cython_debug', or a
7 path to the cython project directory should be given (the parent directory of
10 Additional gdb args can be provided only if a path to the project directory is
23 logger
= logging
.getLogger(__name__
)
25 def make_command_file(path_to_debug_info
, prefix_code
='', no_import
=False):
27 pattern
= os
.path
.join(path_to_debug_info
,
29 'cython_debug_info_*')
30 debug_files
= glob
.glob(pattern
)
33 sys
.exit('%s.\nNo debug files were found in %s. Aborting.' % (
34 usage
, os
.path
.abspath(path_to_debug_info
)))
36 fd
, tempfilename
= tempfile
.mkstemp()
37 f
= os
.fdopen(fd
, 'w')
40 f
.write('set breakpoint pending on\n')
41 f
.write("set print pretty on\n")
42 f
.write('python from Cython.Debugger import libcython, libpython\n')
45 # don't do this, this overrides file command in .gdbinit
46 # f.write("file %s\n" % sys.executable)
49 path
= os
.path
.join(path_to_debug_info
, "cython_debug", "interpreter")
50 interpreter_file
= open(path
)
52 interpreter
= interpreter_file
.read()
54 interpreter_file
.close()
55 f
.write("file %s\n" % interpreter
)
56 f
.write('\n'.join('cy import %s\n' % fn
for fn
in debug_files
))
57 f
.write(textwrap
.dedent('''\
61 gdb.lookup_type('PyModuleObject')
64 'Python was not compiled with debug symbols (or it was '
65 'stripped). Some functionality may not work (properly).\\n')
75 usage
= "Usage: cygdb [options] [PATH [-- GDB_ARGUMENTS]]"
77 def main(path_to_debug_info
=None, gdb_argv
=None, no_import
=False):
79 Start the Cython debugger. This tells gdb to import the Cython and Python
80 extensions (libcython.py and libpython.py) and it enables gdb's pending
83 path_to_debug_info is the path to the Cython build directory
84 gdb_argv is the list of options to gdb
85 no_import tells cygdb whether it should import debug information
87 parser
= optparse
.OptionParser(usage
=usage
)
88 parser
.add_option("--gdb-executable",
89 dest
="gdb", default
='gdb',
90 help="gdb executable to use [default: gdb]")
91 parser
.add_option("--verbose", "-v",
92 dest
="verbosity", action
="count", default
=0,
93 help="Verbose mode. Multiple -v options increase the verbosity")
95 (options
, args
) = parser
.parse_args()
96 if path_to_debug_info
is None:
98 path_to_debug_info
= args
[0]
100 path_to_debug_info
= os
.curdir
105 if path_to_debug_info
== '--':
108 logging_level
= logging
.WARN
109 if options
.verbosity
== 1:
110 logging_level
= logging
.INFO
111 if options
.verbosity
== 2:
112 logging_level
= logging
.DEBUG
113 logging
.basicConfig(level
=logging_level
)
115 logger
.info("verbosity = %r", options
.verbosity
)
116 logger
.debug("options = %r; args = %r", options
, args
)
117 logger
.debug("Done parsing command-line options. path_to_debug_info = %r, gdb_argv = %r",
118 path_to_debug_info
, gdb_argv
)
120 tempfilename
= make_command_file(path_to_debug_info
, no_import
=no_import
)
121 logger
.info("Launching %s with command file: %s and gdb_argv: %s",
122 options
.gdb
, tempfilename
, gdb_argv
)
123 logger
.debug('Command file (%s) contains: """\n%s"""', tempfilename
, open(tempfilename
).read())
124 logger
.info("Spawning %s...", options
.gdb
)
125 p
= subprocess
.Popen([options
.gdb
, '-command', tempfilename
] + gdb_argv
)
126 logger
.info("Spawned %s (pid %d)", options
.gdb
, p
.pid
)
129 logger
.debug("Waiting for gdb (pid %d) to exit...", p
.pid
)
131 logger
.debug("Wait for gdb (pid %d) to exit is done. Returned: %r", p
.pid
, ret
)
132 except KeyboardInterrupt:
136 logger
.debug("Removing temp command file: %s", tempfilename
)
137 os
.remove(tempfilename
)
138 logger
.debug("Removed temp command file: %s", tempfilename
)