pybind11
使用CMake + Pybind11, 将C++写的算法/类,导出到Python中,类似于一个Python库/包
导入pybind11
- vcpkg
cd到vcpkg根目录下, 下载pybind11库
vcpkg install pybind11:x64-windows --clean-after-build
在CMakeLists.txt内添加如下字段
find_package(Python COMPONENTS Interpreter Development)
find_package(pybind11 CONFIG)
- sub_directory
pybind11是一个header-only库, 所以直接把它当做子项目加载到当前项目中也非常方便
从github下载pybind11到指定路径。
项目结构,如下所示
projects/
pybind11/ <-- 从github上下载的pybind11项目
docs/
include/
tools/
...
setup.py
CMakeLists.txt
mylib.cpp
CMakeLists.txt <-- 项目根目录的CMakeLists.txt
在外侧CMakeLists.txt中添加如下字段
add_subdirectory(pybind11)
创建模板库
不同于C++中常见的可执行文件'executable', 动态库'shared library', 又或是静态库'static library', pybind11的目标在VSCode被标记为模板库'module library'。
在创建模板库时也不应该使用C++中常用的add_library
, add_executable
, 而是pybind11_add_module
.
# CMakeLists.txt
pybind11_add_module(py_ltie
your_libs.cpp)
target_link_libraries(py_ltie PUBLIC my_utils)
target_link_libraries(py_ltie PUBLIC my_algo) # my_utils, my_algo 都是依赖库
target_link_libraries(py_ltie PRIVATE pybind11::lto pybind11::embed pybind11::module pybind11::headers)
执行一次CMake后, 该目标会显示在IDE(VSCode)中,
pybind"语法"
几乎所有语法都是写在PYBIND11_MODULE(name, varible)
宏内。其中name
名字应该与pybind11_add_module
的第一个参数相同,varible
则随意设置一个变量即可。
与上面CMake代码相对应的,
/// your_libs.cpp
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(py_ltie, m) {
/* 更多内容... */
}
your_libs.cpp
建议是一个独立的cpp文件, 它可以通过#include <...>
加载其他库里的类和函数, 而不需要在该文件中重新定义。
下面提到PYBIND11_MODULE
的代码块, 都默认使用了#include <pybind11/pybind11.h>
和namespace py = pybind11;
, 也就不再赘述了
函数
大部分“蜻蜓点水”式介绍pybind11的文章/视频,都会提到。
实际上就是用了pybind官方文档的First steps #Creating bindings for a simple function的内容...
写一个函数, 就完事了。完整的代码示例如下:
/// your_libs.cpp
#include <pybind11/pybind11.h>
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(py_ltie, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function that adds two numbers");
}
在我还不太理解pybind11工作原理的时候,这么点示例完全不够我去举一反三的。我甚至一度以为要在自己的每个cpp下面都加一个PYBIND11_MODULE
...
有一点需要注意:
这里的py_lite ↓ 应该与cmakelist.txt里的'py_lite'保持一致(否则会在import py_lite时提示动态模板没有初始化)
PYBIND11_MODULE(py_ltie, m) { <-- 这里的m
和这个m需要保持一致 --> m.def("add", &add, "A func...");
}
言归正传,普通函数的转换语法为:
PYBIND11_MODULE(py_ltie, m) {
m.def("add", &add, "A function that adds two numbers");
}
第一个参数, "add"
是在该函数在python中的名称;
第二个参数,&add
是输入了该函数的地址
第三个参数,"A func..."
是对该函数的解释说明(在pybind11-stubgen章节生成pyi文件后, IDE中就会显示该函数的解释说明)
类
面向对象是C++内常见的编程思路,所以自定义的类才是最需要提供python接口的... 但网上愿意翻译一下官方文档讲一下它的人愣是没几个...
前提:
我之前写了一个小工具动态库my_utils.dll
,并且该库已经通过target_link_libraries