Python和C++的混合編程(使用Boost編寫Python的擴展包)



  想要享受更輕松愉悅的編程,腳本語言是首選。想要更敏捷高效,c++則高山仰止。所以我一直試圖在各種通用或者專用的腳本語言中將c++的優勢融入其中。原來貢獻過一篇《c++和js的混合編程》也是同樣的目的。
  得益於機器學習領域的發展,Python最近一直維持熱度,但Python的速度,比node.js都差距不小,所以使用c++來提高一些速度更有必要。
  編寫Python的擴展模塊已經有不少的不錯的框架,但感覺上boost是最好用的一個。

環境准備

  本文的實驗環境為mac電腦。使用Linux環境通常也可以使用apt或者yum來安裝配置對應的開發環境,請查看其它介紹文檔。
  在mac上准備環境很容易,首先要已經安裝Xcode,並且安裝了Xcode的命令行工具。其次要安裝Homebrew擴展包管理工具。這部分是基礎的開發環境,這里不做額外說明。
  在命令行執行brew install boost-python3,一行命令就可以安裝完成Python模塊的開發環境。(本例中完全使用Python3為例來說明,如果想制作Python2的擴展包,請根據需要修改相應的名稱和版本號)。

簡單示例

  從boost官網抄了一個簡單的示例,包括了初始化、從Python傳遞參數給c++和從c++返回結果給Python的一個基本流程。源代碼非常短,請看下面:

#include <string>
#include <boost/python.hpp>

using namespace std;
using namespace boost::python;
	
struct World{
    void set(string msg) { this->msg = msg; }
    string greet() { return msg; }
    string msg;
};

//特別注意下面的模塊名hello同將來引入Python的模塊名、編譯完成的文件名,三者必須相同 
BOOST_PYTHON_MODULE(hello){
   class_<World>("World")
        .def("greet", &World::greet)
        .def("set", &World::set)
   ;
}

編譯

  假設上面的c++代碼保存為hello.cpp文件。使用如下兩行命令可以完成編譯:

#生成.o臨時編譯文件
g++ -fpic -c hello.cpp $(pkg-config --cflags python3)
#生成.so工作文件
g++ -shared -o hello.so hello.o -lboost_python37 $(pkg-config --cflags --libs python3)

  上面的兩行編譯命令中,有兩個編譯參數可能是需要根據具體版本做調整的,一個是pkg-config庫管理工具中的python3,這個名稱和版本號可以檢查如下路徑的配置文件,根據自己需要選擇對應的庫版本,比如python3對應需要有python3.pc文件:

ls /usr/local/lib/pkgconfig/python*pc

  另外一個是第二行命令中的-lboost_python37,這個檢查已經安裝的庫版本來決定,比如-lboost_python37對應需要有libboost_python37.dylib文件,特別注意這個版本同將來運行的python環境版本必須精確一致,小版本也必須相同:

ls /usr/local/lib/libboost_python*

驗證

  編譯完成會在當前目錄生成hello.so文件,這時候可以直接使用Python的交互模式來驗證擴展模塊的使用:

$ python3
Python 3.7.0 (default, Sep 18 2018, 18:47:22) 
[Clang 9.1.0 (clang-902.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import hello
>>> test=hello.World()
>>> test.set("hello 世界");
>>> test.greet()
'hello 世界'

bjam編譯

  boost官方推薦使用Boost.Build系統bjam來編譯,比Makefile之類的確會略微的方便一點,這里介紹出來供參考。
  安裝bjam:brew install bjam
  在當前目錄建立一個文本文件Jamroot,內容為:

import python ;

using python : 3 ;

lib boost_python37 ;

project demo
  : requirements
    <location>.
    <library>boost_python37
  ;	
#注意下面的hello,同cpp文件中最后導出的模塊名必須相同
python-extension hello
	: hello.cpp
	: <cxxflags>"`pkg-config --cflags python3`"
	: <linkflags>"`pkg-config --libs python3`"
	;

  在命令行執行bjam命令,會自動編譯生成hello.o及hello.dylib文件,.o文件為臨時文件可以刪除,.dylib文件改名為.so文件就是我們需要的Python擴展庫,使用起來是完全相同的。

參考資料

  https://www.boost.org/doc/libs/1_60_0/libs/python/doc/html/tutorial/index.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM