I am wrapping some c++ library code to create a pybind11 module. I adopt the approach described here:
https://github.com/pybind/cmake_example
After building the library, it will be imported in Python using something like:
import cmake_example as m
In order to be used, the library needs to be initialized. During initialization, the code reads some environment variables, sets some internal variables, and prints some stuff, etcetera. Also, there is finalization.
How to ensure that initialization and finalization code is always run? One approach would be to do something like
import cmake_example as m
m.init()
#use module
m.finalize()
However, to make the library easier to use, I would consider handle this on the c++ side: By adding stuff to the c++ code to ensure that init and cleanup are called automatically respectively when the module is imported and when the python script/session ends.
I could imagine that this could be accomplished by adding a static variable of custom type, and to call the initialization code when the custom type is initialized, and the cleanup code when it finalizes. Something like:
#include <pybind11/pybind11.h>
#include <iostream>
class Module
{
public:
Module()
{
std::cout << "initializing";
//code initialization
}
~Module()
{
std::cout << "finalizing";
//finalize
}
};
static Module module;
namespace py = pybind11;
PYBIND11_MODULE(pybind_example, m) {
//Create all the bindings.
}
This seems to work when I test it for my current setup (windows, python 2.9)? Will it suddenly break for other configurations? Are there alternatives that are recommended over this?
Your approach works, but it's pretty brittle and you might run into the "static initialization order fiasco"
A more robust way would be to initialize a static variable inside the pybind scope:
PYBIND11_MODULE(pybind_example, m) {
static Module module;
// Create bindings
}