I'm far from a python expert but I hear this one all the time, about its C/C++ bindings. How does this concept work, and how does Python (and Java) bind to C-based APIs like OpenGL? This stuff has always been a mystery to me.
"Bindings" are implemented either as a pure Python library using ctypes or as a dynamic-link library using Python/C API. The second option is sometimes used with tools like SWIG which make the task easier by taking care of generating the "boiler-plate" code or Boost.
Perhaps the best feature of Python when it comes to integrating with existing technologies is that “glue language” factor. Rather than rebuilding existing technologies and systems from scratch, Python app development can simply use Python's REST API or FFI (Foreign Language Interface) to bind them together.
Compile Python to CPython code can make calls directly into C modules. Those C modules can be either generic C libraries or libraries built specifically to work with Python. Cython generates the second kind of module: C libraries that talk to Python's internals, and that can be bundled with existing Python code.
I have a feeling you are looking for an explanation of the mechanism and not a link to the API or instructions on how to code it. So, as I understand it . . .
The main interpreter is typically written in C and is dynamically linked. In a dynamically linked environment, even C89 has a certain amount of reflective behavior. In particular, the dlopen(3)
and dlsym(3)
calls will load a dynamic (typically ELF) library and look up the address of a symbol named by a string. Give that address, the interpreter can call a function. Even if statically linked, the interpreter can know the address of C functions whose names are compiled into it.
So then, it's just a simple matter of having the interpreted code tell the interpreter to call a particular native function in a particular native library.
The mechanism can be modular. An extension library for the interpreter, written in the script, can itself invoke the bare hooks for dlopen(3)
and dlsym(3)
and hook up to a new library that the interpreter never knew about.
For passing simple objects by value, a few prototype functions will typically allow various calls. But for structured data objects (imagine stat(2)) the wrapper module needs to know the layout of the data. At some point, either when packaging the extension module or when installing it, a C interface module includes the appropriate header files and in conjunction with handwritten code constructs an interface object. This is why you may need to install something like libsqlite3-dev
even if you already had sqlite3
on your system; only the -dev
package has the .h files needed to recompile the linkage code.
I suppose we could sum this up by saying: "it's done with brute force and ignorance". :-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With