• 背景介绍
    pybind11是一个基于C++11标准的模版库. 与Boost.Python类似, pybind11主要着眼于创建C++代码的Python封装, 并为其提供了一套轻量级的解决方案.

  • 安装与代码示例
    ①. 安装C++编译器(各平台略有不同, 支持C++11标准即可)
    ②. 安装cmake工具(官网下载安装即可, 用于组织C++工程)
    ③. 安装Python解释器(官网下载安装即可)
    ④. 安装pybind11库
         终端运行: pip3 install pybind11 
    ⑤. 获取pybind11库相关目录
         解释器内运行:

    import pybind11
    pybind11.get_cmake_dir() # 获取cmake目录
    pybind11.get_include() # 获取include目录

    ⑥. 待封装之C++源码
         本文以一个main.cpp源文件为例, 简要给出一个函数与一个类的封装示例, 代码如下,

    #include <string>
    #include <iostream> #include <pybind11/pybind11.h>
    #include <pybind11/eigen.h> int MyFunc(int i, int j)
    {
    return i + j;
    } class MyClass
    {
    public:
    MyClass(const std::string& msg) : msg_(msg) {} void printMsg()
    {
    std::cout << this->msg_ << std::endl;
    } Eigen::VectorXd add(const Eigen::VectorXd& lhs, const Eigen::VectorXd& rhs)
    {
    Eigen::VectorXd ret = lhs + rhs;
    return ret;
    } std::string msg_;
    }; PYBIND11_MODULE(testlib, m) // 此处设置模块名为testlib
    {
    m.doc() = "This is a test library"; m.def("MyFunc", &MyFunc, "my first function",
    pybind11::arg("i") = 1, pybind11::arg("j") = 2); pybind11::class_<MyClass>(m, "MyClass")
    .def(pybind11::init<const std::string&>())
    .def("printMsg", &MyClass::printMsg)
    .def("add", &MyClass::add, pybind11::arg("lhs"), pybind11::arg("rhs"))
    .def_readwrite("msg_", &MyClass::msg_);
    }

    其中, MyFunc是待导出函数, MyClass是待导出类. 注意, 上例含eigen库(C++)与numpy库(Python)之映射, 无eigen库的小伙伴可以注释相关内容.

  • cmake工程示例
    配合上述main.cpp源文件, CMakeLists.txt文件内容如下,

    cmake_minimum_required(VERSION 3.15)
    
    set(CMAKE_BUILD_TYPE "Release")
    set(CMAKE_CXX_STANDARD 11)
    project(test_lib) set(test_srcs
    main.cpp
    ) set(pybind11_DIR "/opt/homebrew/lib/python3.9/site-packages/pybind11/share/cmake/pybind11") # 此处设置pybind11之cmake目录, 即: pybind11.get_cmake_dir()
    find_package(pybind11 REQUIRED)
    pybind11_add_module(testlib ${test_srcs}) # 此处设置模块名为testlib
    target_include_directories(testlib PUBLIC "/Users/xxhbdk/MyLibs/eigen-3.4.0") # 此处附加包含eigen库目录

    当前工程结构如下,

  • 编译及效果展示
    终端运行如下命令编译Python动态库:

    mkdir build      # 创建编译目录
    cd build
    cmake ..
    make

    运行完成后, 笔者build目录下生成了Python动态库文件"testlib.cpython-39-darwin.so". 随后即可在Python环境中使用之, 测试效果如下,

    可以看到, 接口导出整体符合预期.

  • 注意事项
    ①. C++源文件中模块名需要与cmake工程文件中模块名保持一致;
    ②. 本文着重阐述pybind11配合cmake之通用流程, 具体API使用细节, 请大家参考官方文档等资料.

  • 参考文档
    ①. https://pybind11.readthedocs.io/en/stable/②. https://cmake.org/cmake/help/latest/

  • 补充1(C++调用Python)
    ①. 待调用之Python源码
         本文以一个my_func.py源文件为例, 简要给出一个函数示例, 代码如下,
    def MyFunc(i, j):
    return i + j

    ②. 待编译之C++源码
         本文以一个main.cpp源文件为例, 简要给出一个C++调用Python函数之示例, 代码如下,

    #include <iostream>
    #include <pybind11/embed.h> int main()
    {
    pybind11::scoped_interpreter guard; // 初始化python解释器 pybind11::module my_func = pybind11::module::import("my_func");
    int i = 11;
    int j = 22;
    pybind11::object ret = my_func.attr("MyFunc")(i, j);
    int n = ret.cast<int>();
    std::cout << i << " + " << j << " = " << n << std::endl;
    }

    ③. cmake工程示例
         配合上述main.cpp源文件, CMakeLists.txt文件内容如下,

    cmake_minimum_required(VERSION 3.15)
    
    set(CMAKE_BUILD_TYPE "Release")
    set(CMAKE_CXX_STANDARD 11)
    project(test_cppInvokePy) set(test_srcs
    main.cpp
    ) add_executable(main ${test_srcs})
    set(pybind11_DIR "/opt/homebrew/lib/python3.9/site-packages/pybind11/share/cmake/pybind11") # 此处设置pybind11之cmake目录, 即: pybind11.get_cmake_dir()
    find_package(pybind11 REQUIRED)
    target_link_libraries(main PUBLIC pybind11::embed)

    ④. 编译及效果展示
         当前工程结构如下,

    终端运行如下命令编译C++可执行文件,

    mkdir build      # 创建编译目录
    cd build
    cmake ..
    make

    运行完成后, 笔者build目录下生成了可执行文件"main". 随后将Python文件my_func.py拷贝至此build目录下.终端运行可执行文件main, 测试效果如下,

    可以看到, 执行结果符合预期, Python模块调用成功.

  • 补充1 - 参考文档
    ①. https://www.yuque.com/u461675/pcadi1/hf4fha#e82c4d4d
  • 补充2(Global Interpreter Lock)
    当执行流从Python侧进入C++侧时, GIL总是持有的. 因此, 如果C++侧代码长时间运行, 且不释放GIL, 则Python侧多线程可能无法达到预期的运行效果(如: UI运行阻塞等).
    因此, 通过Python调用C++时, 若C++侧代码执行时间较长且具备Python侧多线程需求, 建议在C++代码入口处释放GIL.
    释放GIL之方法①(功能代码执行处): pybind11::gil_scoped_release release; 
    释放GIL之方法②(模块接口定义处): pybind11::call_guard<pybind11::gil_scoped_release>();
  • 补充2 - 注意事项
    ①. C++侧多线程不受GIL影响.
  • 补充2 - 参考文档
    ①. https://pybind11.readthedocs.io/en/stable/advanced/misc.html#global-interpreter-lock-gil

Python扩展(pybind11混编)的更多相关文章

  1. python 与 matlab 混编

    用于 Python 的 MATLAB 引擎 API 快速入门 安装用于 Python 的 MATLAB 引擎 API Matlab的官方文档中介绍了 Matlab 与其余编程语言之间的引擎接口,其中包 ...

  2. python和C语言混编的几种方式

    Python这些年风头一直很盛,占据了很多领域的位置,Web.大数据.人工智能.运维均有它的身影,甚至图形界面做的也很顺,乃至full-stack这个词语刚出来的时候,似乎就是为了描述它. Pytho ...

  3. Python+C混编

    Python最慢!C最快!Python+C混编?结果可想而知! 樱桃种子 百家号04-1712:11 共享库 使用C语言编译产生共享库,然后python使用ctype库里的cdll来打开共享库. 举例 ...

  4. Python和C|C++的混编(二):利用Cython进行混编

    还能够使用Cython来实现混编 1 下载Cython.用python setup.py install进行安装 2 一个实例 ① 创建helloworld文件夹 创建helloworld.pyx,内 ...

  5. python扩展实现方法--python与c混和编程 转自:http://www.cnblogs.com/btchenguang/archive/2012/09/04/2670849.html

    前言 需要扩展Python语言的理由: 创建Python扩展的步骤 1. 创建应用程序代码 2. 利用样板来包装代码 a. 包含python的头文件 b. 为每个模块的每一个函数增加一个型如PyObj ...

  6. python扩展实现方法--python与c混和编程

    前言 需要扩展Python语言的理由: 创建Python扩展的步骤 1. 创建应用程序代码 2. 利用样板来包装代码 a. 包含python的头文件 b. 为每个模块的每一个函数增加一个型如PyObj ...

  7. swift objective-及c语言 混编

    在xocde6出来我们大部分代码都是用objective-c写的(部分C/C++),现在出生来了一个新的语言叫swift,那么如何既能使用我们之前的代码,还可以使用新语言呢, 本文就此做一下说明. 关 ...

  8. [ios][swift]swift混编

    http://blog.csdn.net/iflychenyang/article/details/8876542(如何在Objective-C的头文件引用C++的头文件) 1.将.m文件扩展名改为. ...

  9. Xcode中C、C++、Object-C3种语言的混编

    转自: http://hi.baidu.com/onejw/item/f34390c997cdc226a1b50ae http://www.cocoachina.com/ask/questions/s ...

  10. Swift & OC 混编 浅析

    转载自:http://www.infoq.com/cn/articles/wangyi-cartoon-swift-mixed-practice?utm_campaign=rightbar_v2&am ...

随机推荐

  1. centos7.6安装teamviewer-原来还可以用yum 安装rpm包,自动解决依赖,太爽了

    1.在官网下载teamviewer安装包 2.安装.一直用rpm -ivh 的方式安装rpm包,但是不会自动解决依赖,今天才知道,原来还可以用yum -y install rpm包,自动解决依赖. [ ...

  2. Prufer序列 学习笔记

    \(Prufer\) 序列 \(\texttt{definition}\) \(Prufer\) 序列序列可以将一个带标号 \(n\) 个结点的树用 \([1..n]\) 中的 \(n-2\) 个整数 ...

  3. 题解 [SHOI2002] 百事世界杯之旅

    其实做这道题还蛮难受的...因为这个每一次有无限种可能我有钱我可以去买无限瓶可乐啊但是不是可口我不是很赞同┓( ´∀` )┏ 然后参考了这篇题解发现错位相减这样的方法,让我们一起膜拜 Butterfl ...

  4. Python_使用Python将一个文件夹下的多个文件夹中的图片复制到一个文件夹中

    代码: # coding=utf-8 import os import shutil #目标文件夹(最终要复制到的文件夹),此处为相对路径,也可以改为绝对路径 determination = '/.. ...

  5. Cesium渲染模块之VAO

    1. 引言 Cesium是一款三维地球和地图可视化开源JavaScript库,使用WebGL来进行硬件加速图形,使用时不需要任何插件支持,基于Apache2.0许可的开源程序,可以免费用于商业和非商业 ...

  6. 常用的基本Dos命令

    Windows+R: 输入cmd,运行控制台 #盘符切换: 盘名+: #查看当前目录下的所有文件: dir #切换目录: cd+文件名 #返回上一级: cd.. #清理屏幕: cls #退出终端: e ...

  7. 在docker中,运行Jcmd命令,报错

    起因: 想调整JVM的设置,观察一下当前jvm进程的资源情况. 输入:docker exec -it xxxxx /bin/sh 输入: jcmd 1 help ,报错 com.sun.tools.a ...

  8. VMware-安装rpm包出现警告:tigervnc-1.1.0-24.el6.x86_64.

    警告:tigervnc-1.1.0-24.el6.x86_64. 解决方法:rpm -ivh tigervnc-1.1.0-24.el6.x86_64.rpm --force --nodeps --n ...

  9. 腾讯QQ v9.7.3.28946 绿色优化版

    修改历史: 2023.02.13:自改官方 9.7.3.28946 最新正式版本2023.01.15:自改官方 9.7.1.28940 最新正式版本2023.01.07:自改官方 9.7.1.2893 ...

  10. Prowide Core:SWIFT [tm] MT(FIN)消息传递的Java框架 开源

    Prowide Core(以前称为WIFE)是用于管理SWIFT MT消息的开源Java框架. 库的主要功能是针对所有MT消息类型的全面Java模型,以及简单易懂的解析和构建API. 该项目自2006 ...