WHAT'S NEW?
Loading...

[VS依賴庫管理]Boost動態連結


當你使用boost動態連結函式庫時,編譯時會出現以下的錯誤代碼嗎?
error C1189: #error :  "Mixing a dll boost library with a static runtime is a really bad idea..."

的確,boost自動連結功能(auto-linking)帶給我們便利性,節省專案設置的時間,然而如何正確設定專案就成為很重要課題。以上錯誤代碼C1189意思是『用靜態Runtime混合boost動態連結庫真的昰一個錯誤想法』,也就是說Boost動態連結的專案屬性設置錯誤。

設定Boost動態連結的專案屬性主要有以下的步驟:
  1. 在前置處理器,強制動態連結Boost函式庫
  2. 在Code Generation選擇Runtime Library
  3. 增加Boost標題檔和函式庫的路徑

錯誤代碼C1189就是在第二步Runtime Library設定錯誤,此步驟主要設定在多執行緒模式下如何連結C和C++執行函式庫(C and C++ Runtime Library),依據偵錯和發佈(Debug & Release)和靜態和動態函式庫(Static & Dll函式庫)主要分成以下四種:
  • Multi-threaded (/MT)
  • Multi-threaded Debug (/MTd)
  • Multi-threaded DLL (/MD)
  • Multi-threaded Debug DLL (/MDd)
簡單來說,若字尾帶有-d即偵錯版,沒有小寫d即發佈版。還有,判斷動態連結庫依據是多執行緒(Multi-threaded)後面是否有DLL,即縮寫為(/MD),而靜態連結則是直接為多執行緒縮寫(/MT)。

環境

  • Windows 7 64 bit
  • VS C++ 2015 
    • 方案:ThirdPartyExample
      • 專案名稱:TestBoost_Dynamic
      • 專案配置:Win32 Debug & Release
  • Boost  1.59.0
    • 下載教學:Boost簡介與分割
    • 所使用到動態連結程式庫(dll)
      • Boost.System
      • Boost.DateTime
      • Boost.Regex
  • 依賴庫相對路徑(環境變數)
    • 標頭檔路徑:$(TParty_DIR)\Boost\Include
    • 函式庫路徑:$(TParty_DIR)\Boost\Lib
    • 打包dll檔$(TParty_DIR)\bin

教程

在前置處理器(Preprocessor)新增定義

  1. 首先,在專案屬性頁面選擇C/C++』→『Preprocessor後,在Preprocessor Definitions 』加入以下的定義強制動態連結Boost函式庫
    1. BOOST_ALL_DYN_LINK
    圖一. 更改專案前置處理器

設定Runtime Library

  1. 首先,在專案屬性頁面選擇C/C++』→『Code Generation後,請根據專案組態選擇正確的Runtime Library,如以下所示。
    • 偵錯版(Debug): Multi-threaded Debug DLL (/MDd)
    • 發佈版(Release): Multi-threaded DLL (/MD)
    圖二. 選擇正確Runtime Library

增加Boost函式庫路徑

  1. 首先,在專案屬性頁面選擇C/C++』→『General後,找到Additional Include Directories』加入以下Boost標頭檔路徑
    1. $(TParty_DIR)\Boost\Include
    圖三. 加入Boost的標頭檔路徑

  2. 接下來,在同頁面下,點選Linker』在右頁面找到Additional Library Directories加入以下Boost函式庫路徑
    1. $(TParty_DIR)\Boost\Lib
    圖四. 加入Boost的函式庫路徑


[VS依賴庫管理]Boost簡介與篩選

你曾經認為Boost 函式庫過於龐大,而不敢使用嗎?

官方編譯好Boost函式庫解壓縮大約有28GB,因為此龐大函式庫是由不同IDE版本編譯出來。首先,請根據你所設定的環境,取出Lib和Header資料夾,將大小減少到2.2GB。

請問將下圖所有函式庫上傳,讓團隊其他人自行決定如何使用,這是好的專案管理嗎?



答案是非常差!!!

首先,上圖是依據專案編譯屬性所分類的函式庫,詳細請參考以下的命名規則。因此若你將所有函式庫上傳,你無法清楚告知其他人如何在新專案正確地設定編譯屬性去連結函式庫。編譯屬性不同會改變產品發佈原則,部署人員必須花時間重新打包,而且產品發佈也缺少一致性。

舉例來說,圖二某人決定新專案有以下三個設定:

  1. 靜態連結 Boost函式庫
  2. 只使用Boost 裡面的三種函式庫
  3. 動態連結C++標準庫
然而,產品發佈原則是跨平台和獨立運行的應用程式,並且不會受更新IDE所影響,請問以上的設定是對的嗎?

錯,因為動態連結C++標準函式庫代表客戶開發機必須安裝Visual C++ 可轉散發套件(Visual C++ Redistributable Packages )』,所以產品發佈時必須將VS2015 的 Visual C++ 可轉散發套件和應用程式一起打包安裝檔。此套件會隨著IDE更新有所改變也就是說,每次開發者更換IDE,部署人員就必須重新打包無形中增加專案時間成本。所以,篩選函式庫不但能讓其他人清楚如何正確使用,而且也減少第三方函式庫大小。


圖二. 已分割Boost函式庫
另一方面,Boost目前是函式庫,某些函式庫並不適合在產品開發上,而且Boost有些功能專案已實作,若不篩選Boost函式庫將導致一種功能有兩份程式碼。舉例來說,專案已經實作產生UUID的API,但是沒有文件說明產生UUID,你分派新人任務產生UUID時,你認為他會怎麼做?

若參考StackOverflow答案,新人就直接使用boost::uuids::random_generator,不但增加引用Boost標頭文件,而且增加產品編譯時間。還有,當你必須更改產生UUID機制,你
必須修正兩個地方,使程式碼缺少一致性。

因此,建議篩選Boost函式庫評估是否違反產品發佈原則,並且整理出Boost函式庫開發規範,如以下步驟所示:
  1. 列出你專案會使用到Boost函式庫
  2. 決定你要使用Boost函式庫類型,請參考以下的命名規則
    • 靜態編譯和動態編譯
    • 若靜態編譯,如何與C++標準函式庫(i.e. stl)互通
  3. 將整理好boost函式庫,分類並移動到第三方函式庫目錄
以下將教你從龐大函式庫取出專案所需要Boost靜態和動態連結,為了教學方便將動態連結和靜態連結分成兩個資料夾解釋。

環境

  • Windows 7 64 bit
  • VS C++ 2015
    • 方案:ThirdPartyExample
      • 專案名稱:TestBoost
      • 專案配置:Win32 Debug & Release
  • Boost  1.59.0
    • 已編譯好windows模組(Prebuilt windows binaries):
    •  預計使用到的函式庫
      • Boost.System
      • Boost.DateTime
      • Boost.Regex
  • 第三方函式庫位置:E:\ThirdParty
    • 靜態連結:$(TParty_DIR)\Boost\sLib
    • 動態連結:$(TParty_DIR)\Boost\Lib

命名規則

下圖列出所有Boost錯誤處理函式庫(boost::system)你能分辨這些函式庫之間的差異嗎? 並且請你先找出哪些是動態連結?



一般而言,微軟VS編譯器(Compiler)能夠自動連結(auto-linking)函式庫,而Boost預設是開啟這功能。換句話說,當你使用boost::system錯誤處理函式庫,你不但不必找出正確的函式庫,而且也不用增加函式庫名稱到其他相依性(additional dependencies)編譯器會根據專案屬性和Include函式庫選擇正確的函式庫名稱並且連結若要關閉此功能,請在前置處理器定義(Preprocessor Definitions)增加定義BOOST_TEST_NO_LIB

Boost函式庫的命名規則分成以下六種[1],如下圖所示:


  1. 前綴(prefix)『lib』在Windows 平台,函式庫有前綴(prefix)『lib』代表是靜態連結,若沒有則是動態連結,並且lib和dll是成對。
  2. 函式庫名稱所有Boost函式庫名稱會以『boost_開頭,例如:boost_system。
  3. 編譯器工具(Toolset) 使用哪個工具和版本編譯此函式庫
    • vc120:VS2013
    • vc140:VS2015
  4. 多執行緒『-mt』若函式庫包含此名稱,代表函式庫支援多執行緒功能。若要開啟這功能記得更改你的專案屬性,請參考此網址[2]。
  5. 二進位介面(ABI)決定函式庫與其他函式庫(i.e. STL、Python)的互通性,還有函式庫是否為偵錯(debug)版本。
    • 『s』: 靜態連結C++標準函式庫和編譯執行函式庫(C++ standard library and compiler runtime support libraries)
    • 『g』:使用C++標準和執行函式庫偵錯版
    • 『d:目前Boost函式庫為偵錯版。
    • 『y: 使用特殊的Python偵錯版。
    • 『p:使用STLPort標準函式庫,而不是編譯器預設的標準函式庫。
  6. 版本號函式庫Boost的版本號,例如:這次下載版本1.59.0,所以被標記為1_59

    教程

    1. 首先,在第三方函式庫的資料夾裡面新增資料夾『Boost後,並在裡面新增『Include』和『Lib』子資料夾。

    2. 圖二. 在第三方函式庫新增Boost


    3. 接下來,請將下載Boost函式庫解壓縮後資料夾boost然後複製到第三方函式庫boost的資料夾Include
    4.  
      圖三. 複製原始碼到Incude底下


    5. 然後,由於本篇下載預編譯好Boost的Windows函式庫請依據你的編譯器工具選擇資料夾,這裡在VS2015建立32位元應用程式所以選擇資料夾lib32-msvc-14.0。然後,當你要連結環境提到的三個Boost函式庫,請決定要用以下哪個方法連結Boost函式庫:
      • 靜態連結,請參考步驟4。
      • 動態連結請參考步驟5和6

      圖四. 已編譯好Boost目錄


    6. 若選擇靜態連結,函式庫必須含有前綴lib,因此挑選你要使用lib檔複製到第三方函式庫boost資料夾sLib底下,包含偵錯版本,如下圖所示

    7. 圖五. 抓取靜態連結的Boost函式庫

    8. 若選擇動態連結,函式庫沒有前綴lib,並且lib和dll是ㄧ對挑選你要使用lib檔複製到第三方函式庫boost資料夾Lib底下,包含偵錯版本,如下圖所示
    9.  
      圖六. 抓取動態連結的Boost函式庫

    10. 最後,為了能成功執行的應用程式,請將對應的dll檔複製到第三方函式庫的bin資料夾。至於如何配置VS2015專案檔,請參考[VS依賴庫管理]Boost動態連結
    11.  
      圖七. 應用程式所需要的dll檔