C 扩展

日期2006-12-08(最后修改),2006-04-28(创建)

骨架

extmodule.h:

#ifndef EXTMODULE_H #define EXTMODULE_H #ifdef __cplusplus extern "C" { #endif /* Python.h must be included before everything else */ #include "Python.h" /* include system headers here */ #if !defined(EXTMODULE_IMPORT_ARRAY) #define NO_IMPORT_ARRAY #endif #include "numpy/arrayobject.h" #ifdef __cplusplus } #endif #endif

请注意,PY_ARRAY_UNIQUE_SYMBOL 必须为每个扩展模块设置一个唯一的值。但是,除非您要编译使用两个不同源文件的扩展模块,否则您实际上不需要设置它。

extmodule.c:

#define EXTMODULE_IMPORT_ARRAY #include "extmodule.h" #undef EXTMODULE_IMPORT_ARRAY static PyObject* FooError; static PyObject* Ext_Foo(PyObject* obj, PyObject* args) { Py_INCREF(Py_None); return Py_None; } static PyMethodDef methods[] = { {"foo", (PyCFunction) Ext_Foo, METH_VARARGS, ""}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC init_extmodule() { PyObject* m; m = Py_InitModule("_extmodule", methods); import_array(); SVMError = PyErr_NewException("_extmodule.FooError", NULL, NULL); Py_INCREF(FooError); PyModule_AddObject(m, "FooError", FooError); }

如果您的扩展模块包含在单个源文件中,那么您可以完全删除 extmodule.h,并将 extmodule.c 的第一部分替换为

#inlude "Python.h" #include "numpy/arrayobject.h" /* extmodule.c 的其余部分在此之后 */

在 Windows 上调试 C 扩展

在 Windows 上调试 C 扩展可能很棘手。如果您在调试模式下编译扩展代码,则必须链接到 Python 库的调试版本,例如 Python24_d.lib。在使用 Visual Studio 构建时,Python24.h 中的 pragma 会处理此问题。如果您强制编译器将调试代码链接到发布库,您可能会遇到以下错误(尤其是在编译 SWIG 包装代码时)

extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_Dealloc referenced in function _PySwigObject_format extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_NegativeRefcount referenced in function _PySwigObject_format extmodule.obj : error LNK2001: unresolved external symbol __imp___Py_RefTotal extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugFree referenced in function _PySwigObject_dealloc extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugMalloc referenced in function _PySwigObject_New extmodule.obj : error LNK2019: unresolved external symbol __imp__Py_InitModule4TraceRefs referenced in function _init_extmodule

但是,现在如果您想导入此可调试的扩展模块,您还需要 Python 解释器的调试版本。现在您还需要使用您使用的每个其他扩展模块的调试版本。显然,这可能需要一些时间才能解决。

另一种方法是将您的库代码构建为调试 DLL。这样,您至少可以确保您的扩展模块正在将正确的数据传递到您正在包装的库代码。

顺便说一句,似乎 MinGW GCC 编译器不会生成 Visual Studio 调试器可以理解的调试符号。

Valgrind

要开发一个稳定的扩展模块,必须检查 C 代码执行的内存分配和内存访问。在 Linux 上,您可以使用 Valgrind。在 Windows 上,您可以尝试使用商业工具,例如 Rational PurifyPlus

在使用 Valgrind 之前,请确保您的扩展模块使用 -g 开关编译到 GCC,以便在检测到错误时获得有用的堆栈跟踪。

然后将以下内容放入一个 shell 脚本中,例如 valgrind_py.sh

#!/bin/sh valgrind \ --tool=memcheck \ --leak-check=yes \ --error-limit=no \ --suppressions=valgrind-python.supp \ --num-callers=10 \ -v \ python $1

valgrind-python.supp 会抑制 Python 代码引起的一些警告。您可以在 Python SVN 仓库中找到 Python 2.4 的抑制文件 此处。还可以参考同一位置的 README.valgrind。默认情况下,一些抑制项被注释掉了。通过移除 # 注释标记来启用它们。

执行 chmod +x valgrind_py.sh 并运行它,例如 ./valgrind_py.sh test_extmodule.py

文档

示例

邮件列表主题

章节作者:AlbertStrasheim、TravisOliphant、DavidLinke