====== pybind11を使ってみる ====== 作成日: 2023-08-10 (木) [[https://youtu.be/PXEZhuwq0xA|第6回 pybind11を使ってみる]] プロジェクトレイアウト . └── pybind11-examples/ ├── simple/ │ ├── simple.cpp │ └── Makefile └── fakegfx/ ├── fakegfx.cpp ├── sample.py └── Makefile ===== simple ===== ==== simple.cpp ==== #define _hypot hypot // work-around for Python 3.6 and Mingw-w64 11.0.0 #include namespace py = pybind11; #include #include #include namespace s { struct ZeroDivisionError : std::runtime_error { using std::runtime_error::runtime_error; }; void greet(std::string_view who) { std::cout << std::format("Hello, {}!\n", who); } int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { if (b == 0) { throw ZeroDivisionError{"division by zero"}; } return a / b; } } // ns s PYBIND11_MODULE(simple, m) { m.def("greet", &s::greet, "Greet to user with Hello."); m.def("add", &s::add, "Add first and second numbers."); m.def("sub", &s::sub, "Subtract second number from first one."); m.def("mul", &s::mul, "Multiply first and second numbers."); m.def("div", &s::div, "Divide first number by second one."); py::register_exception(m, "ZeroDivisionError", PyExc_ZeroDivisionError); } ==== Makefile ==== MODNAME = simple PYBIND11_INCLUDES = $(shell pybind11-config --includes) CXXFLAGS = -Wall -std=c++20 -fPIC ${PYBIND11_INCLUDES} LDFLAGS = -LC:\Python36\libs LDLIBS = -lpython36 all: ${MODNAME}.pyd ${MODNAME}.pyd: ${MODNAME}.o ${CXX} -shared ${CXXFLAGS} -o $@ $< ${LDFLAGS} ${LDLIBS} ${MODNAME}.o: ${MODNAME}.cpp ${CXX} -c ${CXXFLAGS} -o $@ $< ===== fakegfx ===== ==== fakegfx.cpp ==== #define _hypot hypot // work-around for Python 3.6 and Mingw-w64 11.0.0 #include namespace py = pybind11; #include namespace g { class Shape { public: virtual ~Shape() = default; virtual void draw() const = 0; }; class RectangleShape : public Shape { public: void draw() const override { std::cout << "+---------+\n" << "| |\n" << "| |\n" << "+---------+\n"; } }; void draw_shape(Shape const &shape) { shape.draw(); } // trampolines that redirects virtual call back to Python class PyShape : public Shape { public: using Shape::Shape; void draw() const override { PYBIND11_OVERRIDE_PURE( void, // return type Shape, // parent type draw, // method name ); } }; class PyRectangleShape : public RectangleShape { public: using RectangleShape::RectangleShape; void draw() const override { PYBIND11_OVERRIDE(void, RectangleShape, draw); } }; } // namespace g PYBIND11_MODULE(fakegfx, m) { py::class_(m, "Shape") .def(py::init()) .def("draw", &g::Shape::draw); py::class_(m, "RectangleShape") .def(py::init()) .def("draw", &g::RectangleShape::draw); m.def("draw_shape", &g::draw_shape); } ==== sample.py ==== import fakegfx class CircleShape(fakegfx.Shape): def draw(self): print("o") class XRectangleShape(fakegfx.RectangleShape): def draw(self): print("x x x x x x") print("x x") print("x x") print("x x x x x x") ==== Makefile ==== MODNAME = fakegfx PYBIND11_INCLUDES = $(shell pybind11-config --includes) CXXFLAGS = -Wall -std=c++20 -fPIC ${PYBIND11_INCLUDES} LDFLAGS = -LC:\Python36\libs LDLIBS = -lpython36 all: ${MODNAME}.pyd ${MODNAME}.pyd: ${MODNAME}.o ${CXX} -shared ${CXXFLAGS} -o $@ $< ${LDFLAGS} ${LDLIBS} ${MODNAME}.o: ${MODNAME}.cpp ${CXX} -c ${CXXFLAGS} -o $@ $<