C++和Python混合编程

来源:互联网 发布:jetbrains java 编辑:程序博客网 时间:2024/05/29 15:46

早就听说过了对于复杂的系统一般会结合多种语言进行开发,最近摸索了下C++和Python混合编程,在此总结一下,做为笔记。

对于C++和python混合编程实际上包含两部分内容:

  • 用C++写python扩展(extending): 即所谓的在python中调用C/C++代码,一般用于对效率要求高核心模块用C/C++编写,通过一些处理后生成动态库如cppmod.so,然在python代码中import cppmod,即可调用C/C++
  • python脚本嵌入到C++程序中(embedding): 即所谓的C++代码调用python,C++ app要嵌入python解析器从而调用python代码

就实现而言,对于这两者都可以直接用Python/C API,具体可以去参考python文档,但都比较麻烦

  • 对于1, 主要的方案有 boost.python 以及swig, 后者不太了解,本篇主要讲利用boost.python,对C/C++处理后生成动态库,python导入后调用C/C++代码
  • 对于2, C/C++代码中嵌入python,也可以用 boost.python,当然直接 Python/C API也可以

一、安装boost(latest version boost1.55.0)

  1. [tanli@p04bc boost_1_55_0]$./bootstrap.sh --with-python=/usr/bin/python2.7 --with-python-root=/usr --with-python-version=2.7
  2. [tanli@p04bc boost_1_55_0]$./b2 variant=debug link=static threading=multi --with-python

这里为节省时间,只编译boost.python库的static-debug-multi版本,默认在当前目录构建,生成的静库文件位于./statge, 构建完成好了看到信息如下:

  1. The Boost C++ Libraries were successfully built!
  2. The following directory should be added to compiler include paths:
  3. /home/tanli/soft/boost_1_55_0
  4. The following directory should be added to linker library paths:
  5. /home/tanli/soft/boost_1_55_0/stage/lib

注意: boost.python 库是和python版本相关的,当安装Boost, 会自动探测Python版本, 如果有多个python版本,还是需要指定的,否则后面出现一些错误。

二、用boost.python库导出C++函数

在cpp文件中增加导出接口代码

  1. #include <iostream>
  2. #include <boost/python.hpp>
  3. using namespace boost::python;
  4. void SayHello()
  5. {
  6. std::cout<<"hello, world!"<<std::endl;
  7. }
  8. void SayBye()
  9. {
  10. std::cout<<"good bye!"<<std::endl;
  11. }
  12. BOOST_PYTHON_MODULE(hello) // generate python module hello
  13. {
  14. def("SayHello", SayHello);
  15. def("SayBye", SayBye);
  16. }

编译成动态库:

  1. [tanli@p04bc boost_1_55_0]$ g++ hello.cpp -shared -fPIC -o hello.so -I ~/soft/boost_1_55_0 -L ~/soft/boost_1_55_0/stage/lib -lboost_python -I /usr/include/python2.7
  2. /usr/bin/ld: /home/tanli/soft/boost_1_55_0/stage/lib/libboost_python.a(registry.o): relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
  3. /home/tanli/soft/boost_1_55_0/stage/lib/libboost_python.a: could not read symbols: Bad value
  4. collect2: ld returned 1 exit status

原来是boost.python静态库有问题,要加编译选项-fPIC, 看来得改编译选项,google了下,可以怎么改 针对boost_1_55_0版本,修改tools/build/v2/tools/gcc.jam,注释掉391行:

  1. #if $(link) = shared

按照上面命令重新编译boost.python库,然后在编译上面程序,这回好了,再打开python导入动态库调用吧

  1. [tanli@p04bc boostpython]$g++ hello.cpp -shared -fPIC -o hello.so -I ~/soft/boost_1_55_0 -L ~/soft/boost_1_55_0/stage/lib -lboost_python -I /usr/include/python2.7
  2. [tanli@p04bc boostpython]$python
  3. Python 2.7 (r27:82500, Oct 20 2010, 13:31:35)
  4. [GCC 3.4.5 20051201 (Red Hat 3.4.5-2)] on linux2
  5. Type "help", "copyright", "credits" or "license" for more information.
  6. >>> import hello
  7. >>> hello.SayHello()
  8. hello, world!
  9. >>> hello.SayBye()
  10. good bye!
  11. >>> exit()

三、用boost.python库导出C++类

刚才的例子是导出一个函数给python用,那么对于class呢?

  1. #include <string>
  2. #include <boost/python.hpp>
  3. #include <boost/python/module.hpp>
  4. #include <boost/python/def.hpp>
  5. using namespace std;
  6. class CHello{
  7. public:
  8. string GetString()
  9. {
  10. return "CHello::GetString()";
  11. }
  12. int GetInt()
  13. {
  14. return 100;
  15. }
  16. };
  17. BOOST_PYTHON_MODULE(hello_class)
  18. {
  19. using namespace boost::python;
  20. class_<CHello>("CHello")
  21. .def("GetString",&CHello::GetString)
  22. .def("GetInt",&CHello::GetInt)
  23. ;
  24. }

编译运行:

  1. [tanli@p04bc boostpython]$ g++ helloclass.cpp -shared -fPIC -o hello_class.so -I ~/soft/boost_1_55_0 -L ~/soft/boost_1_55_0/stage/lib -lboost_python -I /usr/include/python2.7
  2. [tanli@p04bc boostpython]$python
  3. Python 2.7 (r27:82500, Oct 20 2010, 13:31:35)
  4. [GCC 3.4.5 20051201 (Red Hat 3.4.5-2)] on linux2
  5. Type "help", "copyright", "credits" or "license" for more information.
  6. >>> import hello_class
  7. >>> a = hello_class.CHello()
  8. >>> a.Get
  9. Traceback (most recent call last):
  10. File "<stdin>", line 1, in <module>
  11. AttributeError: 'CHello' object has no attribute 'Get'
  12. >>> a.GetString()
  13. 'CHello::GetString()'
  14. >>> a.GetInt()
  15. 100
  16. >>> quit()

四、用boost.python库导出构造函数

对于非默认构造函数怎么导出呢:

  1. #include <string>
  2. #include <boost/python.hpp>
  3. using namespace std;
  4. class CHello{
  5. public:
  6. CHello(string msg)
  7. : m_msg(msg)
  8. {
  9. m_id = 0;
  10. }
  11. CHello(int id)
  12. {
  13. m_id = id;
  14. }
  15. string GetString() const
  16. {
  17. return m_msg;
  18. }
  19. string SetString(string msg)
  20. {
  21. m_msg = msg;
  22. }
  23. int GetInt()
  24. {
  25. return m_id;
  26. }
  27. int SetInt(int id)
  28. {
  29. m_id = id;
  30. }
  31. string m_msg;
  32. int m_id;
  33. };
  34. BOOST_PYTHON_MODULE(hello_class)
  35. {
  36. using namespace boost::python;
  37. class_<CHello>("CHello", init<string>())
  38. .def(init<int>())
  39. .def("SetString", &CHello::SetString)
  40. .def("GetString", &CHello::GetString)
  41. .def("GetInt", &CHello::GetInt)
  42. ;
  43. }

测试结果:

  1. [tanli@p04bc boostpython]$g++ helloclass.cpp -shared -fPIC -o hello_class.so -I ~/soft/boost_1_55_0 -L ~/soft/boost_1_55_0/stage/lib -lboost_python -I /usr/include/python2.7
  2. [tanli@p04bc boostpython]$python
  3. Python 2.7 (r27:82500, Oct 20 2010, 13:31:35)
  4. [GCC 3.4.5 20051201 (Red Hat 3.4.5-2)] on linux2
  5. Type "help", "copyright", "credits" or "license" for more information.
  6. >>> import hello_class
  7. >>> a = hello_class.CHello()
  8. Traceback (most recent call last):
  9. File "<stdin>", line 1, in <module>
  10. Boost.Python.ArgumentError: Python argument types in
  11. CHello.__init__(CHello)
  12. did not match C++ signature:
  13. __init__(_object*, int)
  14. __init__(_object*, std::string)
  15. >>> a = hello_class.CHello(1)
  16. >>> a.GetInt()
  17. 1
  18. >>> b = hello_class.CHello("hello world!")
  19. >>> b.GetString()
  20. 'hello world!'

五、总结

总的来说就是在C++里引入导出接口代码,然后生成动态库,python里以导入模块的方式加载动态库,然后调用C++程序,更多复杂的导出, 比如继续,虚函数,还是参考手册吧,这里就不介绍了。

0 0
原创粉丝点击