DesignΒΆ

PyBindCpp is our own proposed solution to the problem which leverages Ctypes and C++11 in order to provide highly portable and seamless interoperability between C/C++ and Python. Most of the logic is implemented in Python via the Ctypes module which enables one to call functions from shared library files and do the appropriate type conversions. The key insight is to use C++11 for type deductions, and to feed that information back to Python in order to generate the appropriate Ctypes wrappers. In order to deduce the types of the variables and the signatures of the functions, we have relied heavily on recent features added to C++ such as template metaprogramming, type traits, parameter packs, and the auto specifier. Because of this, the minimum version of C++ necessary to compile PyBindCpp is C++11. Without these features, the only way to obtain the type and signature information of functions would have been to parse C++, which is a very difficult problem given the size and complexity of the language.

In designing PyBindCpp, we have been inspired by ChaiScript [TT], and we have borrowed heavily from its design. ChaiScript is a scripting language that targets C++ directly and takes advantage of its many modern features. The typesystem of ChaiScript is identical to the C++ type system with a few minor additions. Unlike ChaiScript, PyBindCpp is not a new language, but a module of Python, and it provides its own type conversion layer between C++ data types and Python data types. Like ChaiScript, PyBindCCpp is headers only and does not require any external tools or libraries to compile, just a modern C++ compiler.

PyBind11 [JRM16] is another library that is very similar in its design goals to PyBindCpp. However, there are some significant differences. Most of the programming logic in PyBind11 is coded in C++ and the library relies heavily on the CPython API making it difficult to port to other implementations of the Python language. PyBindCpp, on the other hand, uses Ctypes which is provided by most Python interpreters, and can therefore be easily ported. A design goal of PyBindCpp is to minimize reliance on the API to a bare minimum, perhaps even eliminate it completely, and instead leverage the ABI via Ctypes. Additionally, PyBindCpp is coded mainly in Python, and C++ is minimally used for type deduction. Many of the Python functions are made available to the C++ level via Ctypes callbacks. This saves us the effort of having to code them in C++, especially for code that is rarely executed (e.g., only once at import time) where speed is not that critical. This small speed penalty is more than offset by the simplicity of the code when written in Python.