目录
Pybind11
Pybind11 是一个轻量级的 C++ 库,用于将你的 C++ 代码暴露给 Python 调用(反之也可,但主要还是前者)。Pybind11 借鉴了 Boost::Python
库的设计,但使用了更为简洁的实现方式,使用了大量 C++11 的新特性,更易于使用。
如何在C++中使用Pybind11
1.将Pybind11加入到submodule中
添加子模块非常简单,命令如下:
git submodule add <url> <path>
其中,url为子模块的路径,path为该子模块存储的目录路径。example:
git submodule add https://github.com/pybind/pybind11.git third_party/pybind11
执行上述命令时,会从github上clone到你指定的<path>
处,同时会在仓库生成.gitmodules文件,该文件会记录添加的submodule的url和存放submodule的路径,如下:
2.编写C++程序
本例中,我们实现了一个快排的C++类,类的定义如下:
#include <common.h>
class SortFactory
{
public:
void setData(std::vector<int> &raw_data)
{
data_ = raw_data;
}
std::vector<int> &getData()
{
return data_;
}
void printData(std::vector<int> &sorted_data)
{
for (auto item : sorted_data)
{
std::cout << item << " ";
}
std::cout << std::endl;
}
virtual void sort(){};
private:
std::vector<int> data_;
};
class QuickSort : public SortFactory
{
public:
QuickSort() {};
void sort1(std::vector<int> &data);
void mySort(int start, int end, std::vector<int> &data);
};
类的实现如下:
#include <sort/sort.h>
//{3,2,4,5,7,8,0}
//{0,2,4,5,7,8,3}
void QuickSort::mySort(int start, int end, std::vector<int> &data)
{
int tmp_start = start;
int tmp_end = end;
if (start >= end)
return;
int tmp = data[end];
while (start < end)
{
while (data[start] <= tmp)
{
start++;
if (start >= end)
break;
}
data[end] = data[start];
while (data[end] >= tmp)
{
if (start >= end)
break;
end--;
}
data[start] = data[end];
}
data[start] = tmp;
mySort(tmp_start, start - 1, data);
mySort(end + 1, tmp_end, data);
}
void QuickSort::sort1(std::vector<int> &data)
{
int size = data.size();
int start = 0;
int end = size - 1;
mySort(start, end, data);
printData(data);
}
其中,QuickSort中的sort函数就是我们需要绑定的函数,目录结构如下:
pythonApi文件夹下,pythonSort是绑定QuickSort类中的sort函数的文件,定义如下:
#include <include/pybind11/pybind11.h>
#include <sort/sort.h>
namespace py = pybind11;
PYBIND11_MODULE(MyQuickSort, m)
{
py::class_<QuickSort>(m, "QuickSort")
.def(py::init())
.def("sort", &QuickSort::sort1);
}
pythonSort对应的CMake文件,定义如下:
include_directories(${PROJECT_SOURCE_DIR}/include)
include_directories(${PROJECT_SOURCE_DIR}/third_party/pybind11)
include_directories(${PROJECT_SOURCE_DIR}/third_party/pybind11/include)
include_directories(/usr/include/python3.8/)
message(${PROJECT_SOURCE_DIR})
add_subdirectory(${PROJECT_SOURCE_DIR}/third_party/pybind11 pybind11_binary_dir)
add_library(MyQuickSort MODULE pythonSort.cpp)
target_link_libraries(MyQuickSort PRIVATE my_sort)
pybind11_extension(MyQuickSort)
pybind11_strip(MyQuickSort)
issue
在编译的时候遇到了一个问题,如下:
pybind11/include/pybind11/detail/../detail/common.h:274:10: fatal error: Python.h: No such file or directory
274 | #include <Python.h>
| ^~~~~~~~~~
compilation terminated.
参考了如下的文章,执行sudo apt install python3.8-dev之后问题并没有解决,所以采用了笨办法,发现Python.h文件在/usr/include/python3.8下,所以直接在cmake文件中添加include_directories(/usr/include/python3.8/),此时问题解决了。
fatal error: Python.h: No such file or directory when compiling pybind11 example - Stack Overflow
Issues with running the first example · Issue #1781 · pybind/pybind11 · GitHub
调用python接口
在python中调用绑定的接口,此时需要export $PYTHONPATH=$PYTHONPATH:~/cmakestudy/build/src/pythonApi
import MyQuickSort
data = [1,3,4,2,90,23,4,5,78]
a = MyQuickSort.QuickSort()
a.sort(data)
此时可能会报一个错误,如下:
Invoked with: <MyQuickSort.QuickSort object at 0x7fb96ae01cb0>, [1, 3, 4, 2, 90, 23, 4, 5, 78]
Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.
此时需要在pythonApi绑定函数中添加引用,如下:
#include <include/pybind11/pybind11.h>
// new add
#include <include/pybind11/stl.h>
#include <sort/sort.h>
namespace py = pybind11;
PYBIND11_MODULE(MyQuickSort, m)
{
py::class_<QuickSort>(m, "QuickSort")
.def(py::init())
.def("sort", &QuickSort::sort1);
}
代码:https://github.com/xiaoycolor/cmakestudy/tree/main/src/pythonApi
参考: