
























以下是主要的python绑定cpp的方法:
| 方法 | 年份 | 代表用户 |
|---|---|---|
| 适用于 CPython 的 C/C++ 扩展模块 | 1991 | 标准库 |
| PyBind11(推荐用于 C++) | 2015 | |
| Cython(推荐用于 C) | 2007 | gevent、kivy |
| HPy | 2019 | |
| mypyc | 2017 | |
| ctype | 2003 | oscrypto |
| cffi | 2013 | cryptography、pypy |
| SWIG | 1996 | crfsuite |
| Boost.Python | 2002 | |
| cppyy | 2017 |
其中
一般使用pybind11多一些,因为更为轻量化,能够轻易地加入c++特性。
首先在安装时,应确保c++环境和python环境保持一致,具体来讲,就是输入python后
wildkid1024@debian:~$ python3
Python 3.9.2 (default, Feb 28 2021, 17:03:44)
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
会显示python使用的gcc版本号,这里需要和c++项目对应的编译器对应:
wildkid1024@debian:~$ cc --version
cc (Debian 10.2.1-6) 10.2.1 20210110
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
因为笔者使用anaconda的环境,在这里就栽了不少跟头,稍微吐槽以下发现anaconda越来越臃肿和无用。
有两种方式可以安装pybind11,第一种是通过c++的项目引入,一种是通过python库的方式安装
如果是熟悉cpp的编程方式,则是通过submodule的方式进行导入的,具体而言:
git submodule add https://github.com/pybind/pybind11.git third_party/pybind11
cd third_party/pybind11/
git checkout tags/my-version
相应地需要在cmake编译时将pybind11库添加进来,这里需要注意的是pybind11_add_module里的名称需要和编写cpp扩展中的名称保持一直,否则将保持找不到对应的库。
cmake_minimum_required(VERSION 3.1)
project(start-pybind11 VERSION 0.1.0 LANGUAGES C CXX)
set(MY_PYBIND ${MY_CURR}/third_party/pybind11)
add_subdirectory(${MY_PYBIND})
pybind11_add_module(example_pb example_pb.cpp)
如果想在已有 C++ 动态库上扩展 pybind11 绑定,那么 target_link_libraries 链接该动态库就可以了。
target_link_libraries(example_pb PUBLIC example)
使用python库的方式安装比较简单,更适合熟悉python的同学。
通过以上安装步骤,已经在cpp项目中添加了pybind11的库,接下来就是使用pybind11编写cpp到pybind的扩展:
首先导入pybind11的头文件:
#include <pybind11/pybind11.h>
然后在要导入的module底部,添加以下方法绑定:
namespace py = pybind11;
PYBIND11_MODULE(superfastcode2, m) {
m.def("fast_tanh2", &tanh_impl, R"pbdoc(
Compute a hyperbolic tangent of a single argument expressed in radians.
)pbdoc");
#ifdef VERSION_INFO
m.attr("__version__") = VERSION_INFO;
#else
m.attr("__version__") = "dev";
#endif
}
tanh_impl为对应的cpp函数实现的地址,fast_tanh为导入的方法名称,具体来讲,在python中将通过以下方式进行调用:
import superfastcode2
superfastcode2.fast_tanh2(args)
C++类的绑定
PYBIND11_MODULE(tick_pb, m) {
m.doc() = "tick_pb bindings";
py::class_<Tick, std::shared_ptr<Tick>>(m, "Tick")
.def(py::init<std::int64_t, std::int64_t>())
.def(py::init<TickEvent, std::int64_t, std::int64_t,
TickRunCallback, TickRunCallback>())
.def_property_readonly("is_running", &Tick::IsRunning)
.def("start", &Tick::Start)
.def("stop", &Tick::Stop, "wait_life_over"_a = false)
.def("get_time_start", &Tick::GetTimeStart)
.def("set_tick_event", [](Tick &self, const TickEvent &tick_event) {
self.SetTickEvent(tick_event);
})
.def("set_run_beg_callback", [](Tick &self,
const TickRunCallback &run_beg) {
self.SetRunBegCallback(run_beg);
})
.def("set_run_end_callback", [](Tick &self,
const TickRunCallback &run_end) {
self.SetRunEndCallback(run_end);
})
.def("wait_life_over", &Tick::WaitLifeOver,
py::call_guard<py::gil_scoped_release>());
}
py::class_定义了从cpp类到python对象的映射,py::init表示了几种实例化方法,def_property_readonly定义了只读属性对应私有成员变量,def_readwrite定义可读写的公有成员变量,其他按照def,取相应的方法地址即可。
cpp项目build之后,会在build目录下产生name.cpython-python_version-arch-linux-gnu.so的文件,需要将该文件移到python的运行导入库下面,或通过sys.path手动添加。
还可以通过编写setup的方式将cpp项目打包为python库:
from setuptools import setup, Extension
import pybind11
cpp_args = ['-std=c++11', '-stdlib=libc++', '-mmacosx-version-min=10.7']
sfc_module = Extension(
'superfastcode2',
sources=['module.cpp'],
include_dirs=[pybind11.get_include()],
language='c++',
extra_compile_args=cpp_args,
)
setup(
name='superfastcode2',
version='1.0',
description='Python package with superfastcode2 C++ extension (PyBind11)',
ext_modules=[sfc_module],
)
相似问题:
ImportError: dynamic module does not define init function
Symbol not found: __Py_ZeroStruct / _PyInstanceMethod_Type
SystemError: dynamic module not initialized properly
The Python interpreter immediately crashes when importing my module
#include <pybind11/functional.h>此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。