pybind11
The pybind11 library allows you to call C++ code from python. It is a header-only library, and requires that you only add a few lines describing your module and C++ functions to the source to get it to work.
You can install pybind11
via pip
:
pip install pybind11
Since it is a header-only library, the main thing you need in order to
compile source is the location of the headers (so you can specify the
include path via the -I
option). You can find this via:
python -m pybind11 --includes
on my machine, this gives:
-I/usr/include/python3.12 -I/home/zingale/.local/lib/python3.12/site-packages/pybind11/include
When we compile the .cpp
code, we need to make a shared-object library that can be imported
into python as a module. This needs to have a specific name, with the suffix given by
python3-config --extension-suffix
on my machine, this gives:
.cpython-312-x86_64-linux-gnu.so
Simple function example
Here’s a very simple example. We will write a C++ function that computes \(f(x) = \sin(x)\).
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <cmath>
double f(double x) {
return std::sin(x);
}
PYBIND11_MODULE(simple, m) {
m.doc() = "simple example of creating a function f(x) in C++";
m.def("f", &f);
}
We add a PYBIND11_MODULE
macro that defines the entry point
from python—see: https://pybind11.readthedocs.io/en/stable/reference.html#macros
To compile it, we can use this GNUmakefile
:
SOURCES := $(wildcard *.cpp)
OBJECTS := $(SOURCES:.cpp=.o)
BASE := simple
HEADERS := $(wildcard *.H)
PYBIND_INCLUDES := $(shell python -m pybind11 --includes)
PYBIND_SUFFIX := $(shell python3-config --extension-suffix)
PYTHON_LIBRARY := ${BASE}${PYBIND_SUFFIX}
ALL: ${PYTHON_LIBRARY}
CXXFLAGS := -O3 -Wall -Wextra -shared -std=c++17 -fPIC ${PYBIND_INCLUDES}
%.o : %.cpp
g++ ${CXXFLAGS} -c $<
${PYTHON_LIBRARY}: ${OBJECTS} ${HEADERS}
g++ ${CXXFLAGS} -o $@ $<
print-%: ; @echo $* is $($*)
We can use this in python as:
import simple
simple.f(1.0)