Boost庫是一個可移植、提供源代碼的C++庫,作為標準庫的后備,是C++標準化進程的開發(fā)引擎之一。Boost庫由C++標準委員會庫工作組成員發(fā)起,其中有些內(nèi)容有望成為下一代C++標準庫內(nèi)容。在C++社區(qū)中影響甚大,是不折不扣的“準”標準庫。
Boost由于其對跨平臺的強調(diào),對標準C++的強調(diào),與編寫平臺無關(guān)。大部分boost庫功能的使用只需包括相應(yīng)頭文件即可,少數(shù)(如正則表達式庫,文件系統(tǒng)庫等)需要鏈接庫。但Boost中也有很多是實驗性質(zhì)的東西,在實際的開發(fā)中使用需要謹慎。
Boost庫是為C++語言標準庫提供擴展的一些C++程序庫的總稱。
——百度百科
簡單來說,Boost 是一系列通用的 C++ 擴展庫的集合。而 Boost.python 則是這眾多擴展庫中的其中一個,它基于 C++ 代碼提供了一套 Python 接口,可作為 C++ 與 Python 混合編程的橋梁。
Boost 庫的安裝
方式一:Boost 源碼包
首先去 Boost 官網(wǎng)下載 Boost 庫:下載地址。
官方默認只提供 Boost 的源碼包。大多數(shù)情況下(純 C/C++ 開發(fā)),源碼包就足夠了,我們只需要在編譯的時候引入相應(yīng)的頭文件即可。但如果你的程序需要以靜態(tài)/動態(tài)鏈接庫的形式引入某些包,就需要自己編譯了。恰好 Boost.python 就是這樣的需求,畢竟,你總不能指望直接在 python 代碼中引用 C++ 源碼吧!
我們一般會把 python 代碼之外的所有 C/C++ 外掛編譯成一個 .pyd 文件,這樣就能直接在 python 代碼中調(diào)用了。事實上,.pyd 文件就是一個擁有 python 接口的 .dll 文件。
Boost 源碼包的目錄結(jié)構(gòu)如下:
boost_1_68_0
+---boost
+---doc
+---libs
+---more
+---status
+---tools
+---INSTALL
+---Jamroot
+---LICENSE_1_0.txt
+---boost.css
+---boost.png
+---boost-build.jam
+---boostcpp.jam
+---bootstrap.bat
+---bootstrap.sh
+---index.htm
+---index.html
+---rst.css
其中,boost 目錄下是所有庫的頭文件(.hpp文件),libs 目錄下則是所有庫的具體實現(xiàn)(.cpp文件)。
方式二:Boost 預(yù)編譯包
Boost 源碼包如果要在本地完全編譯,可能需要幾個小時的時間。因此,為了方便使用,Boost 也推出了 Windows 下的 預(yù)編譯版本。預(yù)編譯包比起源碼包多出一個子目錄,用于存放已經(jīng)編譯好的靜態(tài)庫和動態(tài)庫。
安裝預(yù)編譯版本 boost_1_68_0-msvc-14.0-32.exe 之后的目錄結(jié)構(gòu)如下:
boost_1_68_0
+---boost
+---doc
+---libs
+---lib32-msvc-14.0 # new
+---more
+---status
+---tools
+---INSTALL
+---Jamroot
+---LICENSE_1_0.txt
+---b2.exe # new
+---bjam.exe # new
+---boost.css
+---boost.png
+---boost-build.jam
+---boostcpp.jam
+---bootstrap.bat
+---bootstrap.log # new
+---bootstrap.sh
+---index.htm
+---index.html
+---project-config.jam # new
+---rst.css
其中,lib32-msvc-14.0 目錄保存了所有編譯好的靜態(tài)庫和動態(tài)庫。需要注意的是,預(yù)編譯版本對編譯器種類、版本和目標位數(shù)(32/64)都有要求。在上述例子中,要使用這些庫,必須用 msvc-14.0(即 Visual Studio 2015)且設(shè)置目標位數(shù)為 32 位。
不同版本的預(yù)編譯包可以安裝在同一個目錄下,以支持不同的編譯環(huán)境,這樣就比較方便了。比如在上述例子中,如果還要支持 64 位,可以再下載一個 boost_1_68_0-msvc-14.0-64.exe,同樣安裝在當前安裝目錄下。這樣安裝目錄下將多出一個 lib64-msvc-14.0 子目錄,存放編譯好的 64 位的庫,其余目錄和文件均不受影響。
預(yù)編譯版本滿足了偷懶的需求,但很難滿足所有要求,因為有些庫必須配合本地環(huán)境才能使用。比如 Boost.python 就必須配合本地的 Python 版本才能使用,因此本地編譯 Boost 庫這個基本技能還是必要的。下面我們還是以 Boost 源碼包的使用為例進行介紹。
本地編譯 Boost.python
在編譯之前,需要確保本機已經(jīng)安裝了 Visual Studio 和 Python。
首先,我們使用命令行進入 Boost 源碼包的安裝目錄,執(zhí)行 bootstrap.bat 腳本,將會在當前目錄下生成 b2.exe、bjam.exe、project-config.jam、bootstrap.log 四個文件。其中,b2.exe、bjam.exe 就是我們編譯時要用到的命令了。這兩個命令的作用是一樣的,bjam 是老版本,b2 是升級版本。
下面就可以開始編譯 Boost.python 了,筆者在本機所使用的命令如下:
b2.exe --with-python stage --stagedir="./bin/lib32-msvc-14.0" link=static address-model=32
編譯完成后,將在 ./bin/lib32-msvc-14.0/lib 目錄下產(chǎn)生 4 個文件:
libboost_numpy36-vc140-mt-gd-x32-1_68.lib
libboost_numpy36-vc140-mt-x32-1_68.lib
libboost_python36-vc140-mt-gd-x32-1_68.lib
libboost_python36-vc140-mt-x32-1_68.lib
其中,python 和 numpy 各 2 個,帶 gd 的對應(yīng) debug 版本,反之對應(yīng) release 版本。
默認情況下,編譯時調(diào)用的編譯器和 Python 版本是 b2/bjam 自動搜索的。如果要指定不同的 Python 版本,就需要在你的 home 目錄下新建一個配置文件 user-config.jam(路徑為 C:\Users\xxx\user-config.jam)。推薦直接使用 Boost 根目錄下的 tools/build/example/user-config.jam 作為模板,稍加修改即可。例如,筆者的 user-config.jam 中對 Python 的配置如下:
using python
: 3.5
: "D:/App/Python35/python.exe"
: "D:/App/Python35/include"
: "D:/App/Python35/libs"
: <define>BOOST_ALL_NO_LIB=1
;
b2/bjam 參數(shù)說明:
b2 命令的功能強大,用起來也比較復雜,因此在使用之前,最好先查看一下該命令的幫助:
b2.exe --help
以下是一些比較重要的參數(shù)說明:
-
stage/install:
stage 表示只生成庫(dll 和 lib),install 還會生成包含頭文件的 include 目錄。推薦使用 stage,因為 install 生成的 include 目錄實際就是源碼包下的 boost 目錄,需要 include 的時候可以直接使用,不需要再次生成,這樣可以節(jié)省大量的編譯時間。
-
toolset:
指定編譯器,可選的如 borland、gcc、msvc-14.0(VS2015)等。如果不指定,會自動搜索本地可用的編譯器(可查看
./project-config.jam文件以確認)。 -
without/with:
選擇不編譯/編譯哪些庫(類似于黑名單/白名單)。
--with-python的含義是僅編譯 python,其他的都不編譯。反過來,如果用--without-python,意思就是除了 python, 其他的都編譯。with/without 參數(shù)可以多次出現(xiàn),以限定多個庫。如果不設(shè)置 with/without 參數(shù),默認全部編譯,可能需要幾個小時的時間!需要注意,編譯 Boost.python 需要確保本地安裝了 Python,并且 python 命令已加入環(huán)境變量。
要查看 Boost 包含的所有庫,可使用以下命令:
b2.exe --show-libraries -
stagedir/prefix:
stage 時使用 stagedir,install 時使用 prefix,表示編譯生成文件的路徑。推薦給不同的編譯環(huán)境指定不同的目錄,如 Visual Studio 2015 的 x86 應(yīng)用對應(yīng)的是
bin/lib32-msvc-14.0,x64 應(yīng)用對應(yīng)的是bin/lib64-msvc-14.0。如果都生成到一個目錄下,將沒有任何益處,徒增管理難度。如果使用了 install 參數(shù),那么還將在上述指定的目錄下生成include目錄,用于保存頭文件。 -
build-dir:
編譯生成的中間文件的路徑,默認是 Boost 根目錄下的
bin.v2目錄,一般無需設(shè)置。 -
link:
指定生成動態(tài)鏈接庫還是靜態(tài)鏈接庫,取值為
static|shared。生成靜態(tài)鏈接庫使用 static,生成動態(tài)鏈接庫需使用 shared。如不指定,默認使用 static。靜態(tài)庫的缺點是占用空間比較大,優(yōu)點是程序發(fā)布的時候無需附帶 Boost 庫的 dll,比較整潔。推薦使用靜態(tài)庫的方式編譯 Boost.python,這樣發(fā)布程序的時候就不用 Boost 的 dll 了,并且也多占用不了太多空間。 -
runtime-link:
指定運行時是動態(tài)還是靜態(tài)鏈接其他庫。同樣有 shared 和 static 兩種方式。如果不指定,默認是 shared,一般無需設(shè)置。
-
threading:
要編譯的庫是單線程還是多線程,可取值
single|multi。如果不指定,默認是 multi,一般無需設(shè)置。 -
variant
debug|release,編譯 debug 版本還是 release 版本。一般與最終發(fā)布的程序是 debug 還是 release 版相對應(yīng)。如果不指定,默認兩個都編譯,一般無需設(shè)置。 -
address-model
編譯成 32 位版本還是 64 位版本,可取值
32|64。如果不指定,默認兩個版本都編譯。如果是編譯 Boost.python,該參數(shù)就要與本地安裝的 Python 位數(shù)相對應(yīng),否則編譯會出錯,因此最好設(shè)置一下。
Boost 靜態(tài)庫/動態(tài)庫的命名規(guī)則
以 Boost.python 為例,如果編譯的是靜態(tài)庫(link=static),將會生成單個 .lib 文件:
libboost_python36-vc140-mt-gd-x32-1_68.lib
而如果編譯的是動態(tài)庫(link=shared),將會生成兩個文件(.lib 和 .dll):
boost_python36-vc140-mt-gd-x32-1_68.lib
boost_python36-vc140-mt-gd-x32-1_68.dll
動態(tài)庫雖然也生成 .lib 文件,但它與靜態(tài)庫的 .lib 文件差別很大。動態(tài)庫的 .lib 更像是對 .dll 的聲明,二者的關(guān)系類似于 .h 與 .cpp 的關(guān)系。因此,動態(tài)庫中的 .lib 文件要比靜態(tài)庫的 .lib 文件小得多。
下面以靜態(tài)庫的命名規(guī)則為例進行分析:
libboost_python36-vc140-mt-sgd-x32-1_68.lib
| || | | | | | || ||| | | | |
- --- ------ --- -- - - - --
1 2 3 4 5 6 7 8 9
- 靜態(tài)庫以
lib開頭,動態(tài)庫開頭沒有lib。 - 所有的庫都含有
boost前綴。 - Boost 庫名稱,本例中為
python36。 - 編譯器名稱及其版本,
vc140指的是 msvc-14.0,對應(yīng) Visual Studio 2015。 - 有
mt代表threading=multi,沒有則代表threading=single。 - 有
s代表runtime-link=static,沒有則代表runtime-link=shared。 - 有
gd代表 debug 版本,沒有則代表 release 版本。 - 目標位數(shù),
x32代表 32 位,x64代表 64 位。 - Boost 庫的版本號,
1_68代表 Boost 1.68 版本。
Boost 庫的使用
如果要在項目中使用 Boost 庫,需要做以下兩項配置:
- 包含 Boost 頭文件(本例中為:
D:\ProgramFiles\boost_1_68_0); - 鏈接 Boost 庫文件(本例中為:
D:\ProgramFiles\boost_1_68_0\bin\lib32-msvc-14.0\lib)。
Boost 官方推薦使用 b2/bjam 命令進行自動化編譯、鏈接,只需要編寫一個 .jam 配置文件,這種方式類似于 make 和 Makefile。但考慮到還要學習 jam 語法,暫時還是用 Visual Studio 手動編譯吧。
在 Visual Studio 中的具體操作如下:
- 選中當前項目,點擊屬性按鈕,依次選擇“配置屬性->C/C++->常規(guī)->附加包含目錄”,編輯并添加一條路徑:
D:\ProgramFiles\boost_1_68_0; - 選中當前項目,點擊屬性按鈕,依次選擇“配置屬性->鏈接器->常規(guī)->附加庫目錄”,編輯并添加一條路徑:
D:\ProgramFiles\boost_1_68_0\bin\lib32-msvc-14.0\lib。
Boost.python 的使用
要使用 Boost.python,除了上述兩項配置之外,還需要再添加兩項配置:
- 包含 Python 頭文件(本例中為:
D:\Program Files (x86)\Python36-32\include); - 包含 Python 靜態(tài)庫文件(本例中為:
D:\Program Files (x86)\Python36-32\libs\python36.lib)。
在 Visual Studio 中的具體操作如下:
- 選中當前項目,點擊屬性按鈕,依次選擇“配置屬性->C/C++->常規(guī)->附加包含目錄”,編輯并添加一條路徑:
D:\Program Files (x86)\Python36-32\include; - 選中當前項目,點擊屬性按鈕,依次選擇“配置屬性->鏈接器->輸入->附加依賴項”,編輯并添加一個文件:
"D:\Program Files (x86)\Python36-32\libs\python36.lib",注意要有雙引號,否則可能識別不正確。
測試
準備 hello world 代碼
使用官網(wǎng)給出的 hello world 示例,代碼文件位于 Boost 安裝目錄下:D:\ProgramFiles\boost_1_68_0\libs\python\example\tutorial,包括 hello.cpp 與 hello.py 兩個文件,如下:
hello.cpp:
// 當引入 #include <boost/python/xxx> 時,Boost 會默認鏈接 boost_python 動態(tài)鏈接庫,
// 如果我們想要鏈接靜態(tài)鏈接庫,就需要在 include 之前加上 #define BOOST_PYTHON_STATIC_LIB
#define BOOST_PYTHON_STATIC_LIB
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
char const* greet()
{
return "hello, world";
}
BOOST_PYTHON_MODULE(hello_ext)
{
using namespace boost::python;
def("greet", greet);
}
hello.py:
import hello_ext
print(hello_ext.greet())
我們的目的是將 hello.cpp 編譯成一個 .pyd 文件(其實就是一個包含 Python 接口的 .dll 文件),然后用 hello.py 調(diào)用它。
注意:hello.cpp 中的宏定義 #define BOOST_PYTHON_STATIC_LIB 非常重要,它可以指定鏈接 boost_python 的靜態(tài)庫,而不是默認的動態(tài)庫。
如果你在編譯過程中遇到了這樣的錯誤:LINK : fatal error LNK1104: cannot open file "boost_python36-vc140-mt-x32-1_68.lib",但是你明明已經(jīng)引入了靜態(tài)庫:libboost_python36-vc140-mt-x32-1_68.lib,你可能會納悶:我明明已經(jīng)導入了靜態(tài)庫,為什么還找我要動態(tài)庫?那么最可能的原因是,你的 C++ 代碼中漏掉了這句宏定義。
使用 Visual Studio 構(gòu)建 hello world
Boost 官方推薦使用 b2/bjam 命令進行自動化編譯、鏈接,只需要編寫一個 .jam 配置文件,這種方式類似于 make 和 Makefile。但考慮到還要學習 jam 語法,暫時還是用 Visual Studio 手動編譯吧。
- 首先使用 Visual Studio 創(chuàng)建一個空項目。
- 打開項目屬性,在“配置屬性->常規(guī)”中,進行以下修改:
- 配置類型設(shè)為:“動態(tài)庫(.dll)”。
- 目標文件名設(shè)為:
hello_ext。
注意:.pyd文件的名稱必須與要導出的 python module 名稱一致,否則 python 的 import 語句將會報錯:ImportError: dynamic module does not define module export function。 - 目標文件擴展名設(shè)為:
.pyd。
- 將
hello.cpp文件導入項目。 - 參照上一節(jié) [Boost 庫的使用] 中的說明,將 Boost 頭文件目錄、Boost 庫文件目錄、Python 頭文件目錄、Python 靜態(tài)庫文件都導入到項目中。
- 選擇菜單“生成->生成 Project”,如果一切無誤,將會生成一個
hello_ext.pyd文件。由于生成器的默認配置是Debug-x86,因此生成目錄為項目下的 Debug 目錄。 - 將
hello_ext.pyd與hello.py放在同一目錄下,執(zhí)行hello.py,將會看到輸出:hello, world。