There are a few more alternatives:
- pybind11 (already mentioned)
CTypes, for good and for bad, is included in the stdlib, the others require installation. cppyy uses a llvm runtime library so its installation is heavy. The others are simple to install. When weighting the possibilities, three criteria stand out for me: ease of use, maintainability, and performance. Here are my (maybe wrong) opinions, corrections or other opinions welcome.
Ease of use
pybind11 and cppyy are designed for c++ code. cython also has some support for c++. All of them have a learning curve. As others mentioned, ctypes (and cffi) will require either refactoring your headers to use `extern "C"` or discovering the mangled name.
CTypes will require reflecting the C structures and functions in python (best practices means you should state the `argtypes` and `restype` of each function or use a `PYFUNCTYPE` to make sure your users are calling the functions properly), the others know something about the code by parsing the headers.
Cython is designed for integrating C and python code, so wrapping code comes naturally to it. CFFI requires some care when using pointers.
Maintainability
The packages that parse headers can deal gracefully with some API changes. You may need to change your python code that calls the library to reflect the changes. CTypes will require manually tracking API changes. Abstractions always leak, so any changes in the library you are wrapping may leak into your python code. Cython and pybind11 will require recompilation to handle new headers (beyond python-level code adjustments). Depending on how you use it, so will CFFI. CTypes is not compiled.
Performance
CTypes will be the slowest of all the solutions (as will the non-compiled CFFI mode). cffi and cppyy will provide faster interfaces in PyPy. Cython, pybind11, cffi and cppyy should be equivalent on CPython (when using the compiled CFFI mode), with a small advantage to cython and pytbind11 (depending on the use case).
I created a small tutorial in wrapping c code in CTypes, Cython, cffi and cppyy (I wrote it before pybind11 was a thing), you can play with the jupyter notebook
https://github.com/mattip/c_from_python
Matti