I have the source to a C library with a C API. I want to expose the functions and C data structures to python, so that I can use the library in my python scripts.
There are over 200+ functions and about 50 data structures, so it would be preferable if I could automate the generation of the “glue” code between C and Python.
I am currently reading up on SWIG, as it seems to be the way forward. Are there other alternatives I should be looking at (and why?).
Last but not the least, (assuming SWIG is the way forward), does anyone have a link to a good tutorial that shows how to write a Python extension module from an existing C library?
I have used SWIG 2.x to convert a pretty complex C and C++ API and it saved me a lot of time.
One important limitation in SWIG is that structs within structs are not handled very well. The same applies to classes in C++. I had full control over the C/C++ APIs, so beforehand I flattened the couple of structs that I had that used inner structs and avoided this problem.
My first recommendation would be that you define a basic module for SWIG that just imports your header files, and see how SWIG likes it. Like a compiler, SWIG will output warning and errors it finds, and those will be what you will need to work on.
After I had all the functions working, I was not completely happy with the result. SWIG translates all your functions literally, but the problem is that some idioms that are very common in C/C++ look pretty weird in Python. For example, functions that have output arguments specified as pointers will not be very Pythonic. For example, consider this function, which is pretty common in C/C++:
This function takes a buffer and a size, and fills in the buffer with a string, returning how many bytes were actually used, or 0 in case of an error. In Python having to send a buffer (a string) and a size as arguments would be awfully odd, so for functions of this style I’ve added alternative versions that translate to more friendly functions. In this case, I did something like this:
The implementation of this function simply passes a static buffer of some maximum size into the original
getPath(), and returns the address of the static buffer, or NULL if there is an error. Disclaimer: I use a C++ compiler, so I could define twogetPath()functions with different arguments. In C you would need to use different names for each function. SWIG converts char* to Python strings automatically, so this translates very nicely.Instead of defining alternative functions in C/C++, you can also provide instructions to SWIG on how you want to convert certain functions and its arguments. For example, SWIG allows you to tie a pair of buffer and size arguments and treat them like a single string argument on the translated function. There are also many more convenience translations like this.
As far as tutorials I did not find anything useful outside of the official SWIG documentation, which is pretty good, and has a section that is specific to Python.
I hope this helps.