使用boost.python进行混合开发

摘要:
使用boost.python进行混合开发原文请参照官网和各方参考,本文有改动!使用Boost.Python库,我可以方便地将C++语言写的程序库用于Python语言,可以用Python更好地完成更多的任务。不过,目前这个包装还不完善,因此可能还是需要直接使用一部分PythonCAPI。而Boost.Python可能是这三者之间对C++支持最好的一个。在这种设计理念下设计出来的Boost.Python比同类工具支持了给完善的C++特性,能够最大程度地保证不修改原C++程序。

使用boost.python进行混合开发

原文请参照官网和各方参考,本文有改动!

参考链接:http://blog.csdn.net/lanbing510/article/details/12197901

引言:

1简介:

Boost.Python Boost的一个组件。而Boost是目前很红火的准C++标准库,它提供了很多组件使得人们可以用C++语言更方便地实现更多的功能。Boost.Python就是Boost众多组件中的一个。但它是个特例,它的目的不是单纯地增强C++语言的功能,而是希望利用C++语言来增强Python语言的能力。使用Boost.Python库,我可以方便地将C++语言写的程序库用于Python语言,可以用Python更好地完成更多的任务。

好吧,我承认,我忘了说很重要的一点。那就是,通过Boost.Python,我们不仅仅可以用C++来扩展Python,我们还可以将Python嵌入C++。其实Python运行环境本身就提供了一套嵌入Python到其它语言的API,不过是C语言写的。有了这套API,我们就完全可以将Python嵌入到C/C++语言程序中去。但是,由于Python本身是一门面向对象的、动态类型的语言,还带垃圾收集,而C是个面向过程的、静态类型的、不带垃圾收集的程序设计语言。因此,直接使用这套CAPI非常痛苦。Boost.Python用面向对象+模板的方法将这套CAPI重新包装了一下,我们用起来就清爽多了。不过,目前这个包装还不完善,因此可能还是需要直接使用一部分PythonCAPI。等它长大了我再来介绍它。

1.1Boost.Python的特性

目前Boost.Python 特性包括:
o支持C++引用和指针
oGlobally Registered Type Coercions
o自动跨模块类型转换
o高效的函数重载
oC++异常到Python异常的转化
o参数默认值
o关键字参数
oC++程序中访问Python语言中的对象
o导出C++迭代器为Python迭代器
o文档字符串


1.2跟其它工具的比较

目前有多个工具可以实现跟Boost.Python类似的功能,如SWIGSIP等。但是它们有很大的不同。SWIGSIP都定义了一种接口描述语言。我需要先写一个接口描述文件,用于描述我要导出的C++函数和类。然后通过一个翻译器,将接口描述文件翻译成C++程序。最后编译连接生成的C++程序来生成扩展库。而Boost.Python用于导出C++函数和类的时候,我需要添加的也是C++的代码,这是Boost.Python的最大特点之一。
SWIG 比较适合用来包装C语言程序,最近也开始增强一些对C++的支持,但是到目前还不支持嵌套类等C++特性。SIP似乎除了用在包装Qt库之外,就没几个人用。而Boost.Python可能是这三者之间对C++支持最好的一个。不过Boost.Python也有缺点,就是它使用了大量模板技巧,因此当要导出的元素比较多时,编译非常慢。不过幸好作为胶水,我并不需要经常修改和重编译,而且如果使用预编译头的话可以进一步提高编译速度。
Boost.Python 的另外一个优点是,它的设计目标就是让C++程序库可以透明地导出到Python中去。即在完全不修改原来C++程序的情况下,导出给Python用。在这种设计理念下设计出来的Boost.Python比同类工具支持了给完善的C++特性,能够最大程度地保证不修改原C++程序。要知道贸然修改别人的程序,往往会带来许多难以察觉的错误。


1.3. 进行环境搭建:Boost1.53 可以直接进行exe安装,省去了编译的麻烦;官网可下载 boost_1_53_0-msvc-10.0-64.exe

使用boost.python进行混合开发第1张


2. 建立一个dll工程,命名为例如CSLIC:进行代码练习

2.1. 从最小的C函数开始

添加包含路径和库路径之后,添加以下包含:

#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/to_python_converter.hpp>

void dummyFunc(){
    cout << "Dummy function called!" << endl;
}

对应的Wrapper为:
BOOST_PYTHON_MODULE(CSLIC) {
def(fun, dummyFunc);
}

这里需要留意的是,对应的MODULE里边的那个名字必须和 命名为例如CSLIC 里边制定的库 名字完全一样,否则python导入对应的模块时候会报错误。

关于第一次环境搭建,我们需要注意的有四点:

1.在编译时,需要让编译器知道Boost.PythonPython的头文件所在目录;
2.在连接时,需要让连接器知道Boost.PythonPython的库文件所在目录;
3.在连接时,让连接器知道我们要生成的是动态连接库,并且注意动态连接库的主文件名要跟模块名一致;
4.在运行Python解释器并装入Baby模块时,需要在当前目录或系统目录下找得到Boost.PythonBaby模块对应的动态连接库;
如果使用不同的操作系统、编译器或者IDE、不同版本的Python运行环境或Boost.Python库,成功运行上面的例子需要的设置可能不同,但我们只要注意保证上面四点,应该不会有什么大问题。

2.2. 构建类和结构体(一个小例子)

 class Complex{

 public:
     double real;
     double imag;
     Complex(double rp,double ip);
    double GetArg()const;
 };


   使用以下胶水代码来包装:

class_<Complex>("Complex", init<double,double>())
   .def_readwrite("real", &Complex::real)
   .def_readwrite("imag", &Complex::imag)
   .def("GetArg", &Complex::GetArg)


胶水代码的意思是,先构造一个临时对象,该对象的类型是init<double, double> (模板类init的一个实例),然后用字符串"Complex"这个临时对象构造另一个临时对象,该对象的类型是class_<Complex> (模板类class_的一个实例)。然后调用第二个临时对象的def_readwrite方法,该方法返回这个对象本身,因此可以接着再调用这个对象的def_readwrite方法和def方法。

一个完整的例子:

 #include<cmath>
 #include<boost/python.hpp>//包含 Boost.Python的头文件
 class Complex   {          //复数类
 public:
      double real;          //表示实部的成员
      double imag;          //表示虚部的成员

     //构造函数,以及初始化列表
     Complex(double rp,double ip):
         real(rp),          //初始化实部
         imag(ip)   {         //初始化虚部
     }
   

    //获取复数的幅角
    double GetArg()const{
          return atan2(imag, real);
      }
 };

usingnamespace boost::python; // 引入命名空间

 BOOST_PYTHON_MODULE(CSLIC) {//胶水代码入口,导出一个名为“CSLIC”的模块
     //构造一个类型为 "boost::python::class_<Complex>"的对象 pyComplex
    //构造参数为字符串 "Complex"
    //表示要将 C++类 Complex导出到 Python中去,名字也叫 "Complex"
     class_<Complex> pyComplex("Complex", no_init);
      //导出它的构造方法,声明它的构造方法有两个 double类型的参数
     pyComplex.def(init<double,double>());
     //导出它的公有成员 real,
     //该成员在 Complex类中的位置是 &Complex::real
     //导出到 Python中之后的名字也是 "real"
    pyComplex.def_readwrite("real", &Complex::real);
    //导出它的公有成员 imag,
     //该成员在 Complex类中的位置是 &Complex::imag
     //导出到 Python中之后的名字也是 "imag"
     pyComplex.def_readwrite("imag", &Complex::imag);
     //导出它的成员方法 GetArg
    //该方法在 Complex类中的入口是 &Complex::GetArg
   //导出到 Python中之后的名字也是 "GetArg"
     pyComplex.def("GetArg", &Complex::GetArg);
 }

生成动态连接库ADT.so (Linux)ADT.dll (Windows)。然后我可以执行一段Python脚本来验证一下:


我遇到的问题

(1):对于函数重载:产生模板库不能展开问题 ErrorC2784,ErrorC2780

解决方法:消除重载,函数改名......

下边的是一个成员函数重载的例子(其实和Free funciton的唯一差别就是声明导出的时候,要在class_<T>对象的那个.后边加def,而一般函数只要直接Def即可):
////////////////////////////////////////////////////////////////////////////////
//Overloadding
struct X{ 
    bool f(int a){
        return true;
    } 

    bool f(int a, double b) {
        return true;
    } 

    bool f(int a, double b, char c){
        return true;
    } 

    int f(int a, int b, int c){
        return a + b + c;
    };
};

声明的时候,则要费时一点:

 //helpers
    bool    (X::*fx1)(int)              = &X::f;
    bool    (X::*fx2)(int, double)      = &X::f;
    bool    (X::*fx3)(int, double, char)= &X::f;
    int     (X::*fx4)(int, int, int)    = &X::f;
    class_<X>("X")
        .def("f", fx1)
        .def("f", fx2)
        .def("f", fx3)
        .def("f", fx4)

(2):对于不能正常初始化问题:利用WIndepends查看后,缺少两个com组件;

打开dll文件,发现:

错误: 由于在隐性依赖模块中丢失导出函数,至少有一个模块有不能解析的导入。
错误: 发现不同 CPU 类型的模块。
警告: 至少有一个延时加载模块没找到。
警告: 由于在延时加载依赖模块中丢失导入函数,至少有一个模块具有不能解析的导入。

由于VS对64位os的支持不完善,导致大量使用32位库,造成不兼容;

解决方法: 切换到32位平台

免责声明:文章转载自《使用boost.python进行混合开发》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇flink 如何实现对watermark 的checkpoint,防止数据复写cpu IP核下载列表 (最新全集)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

用Python获取计算机网卡信息

目录 0. 前言 1. 测试环境及关键代码解释 1.1 测试环境 1.1.1 系统: 1.1.2 开发工具: 2. 模块介绍及演示 2.1 platform模块使用示例 2.2 netifaces模块使用示例 2.2.1 Linux环境下如何获取网卡口的信息 2.2.2 Windows环境下如何获取网卡口的信息 3. 完整代码 4...

Linux下安装Python3.xx个人解析

一、环境准备 提示:在系统的任何目录下都可以进行如下环境配置操作。 1、 yum install openssl -y yum install openssl-devel -y   这两个文件的安装是为了配置pip3,没有这步操作,后续pip3可能出现错误:ImportError: cannot import name 'HTTPSHandler'  ...

Python3基础 list for+continue 输出1-50之间的偶数

         Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda : 4.5.11    typesetting : Markdown   code """ @Author : 行初心 @Date : 18...

python 绘图---2D、3D散点图、折线图、曲面图

python中绘制2D曲线图需要使用到Matplotlib,Matplotlib 是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形,通过 Matplotlib,开发者可以仅需要几行代码,便可以生成绘图,直方图,功率谱,条形图,错误图,散点图等。 1. 绘制折线图 plt.plot() 可以用于绘制折线图。...

guxh的python笔记三:装饰器

1,函数作用域 这种情况可以顺利执行: total = 0 def run(): print(total) 这种情况会报错: total = 0 def run(): print(total) total = 1 这种情况也会报错: total = 0 def run(): total += 1...

超哥笔记--linux准备知识(1)

一 岗位 前端小姐姐 python后端大神 测试工程师 测试+python 测试开发 运维工程师(背锅侠) -安全运维 -linux系统管理员 -桌面运维(helpdesk) -IDC机房运维(服务器上下架) -devops 运维开发 , python开发技能+ linux命令技能 -cmdb资产管理平台(django+saltstack+linux 服...