调试您的 Cython 程序¶
Cython 附带一个 GNU 调试器的扩展,可帮助用户调试 Cython 代码。要使用此功能,您需要安装 gdb 7.2 或更高版本,并使用 Python 支持构建(链接到 Python 2.6 或更高版本)。调试器支持版本 2.6 及更高版本的调试对象。对于 Python 3,代码应使用 Python 3 构建,调试器应使用 Python 2 运行(或者至少它应该能够找到 Python 2 Cython 安装)。请注意,例如,在最近版本的 Ubuntu 中,使用 apt-get
安装的 gdb
配置为使用 Python 3。在这样的系统上,可以通过下载 gdb
源代码,然后运行以下命令来获得 gdb
的正确配置
./configure --with-python=python2
make
sudo make install
安装 Cython 调试器可能很棘手。 此安装脚本和示例代码 可能会有所帮助。
调试器将需要 Cython 编译器可以导出的调试信息。这可以通过在设置脚本中将 gdb_debug=True
传递给 cythonize()
来实现
from setuptools import Extension, setup
extensions = [Extension('source', ['source.pyx'])]
setup(..., ext_modules=cythonize(extensions, gdb_debug=True))
在开发过程中,将 --inplace
标志传递给 setup.py
脚本通常很有帮助,这使得 setuptools 在“就地”构建您的项目,即不在单独的 build 目录中。
当从命令行直接调用 Cython 时,您可以使用 --gdb
标志让它写入调试信息
cython --gdb myfile.pyx
运行调试器¶
要运行 Cython 调试器并让它导入 Cython 导出的调试信息,请在构建目录中运行 cygdb
$ python setup.py build_ext --inplace
$ cygdb
GNU gdb (GDB) 7.2
...
(gdb)
使用 Cython 调试器时,最好使用带有调试符号编译的解释器构建和运行您的代码(即使用 --with-pydebug
配置或使用 -g
CFLAG 编译)。如果您的 Python 由您的包管理器安装和管理,您可能需要单独安装调试支持。如果使用 NumPy,那么您还需要安装 numpy 调试,否则您将看到 multiarray 的导入错误。例如,对于 ubuntu
$ sudo apt-get install python-dbg python-numpy-dbg
$ python-dbg setup.py build_ext --inplace
然后,您需要使用 python-dbg
运行您的脚本。确保在使用调试符号构建您的包时,如果 Cython 扩展以前被编译过,则重新编译它们。如果您的包是版本控制的,您可能希望在构建之前执行 git clean -fxd
或 hg purge --all
。
您还可以将其他参数传递给 gdb
$ cygdb /path/to/build/directory/ GDBARGS
即
$ cygdb . -- --args python-dbg mainscript.py
要告诉 cygdb 不要导入任何调试信息,请将 --
作为第一个参数提供
$ cygdb --
使用调试器¶
Cython 调试器带有一组命令,这些命令支持断点、堆栈检查、源代码列表、单步执行、单步跳过等。大多数这些命令类似于它们各自的 gdb 命令。
- cy break breakpoints...
在 Python、Cython 或 C 函数中设置断点。首先,它会查找具有该名称的 Cython 函数,如果 cygdb 不知道具有该名称的函数(或方法),它将设置一个(待处理的)C 断点。可以使用
-p
选项指定 Python 断点。可以为函数或方法名称设置断点,也可以完全“限定”它们,这意味着给出了函数的整个“路径”。
(gdb) cy break cython_function_or_method (gdb) cy break packagename.cython_module.cython_function (gdb) cy break packagename.cython_module.ClassName.cython_method (gdb) cy break c_function
您也可以在 Cython 行号上设置断点。
(gdb) cy break :14 (gdb) cy break cython_module:14 (gdb) cy break packagename.cython_module:14
Python 断点目前支持模块的名称(而不是整个包路径)以及函数或方法。
(gdb) cy break -p python_module.python_function_or_method (gdb) cy break -p python_function_or_method
注意
Python 断点仅在 Python 构建中有效,其中可以从调试器读取 Python 帧信息。为了确保这一点,请使用 Python 调试构建或使用调试支持编译的非剥离构建。
- cy step
单步执行 Python、Cython 或 C 代码。直接从 Cython 代码调用的 Python、Cython 和 C 函数被认为是相关的,并将单步执行到其中。
- cy next
单步执行 Python、Cython 或 C 代码。
- cy run
运行程序。默认解释器是用于构建扩展的解释器,或者是在“不导入调试信息”选项生效的情况下运行
cygdb
的解释器。可以使用 gdb 的file
命令覆盖解释器。
- cy cont
继续执行程序。
- cy up
- cy down
在堆栈中上下移动到被认为是相关帧的位置。
- cy finish
执行到遇到向上相关的帧或某些东西停止执行为止。
- cy bt
- cy backtrace
打印所有被认为是相关的帧的回溯。
-a
选项使其打印完整的回溯(所有 C 帧)。
- cy select
通过
cy backtrace
列出的编号选择堆栈帧。引入此命令是因为cy backtrace
打印的是反向堆栈跟踪,因此帧编号与 gdb 的bt
不同。
- cy print varname
打印局部或全局 Cython、Python 或 C 变量(取决于上下文)。变量也可以被解引用。
(gdb) cy print x x = 1 (gdb) cy print *x *x = (PyObject) { _ob_next = 0x93efd8, _ob_prev = 0x93ef88, ob_refcnt = 65, ob_type = 0x83a3e0 }
- cy set cython_variable = value
将 Cython 堆栈上的 Cython 变量设置为值。
- cy list
列出当前行周围的源代码。
- cy locals
- cy globals
打印所有局部和全局变量及其值。
- cy import FILE...
从作为参数给出的文件中导入调试信息。导入调试信息的 easiest 方式是使用 cygdb 命令行工具。
- cy exec code
在当前 Python 或 Cython 帧中执行代码。这与 Python 的交互式解释器类似。
对于 Python 帧,它使用来自 Python 帧的全局变量和局部变量,对于 Cython 帧,它使用在 Cython 模块上使用的全局变量字典和一个用局部 Cython 变量填充的新字典。
注意
cy exec
会修改状态并在被调试程序中执行代码,因此可能很危险。
示例
(gdb) cy exec x + 1
2
(gdb) cy exec import sys; print sys.version_info
(2, 6, 5, 'final', 0)
(gdb) cy exec
>global foo
>
>foo = 'something'
>end
便利函数¶
以下函数是 gdb 函数,这意味着它们可以在 gdb 表达式中使用。
- cy_cname(varname)¶
返回 Cython 变量的 C 变量名。对于全局变量,这可能实际上无效。
- cy_cvalue(varname)¶
返回 Cython 变量的值。
- cy_eval(expression)¶
在最近的 Python 或 Cython 帧中评估 Python 代码,并将表达式的结果作为 gdb 值返回。如果成功,这将提供一个新的引用,如果出错,则返回 NULL。
- cy_lineno()¶
返回所选 Cython 帧中的当前行号。
示例
(gdb) print $cy_cname("x")
$1 = "__pyx_v_x"
(gdb) watch $cy_cvalue("x")
Hardware watchpoint 13: $cy_cvalue("x")
(gdb) cy set my_cython_variable = $cy_eval("{'spam': 'ham'}")
(gdb) print $cy_lineno()
$2 = 12
配置调试器¶
调试器的某些方面可以使用 gdb 参数进行配置。例如,可以禁用颜色,可以配置终端背景颜色和断点自动完成。
-
cy_complete_unqualified¶
告诉 Cython 调试器
cy break
是否也应该完成普通函数名,即不以其模块名作为前缀。例如,如果您有一个名为spam
的函数,在模块M
中,它告诉您是否只完成M.spam
还是也只完成spam
。默认值为 true。
-
cy_colorize_code¶
告诉调试器是否对源代码进行着色。默认值为 true。
-
cy_terminal_background_color¶
告诉调试器有关终端背景颜色的信息,这会影响源代码着色。默认值为“dark”,另一个有效选项是“light”。
以下是这些参数的使用方法
(gdb) set cy_complete_unqualified off
(gdb) set cy_terminal_background_color light
(gdb) show cy_colorize_code