現在主流的應用程式大多有提供套件管理系統、可以用來快速地安裝第三方的套件;像是 npm、pip,要安裝其他函式庫來使用都算滿方便的。
但是在 C++ 這邊,感覺上就沒有這樣官方性質的套件管理系統?以 Heresy 自己來說,一直以來也都是自己管理:自己下載、自己建置,然後自己想辦法管理版本。實務上,這樣做的彈性雖然很大,但是問題其實也不少…
而這一篇,則是來稍微紀錄一下前一陣子在研究、測試的 C++ 套件管理系統:vcpkg。
不過這邊算是簡單紀錄一下它的概念和使用情境,細節的部分都會先跳過。
簡介
vcpkg 是微軟開發的一套免費、開放原始碼、跨平台(Windows、Linux、macOS)的 C/C++ 套件管理系統;他從 2016 年就在發展了,過了快十年也算是發展到一定程度了。而在微軟自家的 Visual Studio 上也有一定程度的整合,使用時可以節省不少設定的時間。
他的套件的建置架構是基於 CMake,在透過 vcpkg 來安裝套件的時候,它會自動去下載套件的原始碼以及需要的工具、然後根據系統環境來決定建置的參數設定檔、最後再使用 CMake 進行建置;在建置完成後,會把開發時需要的 header、dll、lib 等檔案以固定的結構放到特定的位置下統一管理、方便開發者使用。
而如果要安裝的套件需要其他套件的話,在大部分的狀況下、他也會按照相依性全部建置出來,不需要自己處理,所以也不太會出現找不到因為缺乏其他套件而編譯失敗的狀況。
由於 vcpkg 處理了許多相依性上的工作、所以當需要大量第三方函示庫的套件的時候,使用 vcpkg 會相對方便不少。
基本名詞
在 vcpkg 裡面有幾個基本名詞應該要知道。
- port(官方文件)
- 針對單一套件而設計好的建置腳本
- 有針對建置腳本做版本管理
- triplet(官方文件)
- 針對建置的環境(包括作業系統、處理器、編譯器等等)定義出來的建置環境的簡稱,同時也用來決定建置過程要使用的參數
- 例如:
x64-windows、x64-linux、x64-uwp-static-md等等 - registry(官方文件)
- 用來管理 port 的資料集合(應該也包含 triplet)
- 通常是直接使用微軟提供的 https://github.com/Microsoft/vcpkg
- 可以自己架設,可以透過 git、或是一般的檔案系統來做
在安裝套件的過程,基本上就是會從 registry 裡面找到對應的 port 檔案、然後使用 vcpkg 決定要使用的 triplet 來進行建置。
安裝 vcpkg
要在電腦上安裝 vcpkg,官方建議的方法是:
- 把 https://github.com/microsoft/vcpkg 這個 repo 整個 clone 下來
- 執行裡面的
bootstrap-vcpkg.bat來下載vcpkg.exe
(Linux 版則是bootstrap-vcpkg.sh) - 設定環境變數
VCPKG_ROOT指到這個資料夾 - 並將
VCPKG_ROOT這個環境變數加到系統路徑、方便後續執行
這部分的指令可以參考官方文件(連結、上面可以切換執行的環境);不過要注意的是,官方文件裡面的指令 3/4、也就是這定環境變數的部分只針對當下工作階段的設定而已,如果要設定成固定使用,則是要另外設定。
由於這個 repo 本身也就是 vcpkg 的 registry,所以他可以在本機就能搜尋到需要的套件的 port。
日後要更新的話,則是要到這個資料夾下、執行 git pull 來更新;而要更新 vcpkg 的程式的話,則是再執行一次 bootstrap-vcpkg 就可以了。
基本使用情境
在開始詳細說明前,這邊先來講一下他基本使用時的狀況。
它的使用方法主要是靠命令提示字元的形式來操作。要搜尋有哪些套件可以使用的話,可以很簡單地透過:
vcpkg search libpng
這樣的指令來找到 registry 中有那些符合的套件、以及他的版本。
(另外也有網頁可以查詢:https://vcpkg.roundtrip.dev/)
在安裝的時候,vcpkg 有兩種運作模式,分別是 classic 模式和 manifest 模式:
Classic 模式/全域安裝
這個模式會把建置好的套件放在統一的位置、讓所有專案來共用,基本上就有點像在 Ubuntu 上使用 apt 來安裝的狀況。(應該算是類似 npm -g 這樣的全域安裝)
在這個模式要安裝 libpng 就只要輸入:
vcpkg install libpng
就會完成下載原始碼、編譯,最後則是會把建置好的檔案放在 VCPKG_ROOT 這個環境變數定義的路徑下的 installed 子資料夾中,方便之後使用。
而像這邊 libpng 實際上還需要 zlib 才能建置,所以在進行 libpng 的建置之前,他就會先把 zlib 建置好,相當方便。
Manifest 模式/專案模式
這個模式會將套件安裝在專案的特定資料夾下,避免不同的專案需要不同版本的套件造成衝突、vcpkg 會透過 vcpkg.json 這個檔案、來描述專案需要那些套件。(概念上應該是和 npm 的 package.json 是類似的)
使用方法呢,則是先進入專案資料夾,然後執行:
vcpkg new --application
這樣它會建立出 vcpkg.json 和 vcpkg-configuration.json 這兩個檔案。
之後有要用的套件,則是可以透過 vcpkg add port 的指令來加入,例如:
vcpkg add port libpng
他就會把需要的套件加到 vcpkg.json 裡面來做紀錄、管理;而如果要加入多個套件,也可以直接寫在後面、一行解決。
當套件都加入完成後,只要執行:
vcpkg install
就可以安裝了。
這個模式下,他預設會在專案資料夾下建立出一個「vcpkg_installed」的資料夾、然後裡面會有一個代表使用環境的子資料夾,建置好的套件都會放在這裡。
安裝完後的資料結構
透過 vcpkg 安裝的套件,會在指定的資料夾(classic 模式預設會是「installed」、manifest 模式預設是「vcpkg_installed」)下,產生一個以 triplet 為名稱的子資料夾;在 Heresy 這邊 Windows 環境就是「x64_windows」、Linux 則是「x64_linux」。
底下的資料結構則是:
bin:release 版的 DLL(含 pdb)lib:release 版的 LIBinclude:函示庫的 headerdebug:debug 的 LIB 和 DLLshare:額外的檔案(例如授權、使用文件等)
根據套件的不同,可能也還會有其他像是 tools、plugins 等資料夾。
由於他會同時建置 debug / release 版本,所以使用上應該不會有太大的問題;另外,他的 header 檔案的配置大致上會和 Linux 上使用 apt 安裝時相同,所以要跨平台開發也會更一致。
而如果想確認到底安裝了那些套件,則可以透過 vcpkg list 這個指令來確認。
Visual Studio 的整合
既然是微軟自家的產品,所以自然也有和 Visual Studio 做一定程度的整合。
在安裝 Visual Studio 的時候,就可以選擇要不要直接安裝 vcpkg,不過由於安裝方法會和使用 Git repo 來安裝不同,vcpkg 功能也會限制在 manifest 模式;以個人稍微玩了一下的感想,是建議不要用 Visual Studio 來進行安裝。
而安裝後預設應該沒有開啟整合功能的,需要執行下面的指令來啟用整合:
vcpkg integrate install
在執行完上面的指令後,Visual Studio 的 C++ 專案屬性就會多出一個「vcpkg」的項目,讓使用者可以決定是否要針對這個專案使用 vcpkg 的管理功能。
啟用之後,如果方案/專案目錄下有 vcpkg.json 的話,Visual Studio 在建置專案的時候,就會先去檢查需要的套件是否有建置、安裝,如果沒有的話,就會自動執行 vcpkg install 來安裝,不需要自行處理。
此外,這個整合模式也包含了自動設定 include 路徑、自動加入 .lib 的連結的功能;所以在加入一個新的函式庫後,理論上不需要另外設定就可以直接使用。
基本概念介紹大概就先這樣了。那使用 vcpkg 來管理 C/C++ 的第三方函式庫的好處是什麼呢?個人覺得有幾點:
- 簡化第三方函式庫建置流程
- 靠現成的工具幫忙解決相依性問題
- 建置的腳本有人幫忙維護
- 跨平台開發
- Windows / Linux 可以使用同一個
vcpkg.json設定檔來維護要使用的套件清單 - 方便專案共同開發
- 專案只要設定好
vcpkg.json就可以了,其他要用這個專案的可以很簡單地完成第三方套件的建置、設定 - 也還有 asset cache 和 binary cache,可以降低重複取得、建置的成本
當然,這邊在使用上也不是沒有缺點、問題的;自己這邊玩得還不算多,但是有碰到一些問題:
-
中文 Windows 系統下三不五時會碰到一些編碼的問題。像是 vulkan 的套件就因為官方不知道在想什麼,在測試裡面有拿 emoji 取名的檔案、所以在解壓縮就直接失敗了。
-
如果要修改部分編譯參數、或是要拿 zlib-ng 來取代 zlib,雖然不是做不到,但是滿麻煩。
-
在 Windows 上建置某些函式庫的時候會使用 msys2 來建置,其實算是 Heresy 個人不是很喜歡的。
-
在 Linux 環境,有不少底層函式庫還是需要自己在系統安裝;尤其是圖形、桌面相關的部分。
-
雖然理論上它已經發展快十年了,但是感覺還是有很多感覺很基礎的指令都還在實驗階段(例如指定安裝路徑),也是讓個人覺得有點奇怪的。
-
他會根據相依性去安裝必要的套件,雖然最後可以很明確地透過
vcpkg list這樣的指令來看出到底裝了那些套件,但是當套件多的時候,感覺上卻很難判斷這個套件是因為哪個套件的需要而安裝的? -
如果要共用 binary cache 的話,雖然不是沒有對應的機制,但是設定和使用快取條件上也相當地麻煩…
而更大的問題,是部分函式庫在使用 vcpkg 建置時,或許是因為內部建置的參數的不同,可能會出現在自行建置時不一樣的行為模式,甚至可能導致本來可以建置的程式無法正確建置。
Heresy 這邊碰到的一些問題,包括了:
- Windows 上
glu.h會因為沒有定義APIENTRY而無法編譯 <boost/process.hpp>在 Windows 上會直接和 Windows 的WinSock.h衝突、在 Linux 上會出現語法錯誤無法編譯- Boost Test 在部分專案會無法正確連結
- Windows 上沒辦法安裝
unixodbc、導致某些相依性問題
也由於這樣的問題,所以 Heresy 這邊目前看來還是沒辦法把整個專案改用 vcpkg 來做第三方套件的管理…或許以後有時間,會再認真研究看看怎麼解決吧?
這篇大概就先這樣了。後面細節會寫多少…目前還不知道,就再看看吧。 XD
本系列文章目錄:
- 簡介
- 搭配 Visual Studio 使用 vcpkg
- 在 Makefile 與 g++ 環境使用 vcpkg
- vcpkg 套件的功能與版本設定(manifest 模式)
- 自行擴展 vcpkg 的套件:以 zlib-ng 取代 zlib

