11 #import distutils.core
12 #from distutils import sysconfig
13 from distutils
import ccompiler
16 import Cython
.Distutils
.extension
17 import Cython
.Distutils
.build_ext
18 from Cython
.Debugger
import Cygdb
as cygdb
20 root
= os
.path
.dirname(os
.path
.abspath(__file__
))
21 codefile
= os
.path
.join(root
, 'codefile')
22 cfuncs_file
= os
.path
.join(root
, 'cfuncs.c')
26 source_to_lineno
= dict([ (line
.strip(), i
+ 1) for i
, line
in enumerate(f
) ])
30 # Cython.Distutils.__init__ imports build_ext from build_ext which means we
31 # can't access the module anymore. Get it from sys.modules instead.
32 build_ext
= sys
.modules
['Cython.Distutils.build_ext']
38 if have_gdb
is not None:
42 p
= subprocess
.Popen(['gdb', '-v'], stdout
=subprocess
.PIPE
)
45 # gdb was not installed
48 gdb_version
= p
.stdout
.read().decode('ascii', 'ignore')
53 # Based on Lib/test/test_gdb.py
54 regex
= "^GNU gdb [^\d]*(\d+)\.(\d+)"
55 gdb_version_number
= list(map(int, re
.search(regex
, gdb_version
).groups()))
57 if gdb_version_number
>= [7, 2]:
58 python_version_script
= tempfile
.NamedTemporaryFile(mode
='w+')
60 python_version_script
.write(
61 'python import sys; print("%s %s" % sys.version_info[:2])')
62 python_version_script
.flush()
63 p
= subprocess
.Popen(['gdb', '-batch', '-x', python_version_script
.name
],
64 stdout
=subprocess
.PIPE
)
66 python_version
= p
.stdout
.read().decode('ascii')
71 python_version_number
= list(map(int, python_version
.split()))
75 python_version_script
.close()
77 # Be Python 3 compatible
79 or gdb_version_number
< [7, 2]
80 or python_version_number
< [2, 6]):
82 'Skipping gdb tests, need gdb >= 7.2 with Python >= 2.6')
88 class DebuggerTestCase(unittest
.TestCase
):
92 Run gdb and have cygdb import the debug information from the code
93 defined in TestParseTreeTransforms's setUp method
98 self
.tempdir
= tempfile
.mkdtemp()
99 self
.destfile
= os
.path
.join(self
.tempdir
, 'codefile.pyx')
100 self
.debug_dest
= os
.path
.join(self
.tempdir
,
102 'cython_debug_info_codefile')
103 self
.cfuncs_destfile
= os
.path
.join(self
.tempdir
, 'cfuncs')
105 self
.cwd
= os
.getcwd()
107 os
.chdir(self
.tempdir
)
109 shutil
.copy(codefile
, self
.destfile
)
110 shutil
.copy(cfuncs_file
, self
.cfuncs_destfile
+ '.c')
112 compiler
= ccompiler
.new_compiler()
113 compiler
.compile(['cfuncs.c'], debug
=True, extra_postargs
=['-fPIC'])
116 test_directory
=self
.tempdir
,
120 optimization_disabler
= build_ext
.Optimization()
122 cython_compile_testcase
= runtests
.CythonCompileTestCase(
123 workdir
=self
.tempdir
,
124 # we clean up everything (not only compiled files)
125 cleanup_workdir
=False,
126 tags
=runtests
.parse_tags(codefile
),
131 new_stderr
= open(os
.devnull
, 'w')
134 sys
.stderr
= new_stderr
136 optimization_disabler
.disable_optimization()
138 cython_compile_testcase
.run_cython(
139 targetdir
=self
.tempdir
,
142 extra_compile_options
={
144 'output_dir':self
.tempdir
,
149 cython_compile_testcase
.run_distutils(
151 workdir
=self
.tempdir
,
152 extra_extension_args
={'extra_objects':['cfuncs.o']},
156 optimization_disabler
.restore_state()
160 # ext = Cython.Distutils.extension.Extension(
164 # extra_objects=['cfuncs.o'])
166 # distutils.core.setup(
167 # script_args=['build_ext', '--inplace'],
169 # cmdclass=dict(build_ext=Cython.Distutils.build_ext)
180 shutil
.rmtree(self
.tempdir
)
183 class GdbDebuggerTestCase(DebuggerTestCase
):
189 super(GdbDebuggerTestCase
, self
).setUp()
191 prefix_code
= textwrap
.dedent('''\
198 def excepthook(type, value, tb):
199 traceback.print_exception(type, value, tb)
202 sys.excepthook = excepthook
204 # Have tracebacks end up on sys.stderr (gdb replaces sys.stderr
205 # with an object that calls gdb.write())
206 sys.stderr = sys.__stderr__
211 code
= textwrap
.dedent('''\
214 from Cython.Debugger.Tests import test_libcython_in_gdb
215 test_libcython_in_gdb.main(version=%r)
218 ''' % (sys
.version_info
[:2],))
220 self
.gdb_command_file
= cygdb
.make_command_file(self
.tempdir
,
223 f
= open(self
.gdb_command_file
, 'a')
229 args
= ['gdb', '-batch', '-x', self
.gdb_command_file
, '-n', '--args',
230 sys
.executable
, '-c', 'import codefile']
233 path
= os
.environ
.get('PYTHONPATH')
236 paths
.append(os
.path
.dirname(os
.path
.dirname(
237 os
.path
.abspath(Cython
.__file
__))))
238 env
= dict(os
.environ
, PYTHONPATH
=os
.pathsep
.join(paths
))
240 self
.p
= subprocess
.Popen(
242 stdout
=open(os
.devnull
, 'w'),
243 stderr
=subprocess
.PIPE
,
251 super(GdbDebuggerTestCase
, self
).tearDown()
253 try: self
.p
.stdout
.close()
255 try: self
.p
.stderr
.close()
259 os
.remove(self
.gdb_command_file
)
262 class TestAll(GdbDebuggerTestCase
):
268 out
, err
= self
.p
.communicate()
269 err
= err
.decode('UTF-8')
271 exit_status
= self
.p
.returncode
274 sys
.stderr
.write(err
)
275 elif exit_status
>= 2:
277 start
= u
'%s v INSIDE GDB v %s' % (border
, border
)
278 end
= u
'%s ^ INSIDE GDB ^ %s' % (border
, border
)
279 errmsg
= u
'\n%s\n%s%s' % (start
, err
, end
)
281 sys
.stderr
.write(errmsg
)
284 if __name__
== '__main__':