Disclaimer, I have just started using Pybind11 and do not have much experience with C++. I've had success in using Pybind until I've needed to add inheritance. I am able to successfully generate a shared object file (e.g. derived_class.so), but get an error when trying to include it in my python project:
ModuleNotFoundError: No module named 'base_class'
I was trying to follow along with the docs, specifically the portion that talks about partitioning modules across multiple files
Below I've included a stripped down version to orchestrate what I'm working with and attempting to accomplish.
C++ Classes
// base_class.h
class BaseClass {
public:
BaseClass(int id): id(int id) {}
int get_id() { return id; }
private:
int id;
}
// derived_class.h
#include "common/base_class"
class DerivedClass: public BaseClass {
public:
DerivedClass(int id);
}
// derived_class.cpp
#include "derived_class.h"
DerivedClass::DerivedClass(int id): BaseClass(id) {}
C++ Bindings
// base_class_binding.cpp
#include "base_class.h"
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(base_class, m) {
py::class_<BaseClass>(m, "BaseClass")
.def(py::init<int>());
}
// derived_class_binding.cpp
#include "common/base_class.h"
#include "derived_class.h"
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(derived_class, m) {
//attempt to import module as per docs
py::module_::import("base_class");
// use of imported module class as per docs
py::class_<DerivedClass, BaseClass>(m, "DerivedClass")
.def(py::init<int>());
}
Library Generation
g++ -std=c++20 -shared -fpic `python3.12 -m pybind11 --includes` derived_class.cpp derived_class_binding.cpp common/base_class_binding.cpp -o derived_class.so
Python usage
# test.py
from derived_class import DerivedClass # THIS GENERATES EXCEPTION
if __name__ == '__main__':
derivedClass = DerivedClass(1)
print(f'The ID is: {derivedClass.get_id()}')
I'm expecting my library to import, and then utilize the get_id() function of the base class. I've tried various combinations of:
- The alternate approach to import a module (py::object).
- Including the base_class_binding.cpp into derived_class_binding.cpp directly (as opposed to using the module import.
- Defining a new
py::class_<BaseClass>within derived_class_binding.cpp, which works, but defeats the purpose of having modules escapsulated per file. It also means I need to redeclare it for all of the other files that use it.