1. 程式人生 > >Boost編譯方法

Boost編譯方法

方法一:

經歷了將近半年多的時間boost終於釋出了1.35.0版本(前版本1.34.1釋出於2007/7),
其編譯方法和原來的編譯方法基本上是一致的,主要改變包括1.34.0以來bjam的toolset所
提供的引數名稱的改變(具體參見《boost1.34.0編譯日誌》)外,還包括bjam的編譯預設
選項的變化,在1.35.0之前的版本預設編譯時會自動編譯各種版本的庫,包括靜態庫、
動態庫、debug庫和release庫等全部的版本,但是到了1.35.0時預設的選擇僅僅編譯release
版本的庫,這樣一來在開發的時候就不能進行必要的除錯了,為了能夠使其編譯全部的版本
需要在bjam的命令列引數中新增一個--build-type=complete型別的引數來指明需要編譯全
部的版本,所需要編譯同時為了使得regex庫能夠通過ICU庫支援Unicode,在編譯上需要有
一些特殊的選擇。我在Visual Studio 2005 Pro + SP1環境下編譯了該庫,為了避免走彎路
所以將其編譯的方法進行說明,以方便大家編譯。
    由於boost是採用其自己的bjam工具通過命令列進行編譯的,所以必須在Windows下開啟console視窗,同時必須將Visual Studio中C++目錄下的環境vcvarsall.bat配置指令碼執行一遍,以設定好VC的編譯器環境變數。
    1. 編譯不帶ICU支援的boost庫
       此種情況下的boost庫編譯起來比較的簡單,在準備好的console視窗中輸入:
           bjam --without-python --toolset=msvc-8.0 --build-type=complete stage
       就可以了,如果要安裝的話則輸入:
           bjam --without-python --toolset=msvc-8.0 --build-type=complete install
          
    2. 編譯具有ICU支援的boost庫
       首先我們必須編譯ICU庫才能夠編譯boost庫,在準備好的console視窗中輸入:
           bjam -sICU_PATH=d:/ICU --without-python --toolset=msvc-8.0 --build-type=complete stage
       就可以了,如果要安裝的話則輸入:
           bjam -sICU_PATH=d:/ICU --without-python --toolset=msvc-8.0 --build-type=complete install
    通過上面的方法可以很正常完成boost各種需要版本的關係。

每次用bjam編譯boost總是要檢視幫助檔案才行。
雖然現在的bjam編譯命令只有兩三個引數,可是不小心還是會錯。

1. toolset引數中,試圖用vc,正確的應該是msvc。
vc用於庫檔案的命名字尾中。兩個名字能統一就好了。

2. 編譯工具的版本號應該用點號分隔,並且總是應該指定該版本號。
如msvc-71是錯誤的,應該用msvc-7.1。
小版本號不能省,如msvc-6.0不能寫成msvc-6。
版本號指定錯誤,可能也能編譯,但是生成庫的名字是錯的。

3. 使用stlport。
要在user-config.jam中配置stlport,
例如:using stlport : : F:/STLport-5.1.0/stlport F:/STLport-5.1.0/lib ;
並且別忘了在引數中加上引數:--stdlib=stlport。
user-config.jam中的stlport配置可以一直保持開啟,
因為最終是由stdlib引數決定是否使用stlport。

方法二:

1.點選 開始->程式->Microsoft Visual Studio 2005->Visual Studio Tools->Visual Studio 2005 命令提示
2.cd D:/Libs/boost_1_35_0/tools/jam/src
3.build.bat
 此時在src/bin.ntx86/目錄下產生了bjam.exe
4.將bjam.exe拷貝到boost的根目錄D:/Libs/boost_1_35_0
5.cd D:/Libs/boost_1_35_0
6.bjam.exe --build-dir=build --toolset=msvc stage
 
 編譯完成後,產生了2個目錄build和stage,但同時也發現一個奇怪問題:stage裡面的檔案,竟然有很多相同的lib,比如boost_date_time-vc80-mt-1_35.lib和boost_date_time-vc80-mt.lib,boost_filesystem-vc80-mt-1_35.lib和boost_filesystem-vc80-mt.lib他們檔案的大小一樣,只是檔名稍微不同,一個帶有版本號,另一個沒有。編譯的問題,還是boost本身有

方法三:

 一、下載安裝:

  下載boost 1.31,解壓縮至一個資料夾,本文以[boost-path]來引用這個路徑。

  二、編譯準備工作:

  首先是編譯jam,在< boost-path >/tools/build/v1下,把vc7.1-tools.jam檔案複製一份,改名為vc80-tools.jam,我暫時未測試stl-port。

  修改檔案內容裡的路徑,這個根據你的安裝路徑來改。去掉幾個flag行,以後編譯時就少一些警告。修改以後內容如下:

extends-toolset msvc ;

# singleton variables...
set-as-singleton VC80_ROOT ;

if ! $(MSVCDir)
{
ProgramFiles ?= $(PROGRAMFILES) ;
VC80_ROOT ?= $(ProgramFiles:J=" ")//Microsoft Visual Studio 8//VC" ;
VC_TOOL_PATH = "$(VC80_ROOT)//bin// ;
VC_SETUP = "CALL /"$(VC_TOOL_PATH)VCVARS32.BAT/" >nul" ;
}
VC_PDB_NAME = vc80 ;
flags vc80 C++FLAGS on : /Zc:wchar_t ;

  然後開啟VC2005程式組裡面的Visual Studio Command Prompt,這能確保已載入環境變數,減少後面一些操作過程。在[boost-path]/tools/build/jam-src目錄下執行:

build -sTOOLS=vc80

  編譯會通過的,最後連結時會報錯,之後想到的方法如下:

./bootstrap.vc7/jam0 -f build.jam --toolset=vc7 "--toolset-root=C:/Program Files/Microsoft Visual Studio 8/VC"

  注:這個選項不能直接附加在build批處理後面,所以要這樣呼叫。

  好了,bjam編譯完成。下面編譯boost,有2個檔案需要改一下:

  [boost-path]/boost/config/auto_link.hpp在第118行附近改為:

#elif defined(BOOST_MSVC) && (BOOST_MSVC == 1310)

// vc71:
# define BOOST_LIB_TOOLSET "vc71"

#elif defined(BOOST_MSVC) && (BOOST_MSVC >= 1400)

// vc80:
# define BOOST_LIB_TOOLSET "vc80"

  注:如果你不修改這裡,那麼後面測試時無法連結到正確的lib,因為前面我們已經使用了“VC.NET 2005”,生成的lib全是VC.NET 2005的。

  [boost-path]/boost/config/compile/visualc.hpp最後面的>1310改為1400,如下:

#if (_MSC_VER?> 1400)

  注:如果不修改這個,無法正確生成所需要的lib。

  這些檔案修改就完成了。如果你需要boost-python,那麼還需設定幾個環境變數,注意路徑替換為你自己的,版本號只留前2位,比如2.3.4,則只需要寫上2.3。

SET PYTHON_ROOT=c:/soft/python24
SET PYTHON_VERSION=2.4
SET PYTHON_LIB_PATH=c:/soft/python24/libs

  三、編譯:

  以上過程都完畢了,現在轉到[boost-path]目錄下,執行如下命令:

tools/build/jam_src/bin.ntx86/bjam -sTOOLS=vc80 "-sBUILD=debug release static/dynamic single/multi"

  編譯完成以後,設定VC2005的include和lib路徑,最好搜尋一下*.lib,拷到一個資料夾下,接下來就可以測試了。

  四、測試:

  寫了一段測試正則表示式的程式碼,編譯、連結,結果是報錯。原來是要連結多執行緒版本!在VC2005裡找了一下,發現只有多執行緒選項,單執行緒竟然沒有列進來。

  這中間我走了一點彎路,試圖編譯一個多執行緒版本的boost,結果發現不行,編譯出來還是單執行緒的,就執行緒庫是多執行緒版本。

  最後用了個蠢辦法:在#include < stdafx.h >後面加上一句:#undef _MT,終於可以執行起來了。

  五、補充說明:

  如果系統中有MSVCDir 這個環境變數,VC80_ROOT這個變數將會被忽略掉。由於vc2005對C++的標準庫增加了更嚴格的安全性檢測,所以在VC2005裡使用boost會得到很多假的警告,可以通過定義 _SCL_SECURE_NO_DEPRECATE 或者加入#pragma warning(disable:4996)來處理掉,另外一些是因為某些老的C庫函式被VC2005宣告為deprecated(不贊成使用的),例如fopen, str*字串函式等。

方法四:

boost庫是一個跨平臺的C++庫,因此它的安裝多少有些麻煩——如果你需要使用那些必須編譯的庫的時候。在windows平臺上(使用VS2003和VS2005)最簡單的辦法就是從 http://www.boost-consulting.com/download/windows?下載boost庫的installer,使用它可以指定安裝基於哪個開發環境的庫,每個庫安裝那些版本,非常方便,免去了配置編譯之苦。

編譯了一個使用正則表示式庫regex的控制檯應用程式,設定好包含目錄和庫目錄後,發現最後連結失敗,提示:LINK : fatal error LNK1104: 無法開啟檔案“libboost_regex-vc80-mt-gd-1_34_1.lib”。使用boost庫不需要在工程設定中顯式的指定庫名字,而是由boost自身來完成這個設定的。由於boost庫跨平臺並且支援多個編譯環境,因此這個被連結庫檔案的檔名是根據當前編譯的配置動態生成的。boost_regex是庫的基本名稱,vc80是編譯環境,mt表示這是一個多執行緒庫,gd表示包含除錯資訊,最後的1_34_1是版本號。檢查安裝後的庫檔案,發現有的是boost_regex-vc80-mt-gd-1_34_1.lib,所以很明顯,在庫名生成的過程中出現了問題,多了一個“lib”字首。

開啟boost/regex.hpp,繼續開啟boost/regex/config.hpp檔案,最終可以發現動態連結配置的功能是由boost/config/auto_link.hpp統一實現的。在這個檔案開頭的註釋裡詳細說明了使用方式,相信這種方式對我們自己的庫開發也很有裨益。這裡提到了名稱的構造公式:

BOOST_LIB_PREFIX
   + BOOST_LIB_NAME
   + "_"
   + BOOST_LIB_TOOLSET
   + BOOST_LIB_THREAD_OPT
   + BOOST_LIB_RT_OPT
   "-"
   + BOOST_LIB_VERSION

根據我們的錯誤,我們應該檢查BOOST_LIB_PREFIX的值為什麼是“lib”而不是空的。通過搜尋,發現

#if (defined(_DLL) || defined(_RTLDLL)) && defined(BOOST_DYN_LINK)
#? define BOOST_LIB_PREFIX
#elif defined(BOOST_DYN_LINK)
#? error "Mixing a dll boost library with a static runtime is a really bad idea..."
#else
#? define BOOST_LIB_PREFIX "lib"
#endif

現在終於清楚了,我們應該在工程設定中加入_DLL定義或者_RTLDLL定義,並且指定boost庫採用動態連線,定義BOOST_DYN_LINK。在工程設定中加入_DLL;BOOST_DYN_LINK,連結就通過了。

方法五:

這幾天寫程式碼需要序列化自定義類,類的定義可以抽象為vector<vector<T> >。我本想通過過載operator<<和operator>> 來實現序列化。但是寫入是寫入了,讀就讀不出來了。在讀完第一個物件之後istream的tellg()返回了-1,導致後續的物件無法讀取。後來我使用boost很方便的就完成了序列化的工作。但是我使用的編譯環境是VC9,boost還沒有針對vc9的編譯設定,所以編譯安裝還是花了點時間。

針對VC9,下載的boost需做如下修改:(+為需增加的行,)

檔案 msvc.jam

@@ -231,6 +231,10 @@ local rule configure-really (
         {
             # Even if version is not explicitly specified, try to detect the version
             # from the path.
+            if [ MATCH "(Microsoft Visual Studio 9.0)" : $(command) ]
+            {
+                version = 9.0 ;
+            }                
             if [ MATCH "(Microsoft Visual Studio 8)" : $(command) ]
             {
                 version = 8.0 ;
@@ -913,13 +916,14 @@ actions compile.mc

 .ProgramFiles = [ path.make [ common.get-program-files-dir ] ] ;

-.known-versions = 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ;
+.known-versions = 9.0 9.0express 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ;

 # Version aliases
 .version-alias-6 = 6.0 ;
 .version-alias-6.5 = 6.0 ;
 .version-alias-7 = 7.0 ;
 .version-alias-8 = 8.0 ;
+.version-alias-9 = 9.0 ;

 # Name of the registry key that contains Visual C++ installation path
 #   (relative to "HKEY_LOCAL_MACHINE/SOFTWARE//Microsoft"
@@ -928,6 +932,8 @@ actions compile.mc
 .version-7.1-reg = "VisualStudio//7.1//Setup//VC" ;
 .version-8.0-reg = "VisualStudio//8.0//Setup//VC" ;
 .version-8.0express-reg = "VCExpress//8.0//Setup//VC" ;
+.version-9.0-reg = "VisualStudio//9.0//Setup//VC" ;
+.version-9.0express-reg = "VCExpress//9.0//Setup//VC" ;

 # Visual C++ Toolkit 2003 do not store its installation path in the registry.
 # The environment variable 'VCToolkitInstallDir' and the default installation

檔案 auto_link.hpp

line133開始改成:

#elif defined(BOOST_MSVC) && (BOOST_MSVC == 1400)
 
 // vc80:
#  define BOOST_LIB_TOOLSET "vc80"
 
#elif defined(BOOST_MSVC) && (BOOST_MSVC >= 1500)
 
 // vc90:
#  define BOOST_LIB_TOOLSET "vc90"

#elif defined(__BORLANDC__)

檔案 visualc.hpp

#error "Compiler not supported or configured - please reconfigure"
 #endif
 //
-// last known and checked version is 1400 (VC8):
-#if (_MSC_VER > 1400)
+// last known and checked version is 1500 (VC9):
+#if (_MSC_VER > 1500)
 #  if defined(BOOST_ASSERT_CONFIG)
 #     error "Unknown compiler version - please run the configure tests and report the results"
 #  else


然後就可以編譯了,但是在編譯過程中會有很多的warning C4819: The file contains a character that cannot be represented in the current code page (936). 原因是boost原始碼的註釋中有很多非low ASCII的字元,都是人名和版權註釋。在編譯boost庫時可以不管,但是在編譯包含了boost的標頭檔案的專案時卻很煩人。可以在project properties,   C/C++,    Advanced,   Disable Specific warnings中填入4819關閉這個警告。

VS2005中     error       LNK2019:       無法解析的外部符號       _WinMain@16       ,該符號在函式       _WinMainCRTStartup       中被引用。

boost庫使用了一種自動連結技術,通過分析編譯器設定的工程選項自動選擇庫進行連結。例如:
    新建一個VC工程,右擊專案,選擇屬性->配置屬性->C/C++->程式碼生成->執行時庫。如果選擇非動態連結庫(MT, MTD),boost自動連結對應的靜態庫,否則(MD, MDD)會連結動態庫,使用者在在連結選項中手動設定的boost庫被忽略。
具體連結的庫名也是有boost/config/auto_link.hpp中的預編譯巨集自動生成,如果發現boost連結了不正確的庫,應該仔細分析該檔案。
    總之,配置boost專案的庫連結不是通過配置連結器,而是通過編譯器的預編譯選項和預編譯巨集實現的。
    再舉一個例子:使用VC編譯boost相關工程常見的一個錯誤是,選擇MDD庫編譯時,報找不到boost庫的錯誤,分析auto_link.hpp可知,在MDD選項開啟時,預編譯巨集_DLL被設定,在auto_link.hpp的294行有如下程式碼:
#if ((defined(_DLL) || defined(_RTDLL))) && defined(BOOST_DYN_LINK)
#define BOOST_LIB_PREFIX
#elif defined(BOOST_DYN_LINK)
#error "Mixing a dll boost library with a static runtime is a really bad idea..."
#else
#define BOOST_LIB_PREFIX "lib"
#endif
由於BOOST_DYN_LINK未設定,導致庫名字首巨集BOOST_LIB_PREFIX被定義為"lib",而boost動態連結庫的庫名預設是沒有lib字首的,如是會導致上述連結錯誤。只要在編譯器預編譯頭中定義巨集BOOST_DYN_LINK即可解決該問題

一個link error
error LNK2001: unresolved external symbol __imp___assert
You may be using /MTd (Debug Multithreaded), which could explain this link error.
When you build and link your static library, I recommend you use /MDd [debug] or /MD [release], which means use the DLL runtime libraries.

關於STLport
首先應該定義:
#define __STL_DEBUG
但由於用了STLport,會連結boost_regex-vc80-mt-gdp-1_41.lib(不用STLport時是boost_regex-vc80-mt-gd-1_41.lib)。boost_regex-vc80-mt-gdp-1_41.lib在boost的lib目錄下沒有,如果非得使用STLport,可以想到的有兩種辦法:
1)將boost的lib目錄下的boost_regex-vc80-mt-gd-1_41的lib和dll複製一份出來改成boost_regex-vc80-mt-gdp-1_41的lib和dll。這種方法又會引入很多新的link error
2)將STLport下的stlportd.5.1的lib和dll拷貝出來,放入當前工程目錄下,程式宣告中加上:
#pragma comment(lib, "stlportd.5.1.lib")

由於boost庫預設是靜態連結的,因此要加入宣告:
#define BOOST_ALL_DYN_LINK
#define BOOST_LIB_DIAGNOSTIC

一個測試程式:
#define BOOST_ALL_DYN_LINK
#define BOOST_LIB_DIAGNOSTIC
#define __STL_DEBUG
#pragma comment(lib, "stlportd.5.1.lib")

#include <cstdlib>
#include <stdlib.h>
#include <boost/regex.hpp>
#include <string>
#include <iostream>

using namespace boost;
using namespace std;

regex expression("^select ([a-zA-Z]*) from ([a-zA-Z]*)");

int main(int argc, char* argv[]){
 std::string in;
 cmatch what;
 cout << "enter test string in the from of select aaa from bbb:" << endl;
 getline(cin,in);
 if(regex_match(in.c_str(), what, expression)){
  for(int i=0;i<what.size();i++)
   cout<<"str :"<<what[i].str()<<endl;
 }
 else{
  cout<<"Error Input"<<endl;
 }
 return 0;
}