====== 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 $@ $<