Friday, August 12, 2011

Python C Extension

Following Andrew Dalke's example, this is perhaps the simplest possible C extension for Python. For explanation of what's happening, see his page.

[ Something's gone wacko with this post---it's single spaced in preview, double after posting ]

x.c

#include <math.h>

#include "Python.h"

int process (const char *c, double f) {
int i = 0;
if (c[0] == 'c') {
i = floor(f);
}
return i;
}

PyDoc_STRVAR(x__doc__,
"x module for process'ing stuff");

PyDoc_STRVAR(process__doc__,
"c,f -> do something with f if c == 'c'");

static PyObject *
py_process(PyObject *self, PyObject *args) {
double f = 0;
char *c;
int i;
if (!PyArg_ParseTuple(args, "sd:process", &c, &f))
return NULL;
i = process(c,f);
return PyInt_FromLong((long) i);
}

static PyMethodDef x_methods[] = {
{"process", py_process, METH_VARARGS, process__doc__},
{NULL, NULL} /* sentinel */
};

PyMODINIT_FUNC
initx(void)
{
Py_InitModule3("x", x_methods, x__doc__);
}


setup.py

from distutils.core import setup, Extension


setup(name="x", version="0.0",
ext_modules = [Extension("x", ["x.c"])])



> python setup.py build

running build
running build_ext
building 'x' extension
creating build
creating build/temp.macosx-10.6-universal-2.6
gcc-4.2 -fno-strict-aliasing -fno-common -dynamic -DNDEBUG -g -fwrapv -Os -Wall -Wstrict-prototypes -DENABLE_DTRACE -arch i386 -arch ppc -arch x86_64 -pipe -I/System/Library/Frameworks/Python.framework/Versions/2.6/include/python2.6 -c x.c -o build/temp.macosx-10.6-universal-2.6/x.o
creating build/lib.macosx-10.6-universal-2.6
gcc-4.2 -Wl,-F. -bundle -undefined dynamic_lookup -arch i386 -arch ppc -arch x86_64 build/temp.macosx-10.6-universal-2.6/x.o -o build/lib.macosx-10.6-universal-2.6/x.so

You can control which architecture is build via setup.py with:

export ARCHFLAGS="-arch x86_64"


> ln -s build/lib.macosx-10.6-universal-2.6/x.so x.so

>
> python -c "import math; import x; print x.process('c',math.pi)"
3
> python -c "import math; import x; print x.process('a',math.pi)"
0
> python
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import x
>>> x.__doc__
"x module for process'ing stuff"
>>> x.process.__doc__
"c,f -> do something with f if c == 'c'"
>>>


Looks good.

Note: on my 64-bit machines I'm getting a warning:

x.c: In function ‘process’:

x.c:7: warning: implicit conversion shortens 64-bit value into a 32-bit value

Converting i to long doesn't help. I'll try to look into that.