Eric Radman : a Journal

Extending C with Python

Sometimes it is useful to borrow functionality that is implemented in a Python library. To do this we can initialize an embedded Python interpreter, and then load functions.

Getting Started

The basic structure of initializing the interpreter and loading the python-hostlist module is as follows

#include <Python.h>

int
main(int argc, char *argv[])
{
    PyObject *pModule;

    Py_SetProgramName(argv[0]);
    Py_Initialize();

    /* import module */
    pModule = PyImport_ImportModule("hostlist");
    if (pModule == NULL) {
        if (PyErr_Occurred())
            PyErr_Print();
        exit(1);
    }

    Py_DECREF(pModule);
    Py_Finalize();
    return 0;
}

Now we can build using

CFLAGS != python2.7-config --cflags
LDFLAGS != python2.7-config --ldflags

hostlist: hostlist.c
    cc ${CFLAGS} -L/usr/local/lib ${LDFLAGS} $< -o $@

Calling Functions

Python arguments are return values are all PyOjbect pointers, and we can use the well-documented set of standard functions to instantiate data and validate/convert outputs

PyObject* expand_hostlist(PyObject *pModule, PyObject* pHostlistExp) {
    PyObject *pFunc;
    PyObject *pArgs, *pValue;

    /* get pointer to function */
    pFunc = PyObject_GetAttrString(pModule, "expand_hostlist");
    if (!pFunc) {
        if (PyErr_Occurred())
            PyErr_Print();
        exit(1);
    }

    /* construct an argument list */
    pArgs = PyTuple_New(1);
    PyTuple_SetItem(pArgs, 0, pHostlistExp);
    pValue = PyObject_CallObject(pFunc, pArgs);

    Py_DECREF(pArgs);
    Py_DECREF(pFunc);

    /* ensure the return value is what we expect */
    if (pValue && PyList_Check(pValue)) {
        return pValue;
    }
    return NULL;
}

To call this function, simply convert a C string into a Python object using PyString_FromString(argv[1]).

Last updated on September 28, 2021