Python調用C/C++的方法——3(Boost.Python)

之前關於Python調用C/C++介紹了:
1.ctypes方式加載並調用C/C++ 動態鏈接庫的方式;
2.使用C/C++編寫Python擴展模塊的方式。
今天的筆記記錄的是使用Boost.Python的方式。

Boost.Python介紹:
Boost.Python是一個開源C++庫,它提供了一個簡明的IDL式的接口用於綁定C++類和函數到Python。 得益於C++編譯期的內部處理(譯註:原文是introspection)和最近開發的元編程(metaprogramming)技術,成就了Boost.Python不需引入一種新的語法而只用純C++的實現。Boost.Python豐富的特性集合以及它的高階接口使得工程師像混合系統(譯註:hybrid system)那樣做打包的事情成爲可能,並且程序員讓在應用C++高效的編譯期多態性以及Python非常方便的運行期多態性的時候獲得易用性和一致性;
Boost庫是非常強大的庫, 其中的python庫可以用來封裝c++被python調用, 功能比較強大, 不但可以封裝函數還能封裝類, 類成員。

文檔:
https://www.boost.org/doc/libs/1_65_1/libs/python/doc/html/index.html

前提
使用boost python庫需要先進行安裝,可能有些版本的操作系統內是有集成的。(例如我使用的Ubuntu16.04)
安裝: sudo apt install libboost-python-dev

簡單的例子
hello.cpp

#include <boost/python.hpp>
char const* greet()
{
   return "hello, world";
}

int add(int x,int y)
{
    return x+y;
}

BOOST_PYTHON_MODULE(hello)     // 參數hello爲模塊的名字,沒有引號
{
    using namespace boost::python;
    def("greet", greet);    // "greet"是python調的方法名,greet是C++的方法
    def("add",add);
}

編譯:

g++ -c -fPIC -o hello.o hello.cpp -I /usr/include/python2.7/
g++ -shared -Wl,-soname,hello.so -o hello.so  hello.o -L/usr/lib/x86_64-linux-gnu -lpython2.7 -lboost_python
或:
g++ -shared -o hello.so -fPIC hello.cpp -I/usr/include/python2.7/ -lpython2.7 -lboost_python
注意:源代碼hello.cpp的位置一定要在聲明頭文件和鏈接庫的左面(g++自右向左解析)。以下是我趟過的坑:
/*
g++ -fPIC -o hello.so -shared -I/usr/include/python2.7/ -L/usr/lib/x86_64-linux-gnu -lboost_python hello.cpp
編譯正常通過,且生成hello.so但是ldd發現沒有鏈接libboost_python這個庫的任何信息,import 報錯:
'''
ImportError: ./hello.so: undefined symbol: _ZNK5boost6python7objects21py_function_impl_base9max_arityEv 
'''
此問題既由於g++語句順序不當引起,由於gcc/g++語句都由右向左解析,所以如果把源代碼放在鏈接庫的右面則有可能鏈接失敗。
另:
    如果boost_python庫的路徑不在ld默認的庫中,可以通過-L添加,例如我的libboost_python.so位置在/usr/lib/x86_64-linux-gnu/下:可以通過:-L/usr/lib/x86_64-linux-gnu指定,或添加到/etc/ld.so.conf.d/中並執行ldconfig
*/

setup.py

## python 提供了setup、Extension方法實現編譯和模塊創建。
#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension

setup(name="hello.test.python",
 ext_modules=[
  Extension("hello", ["hello.cpp"],    ## hello是模塊名,hello.cpp是源代碼文件
  libraries = ["boost_python"])    ## 鏈接的庫
 ])

測試代碼:test.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
## 自定義的C++編寫的模塊
import hello
if __name__ == "__main__":
  ## 簡單的兩個測試
  print hello.greet()
  print hello.add(1,2)
  '''
  hello, world
  3
  '''
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章