+49 6221 672 19-00 info@hdvisionsystems.com

Easing Customer Access With pybind11

Tangle Of Languages

A good method to start a fight among software developers is to ask one simple question:
“What is the best programming language?”

That’s why a lot of people prefer to focus on the less contentious question:
“What is the most popular language?”

An easy way to get a rough idea of the popularity of a language is to check its usage in open source code.

If we take a look at githubs most popular languages, a few evergreens appear:

  • python
  • JavaScript
  • java
  • go
  • C++

Two of these evergreens deserve special attention.

First C++, the byzantine, ubiquitous tool for developing flexible and fast code, with moderate comfort.

I am sure a lot of people will find C++ rather uncomfortable, especially compared to python.

Python is a popular interpreted language. It is read pretty much like pseudo-code, is rather easy to learn, and is supported by an extensive collection of different libraries.

 

The Dilemma

This presents a challenge:

We can write in C++, because we wish to be faster or because we build upon a code base already written in C++.
We can write it in python, so it is easier to understand and can be sued by more people.

The perfect solution is of course both.

To achieve this, we have to introduce a software layer, known as an interface, facilitating communication between the C++ library and a python script that will use the libraries functionalities.

pybind11

We decided to use pybind11.

According to its github page “pybind11 is a lightweight header-only library that exposes C++ types in Python […]”.

It also exposes classes and functions, permitting us to make our entire application-programming-interface available in python and therefore to the customer.

All we have to do, is adding a small .cpp file to our library and compile with a specific cmake-function to create a file, that can be directly used by python.
In other words, pybind11 is relative easy to use and usually does not require significant changes to the already existing code.

It can be included in the project as a git submodule via its github repository or via conan, so it should be easy to integrate into preexisting projects.

 

How-To

While pybind11 of course provides its own documentation, I struggled with it.

So I will expand upon it.

I highly encourage you to read at least the  basic example, since parts of this are derivatives of it.

To create the python readable file, we simply add

pybind11_add_module()

a simple add_library-wrapper to our CMakeLists.txt, after we included the pybind11 camke-files.

The content should be the .cpp file we wish to turn into the python usable file (under windows, this will be a .pyd file).

In the .cpp file we have to declare our module and preferable provide a docstring.

PYBIND11_MODULE(MyModuleName, module) {
    module.doc() = "Perfect docstring.";
}

Functions can now be added in the form of function references from the examples:

#include <pybind11/pybind11.h>
int add(int i, int j) {
    return i + j;
}
PYBIND11_MODULE(example, m) {
    m.doc() = "pybind11 example plugin"; // optional module docstring
    m.def("add", &add, "A function that adds two numbers");
}

Classes are added in a similar manner as described in the docs. Note that the addition of a method returns the call’s object, so multiple methods can be chained.

PYBIND11_MODULE(example, module) {
    py::class_<Wheel>(module, "Wheel")
        .def(py::init<Radius()&>()) // A constructor with an argument
        .def("turn", &Wheel::Turn)
        .def("stop", &Wheel::Stop);
}

If you wish to test your new library make sure the generated binary is in the same directory as your python interpreter.

Now you have to import your module by its assigned name.

In our two last cases this would be “example”. So we may write:

import example
wheelInstance = example.Wheel(5.0)
print(Wheel.turn())

This should print out the return value of the “Turn”method of your wheel class.

 

Easy Data Conversion And Interpreter

In case you did not discover this already, pybind11 does permit the direct conversion from stl to python and eigen to numpy types. It also enables you to embed a python interpreter.

This is very convenient if you wish to process python data-types as input, just bear in mind, that the interpreter should be only opened once, so if your code is called from the python interpreter, you should not start the interpreter in your code again.

I also advise mixing python and C++ code too liberally, because such constructions can be rather complex. Jumping between 2 languages 5 times in a single function call is the kind of fun I intend to avoid in my projects, since I doubt that after a few growth cycles I or my IDE will be able to analyze the code correctly.

 

Conclusion

I hope this post has motivated you to take a look at pybind11, and you remember it if you wish to make your code available, to a wider audience struggling with C++.

Continue reading:

Share This