{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "C extensions\n", "======================================================================\n", "\n", "Skeleton\n", "--------\n", "\n", "`extmodule.h`:" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "#ifndef EXTMODULE_H\n", "#define EXTMODULE_H\n", "\n", "#ifdef __cplusplus\n", "extern \"C\" {\n", "#endif\n", "\n", "/* Python.h must be included before everything else */\n", "#include \"Python.h\"\n", "\n", "/* include system headers here */\n", "\n", "#if !defined(EXTMODULE_IMPORT_ARRAY)\n", "#define NO_IMPORT_ARRAY\n", "#endif\n", "#include \"numpy/arrayobject.h\"\n", "\n", "#ifdef __cplusplus\n", "}\n", "#endif\n", "\n", "#endif" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that `PY_ARRAY_UNIQUE_SYMBOL` must be set to a unique value\n", "for each extension module. But, you actually don't need to set it at all\n", "unless you are going to compile an extension module that uses two\n", "different source files\n", "\n", "`extmodule.c`:" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "#define EXTMODULE_IMPORT_ARRAY\n", "#include \"extmodule.h\"\n", "#undef EXTMODULE_IMPORT_ARRAY\n", "\n", "static PyObject* FooError;\n", "\n", "static PyObject* Ext_Foo(PyObject* obj, PyObject* args) {\n", " Py_INCREF(Py_None);\n", " return Py_None;\n", "}\n", "\n", "static PyMethodDef methods[] = {\n", " {\"foo\", (PyCFunction) Ext_Foo, METH_VARARGS, \"\"},\n", " {NULL, NULL, 0, NULL}\n", "};\n", "\n", "PyMODINIT_FUNC init_extmodule() {\n", " PyObject* m;\n", " m = Py_InitModule(\"_extmodule\", methods);\n", " import_array();\n", " SVMError = PyErr_NewException(\"_extmodule.FooError\", NULL, NULL);\n", " Py_INCREF(FooError);\n", " PyModule_AddObject(m, \"FooError\", FooError);\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If your extension module is contained in a single source file then you\n", "can get rid of extmodule.h entirely and replace the first part of\n", "`extmodule.c` with" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "#inlude \"Python.h\"\n", "#include \"numpy/arrayobject.h\"\n", "\n", "/* remainder of extmodule.c after here */" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Debugging C Extensions on Windows\n", "---------------------------------\n", "\n", "Debugging C extensions on Windows can be tricky. If you compile your\n", "extension code in debug mode, you have to link against the debug version\n", "of the Python library, e.g. `Python24_d.lib`. When building with\n", "Visual Studio, this is taken care of by a pragma in `Python24.h`. If\n", "you force the compiler to link debug code against the release library,\n", "you will probably get the following errors (especially when compiling\n", "SWIG wrapped codes):" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_Dealloc referenced in function _PySwigObject_format\n", "extmodule.obj : error LNK2019: unresolved external symbol __imp___Py_NegativeRefcount referenced in function _PySwigObject_format\n", "extmodule.obj : error LNK2001: unresolved external symbol __imp___Py_RefTotal\n", "extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugFree referenced in function _PySwigObject_dealloc\n", "extmodule.obj : error LNK2019: unresolved external symbol __imp___PyObject_DebugMalloc referenced in function _PySwigObject_New\n", "extmodule.obj : error LNK2019: unresolved external symbol __imp__Py_InitModule4TraceRefs referenced in function _init_extmodule" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, now you also need a debug build of the Python interpreter if\n", "you want to import this debuggable extension module. Now you also need\n", "debug builds of every other extension module you use. Clearly, this can\n", "take some time to get sorted out.\n", "\n", "An alternative is to build your library code as a debug DLL. This way,\n", "you can at least that your extension module is passing the right data to\n", "the library code you are wrapping.\n", "\n", "As an aside, it seems that the MinGW GCC compiler doesn't produce debug\n", "symbols that are understood by the Visual Studio debugger.\n", "\n", "Valgrind\n", "--------\n", "\n", "To develop a stable extension module, it is essential that you check the\n", "memory allocation and memory accesses done by your C code. On Linux, you\n", "can use [Valgrind](http://www.valgrind.org/). On Windows, you could try\n", "a commercial tool such as [Rational\n", "PurifyPlus](http://www-306.ibm.com/software/awdtools/purifyplus/).\n", "\n", "Before using Valgrind, make sure your extension module is compiled with\n", "the `-g` switch to GCC so that you can get useful stack traces when\n", "errors are detected.\n", "\n", "Then put the following in a shell script, say `valgrind_py.sh`:" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "#!/bin/sh\n", "valgrind \\\n", " --tool=memcheck \\\n", " --leak-check=yes \\\n", " --error-limit=no \\\n", " --suppressions=valgrind-python.supp \\\n", " --num-callers=10 \\\n", " -v \\\n", " python $1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "`valgrind-python.supp` suppresses some warnings caused by the Python code. You can find the suppression file for Python 2.4 [in the Python SVN repository](http://svn.python.org/projects/python/branches/release24-maint/Misc/valgrind-python.supp). See also [README.valgrind](http://svn.python.org/projects/python/branches/release24-maint/Misc/README.valgrind) in the same location. Some of the suppressions are commented out by default. Enable them by removing the # comment markers.\n", "\n", "Execute `chmod +x valgrind_py.sh` and run it as `./valgrind_py.sh test_extmodule.py`.\n", "\n", "Documentation\n", "-------------\n", "\n", "* [Extending and Embedding the Python Interpreter](http://docs.python.org/ext/ext.html) (read this first)\n", "* [Python/C API Reference Manual](http://docs.python.org/api/api.html) (then browse through this)\n", "* Chapter 13 of [Guide to NumPy](http://www.tramy.us/) describes the complete API\n", "* Chapter 14 deals with extending !NumPy (make sure you have the edition dated March 15, 2006 or later)\n", "\n", "Examples\n", "--------\n", "\n", " * [ndimage in the SciPy SVN repository](http://projects.scipy.org/scipy/scipy/browser/trunk/Lib/ndimage)\n", " * [NumPy arrays](NumPy_arrays) (collection of small examples)\n", "\n", "Mailing List Threads\n", "--------------------\n", "\n", "* [Freeing memory allocated in C](\n", "http://thread.gmane.org/gmane.comp.python.numeric.general/5206/focus=5206)\n", "* [port C/C++ matlab mexing code to numpy](http://thread.gmane.org/gmane.comp.python.scientific.user/7392/focus=7400)\n", "* [newbie for writing numpy/scipy extensions](http://thread.gmane.org/gmane.comp.python.numeric.general/5186/focus=5186)\n", "* [Array data and struct alignment](http://thread.gmane.org/gmane.comp.python.numeric.general/5234/focus=5234)\n", "\n" ] } ], "metadata": {} } ] }