The functionality and use of pybind11 is very similar to Boost.Python, the bonus being that pybind11 is a more lightweight dependency – although we will require C++11 support from the compiler. The interface definition in account.hpp is rather similar to that in the previous recipe:
#include <pybind11/pybind11.h>
// ...
namespace py = pybind11;
PYBIND11_MODULE(account, m) {
py::class_<Account>(m, "Account")
.def(py::init())
.def("deposit", &Account::deposit)
.def("withdraw", &Account::withdraw)
.def("get_balance", &Account::get_balance);
}
Again, we can clearly recognize how Python methods are mapped to C++ functions. The library that interprets PYBIND11_MODULE is defined in the imported target pybind11::module, which we have included using the following:
add_subdirectory(
${pybind11_sources_SOURCE_DIR}
${pybind11_sources_BINARY_DIR}
)
There are two differences with respect to the previous recipe:
- We do not require pybind11 to be installed on the system and therefore do not try to locate it.
- The ${pybind11_sources_SOURCE_DIR} subdirectory, which contains pybind11 CMakeLists.txt, does not exist when we start building our project.
One solution for this challenge is to use the FetchContent module, which fetches the pybind11 sources and CMake infrastructure at configure time so that we can reference it using add_subdirectory. Using the FetchContent pattern, we can now assume that pybind11 is available within the build tree, which allows us to build and link the Python module:
add_library(account
MODULE
account.cpp
)
target_link_libraries(account
PUBLIC
pybind11::module
)
We use the following command to make sure that the Python module library gets a well-defined prefix and suffix, compatible with the Python environment:
set_target_properties(account
PROPERTIES
PREFIX ${PYTHON_MODULE_PREFIX}
SUFFIX ${PYTHON_MODULE_EXTENSION}
)
The rest of the top-level CMakeLists.txt file is testing (we use the same test.py as in the previous recipe).