1. 程式人生 > >Python呼叫C/C++的方法——3(Boost.Python)

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呼叫, 功能比較強大, 不但可以封裝函式還能封裝類, 類成員。

前提
使用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
*/
## 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"])    ## 連結的庫
 ])
#!/usr/bin/env python
# -*- coding: utf-8 -*-
## 自定義的C++編寫的模組
import hello
if __name__ == "__main__":
  ## 簡單的兩個測試
  print hello.greet()
  print hello.add(1,2)
  '''
  hello, world
  3
  '''