Skip to content

A simple example of how to bind C++ code in Python

License

Notifications You must be signed in to change notification settings

volpatto/simple_pybind_example

Repository files navigation

Simple pybind example

Platform Build status
Ubuntu 18.04 LTS and Windows 2019 Build Status

TL;DR

Here, a simple example about how to bind C++ code in Python is provided. The structure tries to be not invasive as much as possible concerning the C++ extension.

Now a longer description

My idea is to provide a structure to bind a C++ extension code to a Python base code. The C++ library (here, the extension we want to bind) can be anything that compiles standalone with its own CMakeLists (I use CMake here, so deal with it), and is exposed as a library that can be linked by others CMakeListss. The structural design aims to plug this extension in the Python base code by providing a binding interface using pybind11. Pursuing a generic purpose, I separate the binding module from the C++ extension code. Why? Well, my big and bold target here is to be not invasive while binding, so the binding duty is out of the C++ target library. Let's dive in to understand it better.

The basic tree structure of the package directory is shown below:

├── CMakeLists.txt
├── LICENSE
├── python_package
│   ├── bindings
│   │   ├── bindings.cpp
│   │   └── CMakeLists.txt
│   ├── cpp_binding
│   │   └── example_binding.cpython-37m-x86_64-linux-gnu.so
│   ├── _cpp_package
│   │   ├── CMakeLists.txt
│   │   ├── example_cpp.cpp
│   │   └── example_cpp.hpp
│   ├── foo_module.py
│   └── __init__.py
├── README.md
├── setup.cfg
├── setup.py
└── tests
    └── test_foo.py

A generic python package named (guess what?! wait for it) python_package is our Python module. Inside it, all the Python lib stuff is located. Here, just for simplifying things, we consider that there is only one Python module (foo_module.py). Now, beside Python modules, I inserted the C++ extension. Just as a note, it could be placed out of python_package dir, say, external or lib dirs, for example. Since it's only an extension, not a huge C++ lib actually, I do prefer to put it beside Python modules (personal tastes, you know). The C++ extension is in _cpp_package dir. The binding interface is placed in binding dir, with a proper binding.cpp file which does all the witchcraft with pybing11. An important point here is to take a look in the CMakeLists.txt (actually all the CMakeLists.txt worth it, do not underestimate CMake's evil power) to get a glance of how to use pybind on a target link library.

After all the compilation and linking processes, a shared library will be generated in cpp_binding dir. It can be imported from a python script from this point. But how we could pack it in a Python package? Well, the setup.py will do the trick for you. You could install it with:

python setup.py develop

or

python setup.py install

or even with the beloved pip:

pip install -e ./

Everything above will install the Python package with the C++ extension for you (in a development mode, btw, but working). The setup.py is heavily based on the official pybind11 cmake example and in this helpful post here. To be honest, I must say that these two sources inspired me also in several others features I aimed to reach here. So kudos to the authors!

Tests

With everything working properly, here come the goodies: Testing C++ codes with Python with the delightful pytest.

"- Oh! Do you mean that there is no Boost.Test or Catch2?! Wtf, man?! They are great!"

Yeah, I agree. But Python can make things faster (polemical pause, awkward silence). Watch out, I didn't say what will get faster! In my humble and pretty insignificant opinion, testing things with pytest is easier than testing in C++. It could turn the testing creation stage quickier (of course, if you have good and well designed bindings available).

Examples of tests are provided in tests dir. The tests are performed using pytest, but could be any other Python test lib.

If you want to see tests working, I defined an alias for it in setup.cfg file, just run the below command in your terminal:

python setup.py test

Requirements

I create isolated environments with conda. You can use and create an environment with all the requirement just doing the following in the repo root:

conda env create -f environment.yml

This will create an environment named cpp-bindings. Activate it and you will got all that you need.

"- Oh! I don't use conda! I even don't know how to use it. Wait, I even don't know what is conda! What could I do?"

Well, no problem. Be sure that you have the following things properly installed in your system (or anything you prefer rather than conda envs):

  • clangdev >=6.0 (I use clang compiler here, but things should work OK with g++ as well)
  • cmake
  • make
  • pybind11 (this one is the most important! you have to be able to find it with CMake's find_package command)
  • pytest (to run the tests)
  • pytest-runner
  • python >=3.6.7 (Python greater than 3.7 would be nice!)

You could use Python virtualenvs as well, I think it wouldn't be a problem (but I won't do it, if you do you tell me).

Contributing

"- Oh! I think you did a terrible work here. This repo is a piece of LOVE!" (edited due to educational reasons)

Thank you! You are very nice! I think you are also a great programmer, probably far better than me (I try my best, I swear). If you have any suggestion, correction, improvements or anything that could increase the quality of the content of the present repo, please feel free to open an issue or, even better, send a PR. I will really appreciate that!

Usage

"- Oh! I think this repo is a good starting point for a project I have in mind! Can I use it?!"

Don't say more. Free software, MIT license. If it help you in any way, I will be very happy! At least I helped someone! This way I am contributing to a better world.

Contact

My name is Diego Volpatto, feel free to contact me through the email [email protected]. However, there is no guarantee that I can help you.

About

A simple example of how to bind C++ code in Python

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published