PyMaemo/Accessing APIs without Python bindings
This is an on-going document, and will be linked on the PyMaemo main page once finished
Contents |
Introduction
There are many libraries written in C that do not have native Python bindings yet. In Maemo, one of such libraries is libabook, used to manipulate the address book on Maemo devices.
While a full binding is still very useful, in most cases you need to use just a couple of functions and data structures to get your work done. Instead of waiting for a binding to be implemented, you can use Python's "ctypes" module, which allows to directly call functions and access data structures from C libraries.
This document will explain how to do call C library functions using ctypes, using libabook as an example. Most of the code snippets were based on source code from the Hermes application. This document is not meant to be a complete ctypes
guide; for that, be sure to read the official API documentation.
Basic usage
Let's say you want to use libc's printf, for some reason. All you need in python is:
import ctypes libc = ctypes.CDLL('libc.so.6') libc.printf('Hello world!')
In a few words, you create an object correspondent to the library you need and use it to call the function directly. You can also store the functions in plain python objects to use them easily later:
c_printf = libc.printf c_printf('Hello libc')
Remember that those are C functions, not Python ones, so you must supply arguments of the correct type to avoid undefined behavior. As a example, if I pass an integer to the above function, I get
>>> c_printf(1) Segmentation fault (core dumped)
Wrapping function arguments
Quoting http://docs.python.org/library/ctypes.html#calling-functions:
- None, integers, longs, byte strings and unicode strings are the only native Python objects that can directly be used as parameters in these function calls. None is passed as a C NULL pointer, byte strings and unicode strings are passed as pointer to the memory block that contains their data (char * or wchar_t *). Python integers and Python longs are passed as the platforms default C int type, their value is masked to fit into the C type.
For all other types, a ctypes
C wrapper must be used; you can find them at http://docs.python.org/library/ctypes.html#fundamental-data-types.
An usage example of these wrappers is shown below:
>>> libc.printf("a integer: %d, a double: %f\n", 42, 3.14) Traceback (most recent call last): File "<stdin>", line 1, in <module> ctypes.ArgumentError: argument 3: <type 'exceptions.TypeError'>: Don't know how to convert parameter 3
Integers are fine, but ctypes
can't handle Python doubles directly. ctypes.c_double()
will solve the problem here:
>>> libc.printf("a integer: %d, a double: %f\n", 42, ctypes.c_double(3.14)) a integer: 42, a double: 3.140000