自行擴展 vcpkg 的套件:以 zlib-ng 取代 zlib

| | 0 Comments| 14:43|
Categories:

微軟的 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.cmakevcpkg.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.cmakevcpkg.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 也不熟,所以就沒什麼碰了。

Leave a Reply

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *