使用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是个面向过程的、静态类型的、不带垃圾收集的程序设计语言。因此,直接使用这套 C API非常痛苦。
Boost.Python用面向对象 +模板的方法将这套 C API重新包装了一下,我们用起来就清爽多了。不过,目前这个包装还不完善,因此可能还是需要直接使用一部分 Python C API。等它长大了我再来介绍它。

1.1  Boost.Python的特性

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


1.2  跟其它工具的比较

目前有多个工具可以实现跟 Boost.Python类似的功能,如 SWIGSIP等。但是它们有很大的不同。SWIG和 SIP都定义了一种接口描述语言。我需要先写一个接口描述文件,用于描述我要导出的 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


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

2.1. 从最小的C函数开始

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

  1. #include <boost/python.hpp>
  2. #include <boost/python/module.hpp>
  3. #include <boost/python/def.hpp>
  4. #include <boost/python/to_python_converter.hpp>
  5.  
  6. void dummyFunc(){
  7. cout << "Dummy function called!" << endl;
  8. }

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

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

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

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

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

  1. class Complex{
  2.  
  3. public:
  4. double real;
  5. double imag;
  6. Complex(double rp,double ip);
  7. double GetArg()const;
  8. };
  9.  
  10. 使用以下胶水代码来包装:
  11.  
  12. class_<Complex>("Complex", init<double,double>())
  13. .def_readwrite("real", &Complex::real)
  14. .def_readwrite("imag", &Complex::imag)
  15. .def("GetArg", &Complex::GetArg)

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

一个完整的例子:

  1. #include<cmath>
  2. #include<boost/python.hpp>//包含 Boost.Python的头文件
  3. class Complex { //复数类
  4. public:
  5. double real; //表示实部的成员
  6. double imag; //表示虚部的成员
  7.  
  8. //构造函数,以及初始化列表
  9. Complex(double rp,double ip):
  10. real(rp), //初始化实部
  11. imag(ip) { //初始化虚部
  12. }
  13.  
  14. //获取复数的幅角
  15. double GetArg()const{
  16. return atan2(imag, real);
  17. }
  18. };

  1. usingnamespace boost::python; // 引入命名空间
  2.  
  3. BOOST_PYTHON_MODULE(CSLIC) {//胶水代码入口,导出一个名为“CSLIC”的模块
  4. //构造一个类型为 "boost::python::class_<Complex>"的对象 pyComplex
  5. //构造参数为字符串 "Complex"
  6. //表示要将 C++类 Complex导出到 Python中去,名字也叫 "Complex"
  7. class_<Complex> pyComplex("Complex", no_init);
  8. //导出它的构造方法,声明它的构造方法有两个 double类型的参数
  9. pyComplex.def(init<double,double>());
  10. //导出它的公有成员 real,
  11. //该成员在 Complex类中的位置是 &Complex::real
  12. //导出到 Python中之后的名字也是 "real"
  13. pyComplex.def_readwrite("real", &Complex::real);
  14. //导出它的公有成员 imag,
  15. //该成员在 Complex类中的位置是 &Complex::imag
  16. //导出到 Python中之后的名字也是 "imag"
  17. pyComplex.def_readwrite("imag", &Complex::imag);
  18. //导出它的成员方法 GetArg
  19. //该方法在 Complex类中的入口是 &Complex::GetArg
  20. //导出到 Python中之后的名字也是 "GetArg"
  21. pyComplex.def("GetArg", &Complex::GetArg);
  22. }

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

我遇到的问题:

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

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

  1. 下边的是一个成员函数重载的例子(其实和Free funciton的唯一差别就是声明导出的时候,要在class_<T>对象的那个.后边加def,而一般函数只要直接Def即可):
  1.  
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //Overloadding
  3. struct X{
  4. bool f(int a){
  5. return true;
  6. }
  7.  
  8. bool f(int a, double b) {
  9. return true;
  10. }
  11.  
  12. bool f(int a, double b, char c){
  13. return true;
  14. }
  15.  
  16. int f(int a, int b, int c){
  17. return a + b + c;
  18. };
  19. };

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

  1.  
  1. //helpers
  2. bool (X::*fx1)(int) = &X::f;
  3. bool (X::*fx2)(int, double) = &X::f;
  4. bool (X::*fx3)(int, double, char)= &X::f;
  5. int (X::*fx4)(int, int, int) = &X::f;
  6. class_<X>("X")
  7. .def("f", fx1)
  8. .def("f", fx2)
  9. .def("f", fx3)
  10. .def("f", fx4)

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

打开dll文件,发现:

错误: 由于在隐性依赖模块中丢失导出函数,至少有一个模块有不能解析的导入。

错误: 发现不同 CPU 类型的模块。

警告: 至少有一个延时加载模块没找到。

警告: 由于在延时加载依赖模块中丢失导入函数,至少有一个模块具有不能解析的导入。

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

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

使用boost.python进行混合开发的更多相关文章

  1. [转]boost::python开发环境搭建

    转自:http://www.cnblogs.com/gaoxing/p/4317051.html 本来想用mingw编译boost::python模块,网上看了下资料太少,只有使用vs2012 操作环 ...

  2. boost::python开发环境搭建

    本来想用mingw编译boost::python模块,网上看了下资料太少,只有使用vs2012 操作环境:win7 x64 python: x86 boost: 1.57 编译boost::pytho ...

  3. 使用Boost.Python构建混合系统(译)

    目录 Building Hybrid Systems with Boost.Python 摘要(Abstract) 介绍(Introduction) 设计目标 (Boost.Python Design ...

  4. boost.python笔记

    boost.python笔记 标签: boost.python,python, C++ 简介 Boost.python是什么? 它是boost库的一部分,随boost一起安装,用来实现C++和Pyth ...

  5. 64位win7下安装Boost 1.59.0 + boost.python 1.59.0 + gccxml + pygccxml + pyplusplus(py++)

    由于安装过程中实在是出现了N多问题,所以不得不专门写个帖子来记录一下这破东西在Win7下的安装过程,避免以后还要再用的时候踩坑. 1.Boost简介 Boost库是一个可移植.提供源代码的C++库,作 ...

  6. Python运维开发基础10-函数基础【转】

    一,函数的非固定参数 1.1 默认参数 在定义形参的时候,提前给形参赋一个固定的值. #代码演示: def test(x,y=2): #形参里有一个默认参数 print (x) print (y) t ...

  7. boost.python入门教程 ----python 嵌入c++

    Python语言简介 Python是一种脚本语言.以开放的开发接口和独特的语法著称.尽管Python在国内引起注意只有几年的时间,但实际上Python出现于上世纪90年代(据www.python.or ...

  8. 【转】Boost.Python

    http://edyfox.codecarver.org/html/boost_python.html Boost.Python 是 Boost 中的一个组件,使用它能够大大简化用 C++ 为 Pyt ...

  9. 在 Windows 上使用 Python 进行 web 开发

    本文由葡萄城技术团队于原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 上一篇我们介绍了在Windows 10下进行初学者入门开发Python的指 ...

随机推荐

  1. log日志模块得作用

    import logginglogger=logging.getLogger()logger.setLevel(logging.DEBUG)#控制台输出日志'''consle=logging.Stre ...

  2. Jmeter的参数签名测试

    简介 参数签名可以保证开发的者的信息被冒用后,信息不会被泄露和受损.原因在于接入者和提供者都会对每一次的接口访问进行签名和验证. 签名sign的方式是目前比较常用的方式. 第1步:接入者把需求访问的接 ...

  3. 【剑指Offer】56、删除链表中重复的结点

      题目描述:   在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4-> ...

  4. NFS实时备份

    方法一(inotify+rsync): 1.安装inotify-tools(客户端)[监听工具],实现数据属实备份检查目录是否有如下文档,没有表示操作系统不支持 ls -l /proc/sys/fs/ ...

  5. touch:命令创建文件

    touch:创建空文件或改变文件的时间戳属性 [功能说明] touch命令有两个功能:一是创建新的空文件:二是改变已有文件的时间戳属性 [语法格式] touch [option] [file] tou ...

  6. Spring boot 前后台分离项目 怎么处理spring security 抛出的异常

    最近在开发一个项目 前后台分离的 使用 spring boot + spring security + jwt 实现用户登录权限控制等操作.但是 在用户登录的时候,怎么处理spring  securi ...

  7. CCNP路由实验之十四 路由器的訪问控制ACL

     年9月1月12:00.还有一种时间叫做周期时间(periodic),即这个时间是会多次反复的.比方每周一,或者每周一到周五 ,"rotary 2″开启3002以此类推. 变成1,1变成 ...

  8. 基础树形DP小结

    HDU 4044 Geodefense http://blog.csdn.net/zmx354/article/details/25109897 树形DP暂且先告一段落了. HDU 3586 Info ...

  9. 线程同步、死锁和通信——Java多线程(二)

    一.多线程同步 上一篇随笔中,我曾遇到对多线程程序的多次运行结果不一致的情况,这主要是因为没有对这些线程在访问临界资源做必要的控制,而接下来就用线程的同步来解决这个问题. 1.同步代码块 class ...

  10. ioctl方法详解

    设备控制接口(ioctl 函数)回想一下我们在字符设备驱动中介绍的struct file_operations 结构,这里我们将介绍一个新的方法: int (*ioctl) (struct inode ...