为了使用C++ 编写python的扩展程序, 需要使用pybind11, pybind11使用比较简单,文档也比较详细。下面本人Windows系统上测试使用pybind11,本篇主要讲述简单样例与原理.平常使用的python实现都是cpython,所以使用C语言或者C++来写一些扩展的时候,就相当于在写cpython的插件。cpython的扩展关键在于要实现一个PyObject* PyInit_modulename
(void)的函数,也叫initialization function,这个函数返回一个PyModuleDef
的instance。
Ubuntu系统
Windows系统
GitHub - pybind/pybind11: Seamless operability between C++11 and Python
下载pybind11或者直接pip install pybind11git clone https://github.com/pybind/pybind11.git
添加一个c++ add算子
//ex.cpp
#include
int add(int i, int j) {
return i + j;
}
PYBIND11_MODULE(ex, m) {
m.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function which adds two numbers");
}
编译为so动态链接库,供pythonimport调用
#该编译命令会生成 ex.cpython-35m-x86_64-linux-gnu.so
g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` ex.cpp -o gemfield`python3-config --extension-suffix`
python测试
>>> import ex
>>> ex.add(1,1)
2
那么看看PYBIND11_MODULE的宏展开之后执行了什么。
可以看到实现了PyObject *PyInit_ex()函数。
static void pybind11_init_ex(pybind11::module &);
extern "C" __attribute__ ((visibility("default"))) PyObject *PyInit_ex() {
{
const char *compiled_ver ="3.8";
const char *runtime_ver = Py_GetVersion();
size_t len = std::strlen(compiled_ver);
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) {
PyErr_Format(PyExc_ImportError, "Python version mismatch: module was compiled for Python %s, " "but the interpreter version is incompatible: %s.", compiled_ver, runtime_ver);
return nullptr;
}
}
auto m = pybind11::module("ex");
try {
pybind11_init_ex(m);
return m.ptr();
} catch (pybind11::error_already_set &e) {
PyErr_SetString(PyExc_ImportError, e.what());
return nullptr;
} catch (const std::exception &e) {
PyErr_SetString(PyExc_ImportError, e.what());
return nullptr;
}
}
void pybind11_init_ex(pybind11::module &m){
m.doc() = "pybind11 example plugin";
m.def("add", &add, "A function which adds two numbers");
}
如何对c++类进行python绑定呢
#include
#include
extern "C" bool initav(const char* url);
class EXClass{
public:
EXClass(const std::string &url) : url(url){initav(url.c_str());}
const std::string &getFrame() const;
private:
std::string url;
};
const std::string& EXClass::getFrame() const
{
std::cout<< url << std::endl;
return url;
}
PYBIND11_MODULE(cxvlass, m) {
pybind11::class_(m, "EXClass")
.def(pybind11::init())
.def("getFrame", &SYSZUXav::getFrame);
}
编译
g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` syszuxav.cpp -o syszuxav`python3-config --extension-suffix`
同样展开宏查看,可以看到还是实现了
可以看到实现了PyObject *PyInit_exclass()函数。
extern "C" bool initav(const char* url);
class EXClass{
public:
EXClass(const std::string &url) : url(url){initav(url.c_str());}
const std::string &getFrame() const;
private:
std::string url;
};
const std::string& EXClass::getFrame() const
{
std::cout<< url << std::endl;
return url;
}
static void pybind11_init_exclass(pybind11::module &);
extern "C" __attribute__ ((visibility("default"))) PyObject *PyInit_exclass()
{
{
const char *compiled_ver = "3.8";
const char *runtime_ver = Py_GetVersion();
size_t len = std::strlen(compiled_ver);
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) {
PyErr_Format(PyExc_ImportError, "Python version mismatch: module was compiled for Python %s, \
but the interpreter version is incompatible: %s.", compiled_ver, runtime_ver);
return nullptr;
}
}
auto m = pybind11::module("exclass");
try {
pybind11_init_exclass(m);
return m.ptr();
} catch (pybind11::error_already_set &e) {
PyErr_SetString(PyExc_ImportError, e.what());
return nullptr;
} catch (const std::exception &e) {
PyErr_SetString(PyExc_ImportError, e.what());
return nullptr;
}
}
void pybind11_init_syszuxav(pybind11::module &m)
{
pybind11::class_(m, "SYSZUXav").def(pybind11::init()).def("getFrame", &SYSZUXav::getFrame);
}
后续将会结合pip setup+opencv详细说明如何构建python package c++