微軟的 vcpkg 官方 registry 其實已經算提供相當多套件了,在大部分的情境下,應該都算是夠用吧?但是某些狀況下,可能還是會發現 vcpkg 官方的 registry 不夠用,例如:
- 有的套件的更新頻率不夠快
- 某些冷門套件更可能沒有被納入
- 官方提供的 port 建置方法和需求不同
而為了解決這種比較特別的需求,官方其實也有提供一些擴展的功能、可以在基於使用官方的 registry 的情況下、額外去自訂、擴充一些東西。
這邊主要有兩個方法:overlay 和自己架設/第三方的 registry。
使用多個 registry
由於要弄出一個符合規範的 registry 來說其實相對麻煩,所以個人覺得比較有可能的方法,應該會是使用第三方的 registry。
vcpkg 本身就支援同時使用多個 registry、基本上只要在 vcpkg-configuration.json 中加入額外的 registry 定義就可以了。
而在多個來源的時候,官方也有明確地定義 port 的解析順序、並且也可以自己透過字串比對來做調整,基本大部分時候應該也都夠用。
不過由於 Heresy 這邊沒有額外的 registry 來玩,所以基本上就沒什麼在管這部份了;有興趣的可以參考官方的《Package name resolution》這篇文章。
自己定義 overlay
相較於比較麻煩的 registry,一般人要擴展的話、比較方便使用的選項應該會是 overlay(官方文件)。
Overlay 基本的概念就是另外定義一組 port(也可以定義 triplet)、用來覆蓋本來 registry 的東西;在要找東西的時候,vcpkg 會先到 overlay 裡面找,所以除了可以加入本來沒有的套件外、也可以設定和本來同名的套件、用來取代本來的建置規則。
overlay ports
如果是要自己定義一個套件的 port 的話,基本上針對每個套件建立一個資料夾、裡面需要有 portfile.cmake 和 vcpkg.json(或者 CONTROL) 這兩個檔案;下面就是官方舉的例子:
my-ports/ |-- sqlite3/ |---- vcpkg. json |---- portfile.cmake |-- rapidjson/ |---- vcpkg. json |---- portfile.cmake
這樣就是定義了自己的 sqlite3 和 rapidjson 這兩個套件的 port。
要使用的時候,則有三種方法:
- 執行
vcpkg的時候透過--overlay-ports這個參數(官方文件)來指定要使用的 overlay ports 的路徑 - 在
vcpkg-configuration.json這個檔案裏面加入overlay-ports的定義(官方文件) - 透過環境變數
VCPKG_OVERLAY_PORTS來設定(官方文件)
這邊都是要指定的路徑,可以指定到 my-ports 這層讓他去找子資料夾、也可以指定到個別的 port,如果有多個路徑可以指定多次。
至於 portfile.cmake 和 vcpkg.json 要怎麼寫,就之後再看看吧。
overlay triplets
而如果是要自定義編譯參數的話,基本上是要透過自己定義 triplet 來做,這部分官方也有提供範例(官方文件)。
這邊是建議建立一個資料夾、來放自己定義的 triplet;而每一個 triplet 就是一個 .cmake 檔案、裡面設定必要的變數,檔案的名稱就是 triplet 的名字。
比如說這邊要針對預設的「x64-linux」和「x64-windows」做修改(覆寫),就可以建立成下面的結構:
my-triplets |-- x64-linux.cmake |-- x64-windows.cmake
這邊的檔案可以直接拿官方的來修改(參考)、應該算是相對簡單。
而要使用的話,基本上設定方法和 overlay ports 類似、主要是三種方法:
- 執行
vcpkg的時候加上--overlay-triplets(官方文件) - 在
vcpkg-configuration.json這個檔案裏面加入overlay-triplets的定義(官方文件) - 透過環境變數
VCPKG_OVERLAY_TRIPLETS來定義(官方文件)
不過這樣的設定只是讓 vcpkg 知道到哪邊可以找到 triplet、如果有需要手動指定的話,則是會需要另外設定(參考)。
所以如果在都做好的狀況下,要使用自己的 overlay 的話,使用 vcpkg 指令來安裝就會變成類似下面的指令:
vcpkg install --overlay-ports=./my-ports --overlay-triplets=./my-triplets
而如果是用 manifest 模式的話,vcpkg-configuration.json 的內容大概會變成下面的形式:
{
"default-registry": {
"kind": "git",
"baseline": "3bdaa9b42070c241c1bdb02b4cf01f90de579738",
"repository": https://github.com/microsoft/vcpkg
},
"overlay-ports": [ "./my-ports" ],
"overlay-triplets": [ "./my-triplets" ] }
接下來下面就用舉例來說明了。
實際範例:使用 zlib-ng 取代 zlib
zlib(官網)是一個相當老牌的壓縮函式庫,基本上有大量的函式庫都會用到它。而 zlib-ng(官網)則號稱是下一代的系統、號稱可以提高相當的效率;由於它可以用 zlib 相容模式建置外、所以其實在技術上可以整個取代掉 zlib。
但是由於 vcpkg 本身會去處理函示庫的相依性、所以要做到底層套件的替換、其實變得相對困難;所以如果想用 zlib-ng 完全取代 zlib 的話,比較簡單的想法,就會是:
- 建立一個 zlib 的 overlay port、裡面去用 zlib 相容模式來建置 zlib-ng
但是由於 zlib-ng 如果要建置成 zlib 相容模式需要特別的建置參數(ZLIB_COMPAT)、vcpkg 提供的 port 也沒辦法調整(因為會破壞專有 API 的相容性),所以沒辦法像自己在編譯的時候那樣簡單地切換。
所以要在 vcpkg 裡面做這樣的事,可能會有兩種方向:
- 把本來 zlib-ng 的 port(參考)複製到這個 overlay port、修改裡面的參數
- 透過 overlay triplet 來調整 zlib-ng 的編譯參數
這邊的範例採用的是第二種方法。
這邊的範例放在 overlay 這個分支(連結),其中 overlay port 的部分就是 my-ports 這個資料夾,裡面只有定義 zlib 這個 port;其中 vcpkg.json 定義了這個 port 的資訊,內容如下:
{ "name": "zlib", "version-string": "2.0.0", "description": "Proxy port to redirect zlib dependencies to zlib-ng.", "dependencies": [ "zlib-ng" ] }
這邊是隨便把他的版本設定成 2.0,然後加上簡單的描述;比較重要的,是要加上 dependencies、讓 vcpkg 使用這個套件的時候去安裝 zlib-ng。
而另一個 portfile.cmake 理論上是要設定套件的建置方法,但是由於這邊不會真的去建置 zlib,所以基本上是空的,內容如下:
message(STATUS "Using zlib overlay: Redirecting to zlib-ng.") set(VCPKG_POLICY_EMPTY_PACKAGE enabled)
這邊就是告訴 vcpkg 允許這個空的套件而已。
這樣雖然就可以成功地讓 vcpkg 在需要的 zlib 的時候都自動去使用 zlib-ng、但是由於 zlib-ng 預設不是 zlib 相容模式,所以這邊會需要透過 overlay triplet 來調整參數;這邊的檔案放在 my-triplets 裡面,目前只有針對 x64-linux.cmake 和 x64-windows.cmake 做修改。
處理方法呢,就是先把 vcpkg 官方的 triplet(參考)複製過來,然後加入下面的內容:
# Turn on zlib compatibility if (PORT STREQUAL "zlib-ng") set(ZLIB_COMPAT ON) endif ()
這段內容基本上就是在要建置的套件名稱是「zlib-ng」的時候、額外去設定「ZLIB_COMPAT」這個參數。
這樣都處理好了之後,只要執行 vcpkg install 就可以了~之後執行 vcpkg list 來確認安裝的套件的話,應該會是類似下面的結果:
libarchive:x64-windows 3.8.1 Library for reading and writing streaming archives vcpkg-cmake-config:x64-windows 2024-05-23 vcpkg-cmake:x64-windows 2024-04-23 zlib-ng:x64-windows 2.2.5 zlib replacement with optimizations for 'next ge... zlib:x64-windows 2.0.0 Proxy port to redirect zlib dependencies to zlib...
不過要注意的,是這樣修改的結果會變成 zlib-ng 只有 zlib 相容 API,所以哪天如果有碰到需要 zlib-ng 自己的 API 的套件的時候應該是會出問題的。
簡單的玩 overlay 大概就是這樣了。
至於如果要自己寫一個官方沒有提供的函示庫的 port 該怎麼寫呢?官方在《Tutorial: Package a library with vcpkg》這邊是有教學,但是由於整個架構都是基於 CMake、Heresy 也不熟,所以就沒什麼碰了。
