如何在 Vcpkg 使用特並版本LIB

Using Specified Lib Version in Vcpkg

Vcpkg 作為微軟在Windows平台上的函示庫管理方案。當然Vcpkg也能運行於Linux與Mac平台上。只是這兩個平台上原本就有unix系統上與生俱來的庫管理系統,我想多數開發者都不太會使用vcpkg作為自己的庫管理工具。

在Windows上,一直缺乏統一的Library Manager。所以幾乎都是採用Case by Case的方式運作。此外,Windows也沒有統一的編譯環境。或者說與unix的方式有著本質上的不同,你無法用一套makefile來完成所有工作。總之,一切運作起來總是顯得格格不入。Vcpkg就是這麼一個為了解決此問題而提出的重要工具。

致命缺點:不具備版本管理

然而,嚴格來說,Vcpkg並不是一個完善的解決方案。至少我不這麼認為。他有著一個非常致命的缺點-他不具備版本管理的功能。這個缺點非常非常的嚴重。

我舉個我最近遇上的問題為例:我想所有開發OpenGL或是科學計算的人都會用上GLMGLFW3這兩個函示庫。在Vcpkg你只要簡單的使用:

這樣你就能輕輕鬆鬆在你的 Visual Studio 專案中,直接使用這兩個函數庫,並且連Header、Includes、Libs 都不需要任何設定就能使用。而且 Visual Studio還會很聰明的依據依賴關係幫你把必要的DLLs都替你準備好。就在一切看來是那麼美好的情況下,他潛藏的一個巨大難題與缺點是,假設你有不同的專案需要使用不同版本的函示庫時,抱歉,Vcpkg並不具備多重版本管理的功能。這時候你無法用 "一套" Vcpkg滿足你所有的需求。

Vcpkg 一個基於GIT版本控制的方案

為了找到解法,我們就要先理解Vcpkg的運作方式。Vcpkg的是一套基於GIT的庫管理工具。他的思維比較像是微軟替你管理了一套雲端的庫版本套件,他在乎的不是你要的是哪個函示庫的哪個版本。而是微軟自顧自的一直演進這些版本,他只在乎他們能不能工作正常,而不是你自己能不能工作正常。所以一旦git pull 那你可能就把一堆庫的版本不知不覺的更新成別的版本。這樣一來你的專案可能再也無法正常工作。

正因為如此,隨意的更新套件就會帶來許多的衝突與困擾。維持一套特定可用的Vcpkg就是一個必須的工作。

解決方案1: 採用多個Vcpkg

既然更新Vcpkg可能會帶來潛在問題,那個我們所幸維持一個特定的版本給特定的專案使用,這樣也能減少因為版本衝突產生問題。而且這樣也不會帶來額外的工作,頂多是多浪費了磁碟空間。

既然Vcpkg是基於GIT。所以我們可以藉由觀察GIT Log來理解哪個Vcpkg是最適合我的。以下舉 OpenSSL 為例:

我的專案需要使用 OpenSSL 1.0.2s 這個版本。但是Vcpkg 的 Head版本已經支持了OpenSSL 1.1.1,所以我不能使用master上head版本。最簡單的是直接拿特定Tag來使用。因為通常Tag的版本多為穩定版本。如此一來,我在我專案中,有了一個專屬的Vcpkg。

他看起來就像這樣:

安裝OpenSSL:

因為我們這是一個特定版本的Vcpkg,所以我不能在上面使用Vcpkg的預設整合方案,我們僅可以採用手動或是nuget的方式。因為我很懶,我推薦使用nuget的方式。雖然在多數的C/C++專案中,我們很少使用nuget來管理packages。但是實際上在C++中也非常好用。

Vcpkg 產生 nuget project:這個步驟,我們讓Vcpkg產生nuget安裝路徑。

開啟 Package Manager Console:
Visual Studio -> Menu-> Other Windows

安裝剛剛Vcpkg產生的 nupkg 安裝路徑:

安裝好之後,你的 Visual Studio 就能正常引用與編譯這些庫了。非常方便。而且不需要任何手動設定。

值得注意的,你只能同時使用一個 Vcpkg 產生的 nupkg。多個安裝的 Vcpkg 只有一個是有效的。當然,你安裝的 nupkg 的優先權將高於 root Vcpkg的整合式安裝,你不用擔心其他的 Vcpkg。 換句話說,別的 Vcpkg integrate install 並不會影響你的專案。這點非常重要。

解決方案2: 採用獨立nupkg安裝包

你或許會注意到如果每個專案都採用完整的Vcpkg,那將是非常耗非空間的。舉例來說,一個C++ Boost 就可能高達 10GB的空間。但是你可能僅僅需要數個小的工具程式,卻得付出高昂的空間,這點實在很不經濟實惠。

基於此,我們可以把解決方案1中安裝的Vcpkg打包成獨立安裝包。如此一來,我們只需要在專案引用這個安裝包,就可以避免重新下載、編譯整個Vcpkg。

打包nupkg安裝包:

這樣一來我們就有了一個名為:vcpkg-export-20200417–005338.nupkg。而且你只需要約250MB空間。接下來,我們僅需要發行這個安裝包給所有需要這些庫的專案,就能輕鬆解決函示庫安裝問題。

舉例來說,我們check out一個新專案。接下來我們重複剛剛安裝nuget的方式,安裝我們的nupkg。

注意的這種方式安裝包,一樣不能支持多個 Vcpkg 安裝包。並且也會受root Vcpkg integrate 影響。編譯前,請記得先把 root Vcpkg 的整合式安裝給移除。 root .\vcpkg integrate remove

結論:

Vcpkg 無疑是個強大又好用的函示庫管理工具。但是不具備版本管理功能讓我們產生了許多工作上的困擾。我所以採用這種多個 Vcpkg方式,其實也只能解決一部分多重版本的問題,更複雜的版本交雜則必須採用曠日廢時的手動調整,這樣一來是不是划算就很難說了。另外,Vcpkg完整的支持CMake功能,這點也是十分重要。因為Windows環境沒有預設的函示庫安裝路徑,在Windows上,使用多個CMake,而需要 find_package,幾乎無法正確找到對應的package。利用 CMake toolchain 設定為 Vcpkg 就成了一個超方便的解決方案。