惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
T
Troy Hunt's Blog
Cloudbric
Cloudbric
Security Archives - TechRepublic
Security Archives - TechRepublic
WordPress大学
WordPress大学
Recent Commits to openclaw:main
Recent Commits to openclaw:main
W
WeLiveSecurity
GbyAI
GbyAI
V2EX - 技术
V2EX - 技术
Latest news
Latest news
Engineering at Meta
Engineering at Meta
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
PCI Perspectives
PCI Perspectives
Hacker News - Newest:
Hacker News - Newest: "LLM"
博客园 - 叶小钗
I
InfoQ
Y
Y Combinator Blog
罗磊的独立博客
大猫的无限游戏
大猫的无限游戏
The Register - Security
The Register - Security
U
Unit 42
F
Full Disclosure
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
D
DataBreaches.Net
博客园 - 聂微东
Recorded Future
Recorded Future
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
S
Secure Thoughts
博客园 - Franky
M
MIT News - Artificial intelligence
爱范儿
爱范儿
N
Netflix TechBlog - Medium
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
S
SegmentFault 最新的问题
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Threat Research - Cisco Blogs
腾讯CDC
S
Securelist
P
Proofpoint News Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
AI
AI
Simon Willison's Weblog
Simon Willison's Weblog
Google Online Security Blog
Google Online Security Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Cybersecurity and Infrastructure Security Agency CISA
Recent Announcements
Recent Announcements
H
Hackread – Cybersecurity News, Data Breaches, AI and More

博客园 - wildkid1024

RLHF模型训练-PPO拆解 [SentencePiece]Tokenizer的原理与实现 [cuda][caffe]统一内存管理 [LLM] LLM后量化(PTQ)总结及原理实现 [TRT-LLM] TRT-LLM部署流程 生产者消费者模式下实现多batch延时推理 LLM采样后处理总结:LLM的后处理的cpp实现 ControlNet-trt优化总结4:onnx图修改与重建 ControlNet-trt优化总结3:使用multi-stream和cuda-graph构建并行流水线 ControlNet-trt优化总结2:使用TRT-API从零构建ControlNet网络 [vllm]kernels分析 [vllm]vllm架构分析 [trt-hackthon2023]ControlNet-trt优化总结 [fastllm]多线程下动态组batch实现解析 [fastllm]cuda-kernels源码解析 [cuda]RMSNorm核函数解析 fastllm源码解析 Inferllm源码解析 [LLM]常见大模型下载地址
[pybind11]为c++项目写python API接口
wildkid1024 · 2023-06-18 · via 博客园 - wildkid1024

C++项目的pybind方法有哪些?有什么区别?

以下是主要的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

其中

  1. ctypes: C 与 Python 绑定, Python 内建模块,通过调用.so动态链接库来使用方法,不需要在c++中有特殊的写法,如果使用c++则需要使用extern c的方式再包装一层
  2. Boost.Python: C++ 与 Python 绑定, Boost 模块
  3. pybind11: C++11 与 Python 绑定, 减去了旧 C++ 支持,更轻量化,需要在编写cpp时处理响应的绑定函数。
  4. CPython python标准库中的方式,需要手写绑定方法

一般使用pybind11多一些,因为更为轻量化,能够轻易地加入c++特性。

怎么使用pybind11为python添加c++扩展?

安装pybind11

注意事项

首先在安装时,应确保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 安装

如果是熟悉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库的方式安装比较简单,更适合熟悉python的同学。

  1. 使用 pip 安装 PyBind11:pip install pybind11 或 py -m pip install pybind11。
  2. 在cpp项目目录下,运行 python -m pybind11 --includes 或 py -m pybind11 --includes导入pybind11的库

通过pybind11编写绑定扩展

通过以上安装步骤,已经在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],
)

问题排查

1. dynamic module does not define module export function

  1. 检查包名是否一致,即cmake中bind的名称是否和cpp绑定代码中的名称一致。
  2. 检查cc版本是否python编译版本一致
  3. 检查python项目是否包含了编译好的lib路径

相似问题:

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

2. Some automatic conversions are optional and require extra headers to be included when compiling your pybind11 module.

  1. 检查是否导入#include <pybind11/functional.h>

文献引用

  1. https://learn.microsoft.com/zh-cn/visualstudio/python/working-with-c-cpp-python-in-visual-studio?view=vs-2022
  2. https://pybind11.readthedocs.io/en/stable/index.html