Wrapping C libraries in Python
Introduction
Given that the library code is handy it’s a better to write a simple example program to test all the function that are supposed to be exposed by the python wrapper module. For this example I’m using devmem2
utility. The reason behind is that it is very small, with limited functions and requires elevated access as well.
Code
Full code can be found here
Selecting Lib and Functions to expose
As mentioned above the first step is to package and test the code using an example file. Once we have the C build up and running it’s time to expose the devmem2.h
to python interface C file.
Functions about to get exposed
// read the value at given memory addr
unsigned long read_addr(off_t target);
// write the value at given memory addr
unsigned long write_addr(off_t target, unsigned long writeval);
// print usage
void usage(void);
Writing Python interface
The interface for python C file follow a standard structure as explained here
All the functions that are needed to exposed are defined using this template
static PyObject* foo(PyObject *self, PyObject *args) {
// call C function here and collect result if any
// return result
// return Py_BuildValue("pattern", vals...)
// return Nothing
// Py_RETURN_NONE
}
Complete example for reading an address
static PyObject* devmem_read(PyObject *self, PyObject *args) {
int ok;
unsigned long addr;
unsigned int value = 0;
ok = PyArg_ParseTuple(args, "l", &addr);
if (ok) {
value = read_addr((off_t)addr);
}
return Py_BuildValue("i", value);
}
Exposing Interfaced functions
Functions and types defined here are exported as a extension module, as explained here
Wrapper python module is defined with a different name and it specifies this auto-generated module as its extension module in its setup.py
module = Extension('_devmem',
define_macros=define_macros,
extra_compile_args=extra_compile_args,
sources=c_sources,
include_dirs=['c_src'])
setup(
...
ext_modules=[module],
...
)
In its code the wrapped module can call the internal module _devmem
as any other python module. Here it is exposing a user friendly function to call read_mem
function of devmem2
C library
import _devmem
def read_mem(addr=None):
return _devmem.devmem_read(addr)
Using Python Package
Once built and installed the python package can be used to perform devmem2
functions.
import pydevmem
print(pydevmem.read_mem(0))
print(pydevmem.write_mem(0, 0))
Since this operation requires elevated access it is advisable to run with sudo.