維護者指南

本檔列出新增或更新埠配方時應套用的原則集。 它的目的是為 Debian 的政策手冊Homebrew 的維護者指導方針Homebrew 的公式食譜的角色提供服務。

PR 結構

為每個埠提出個別的提取要求

盡可能將變更分成多個 PR。 這可讓它們更容易檢閱,並防止一組變更的問題阻礙所有其他變更。

避免未變更檔案中的簡單變更

例如,請避免在 portfiles 中重新格式化或重新命名變數,否則沒有理由針對目前的問題進行修改。 不過,如果您需要將檔案修改為PR的主要用途(更新連結庫),則很欣賞修正錯字等明顯有益的變更!

檢查其他存放庫的名稱

一次檢查許多人的好服務是 Repology。 如果您要新增的連結庫可能會與另一個連結庫混淆,請考慮重新命名以清楚說明。 當名稱較長且/或不太可能與任何未來使用相同的名稱使用時,我們偏好使用 。 如果埠參考 GitHub 上的連結庫,如果有任何混淆的機會,最好是將名稱前面加上組織。

使用 GitHub 草稿 PR

GitHub 草稿 PR 是取得尚未準備好合併之工作 CI 或人為意見反應的絕佳方式。 大多數新的 PR 應該以草稿的形式開啟,並在 CI 通過後轉換為一般 PR。

如需 GitHub 草稿 PR 的詳細資訊,請參閱 簡介草稿提取要求

Portfiles

避免已被取代的協助程式函式

此時,下列協助程式已被取代:

某些取代協助程式函式位於「工具埠」中,可讓取用者在特定版本釘選其行為,以允許鎖定特定版本的協助程序行為。 工具埠必須新增至您埠的 "dependencies",如下所示:

{
  "name": "vcpkg-cmake",
  "host": true
},
{
  "name": "vcpkg-cmake-config",
  "host": true
}

避免在 portfiles 中過度批注

在理想情況下,portfiles 應該是簡短、簡單且盡可能宣告式。 提交PR之前,請先移除命令所 create 引進的任何鍋爐板批注。

埠不得相依於路徑

埠不得根據哪些埠已安裝的形式變更其行為,而該窗體會變更埠所安裝的內容。 例如,假設:

> vcpkg install a
> vcpkg install b
> vcpkg remove a

> vcpkg install b

b 安裝的檔案必須相同,不論先前安裝 a的影響為何。 這表示埠在採取一些動作之前,不得嘗試偵測安裝樹狀結構中是否有專案由另一個埠提供。 以下說明「定義功能時,明確控制相依性」中這類「路徑相依性」行為的特定和常見原因。

唯一埠屬性規則

在整個 vcpkg 系統中,用戶預期不會同時使用兩個埠,可能會提供相同的檔案。 如果埠嘗試安裝已由另一個檔案提供的檔案,安裝將會失敗。 例如,如果埠想要針對標頭使用極通用的名稱,它應該將這些標頭放在子目錄中,而不是 在中 include

在非官方命名空間中新增 CMake 導出

vcpkg 的核心設計是不會為客戶建立「鎖定」。 在建置系統中,根據來自系統的連結庫,以及根據 vcpkg 的連結庫,應該沒有任何差異。 為此,我們避免將 CMake 匯出或目標新增至具有「明顯名稱」的現有連結庫,以允許上游新增自己的官方 CMake 匯出,而不會與 vcpkg 衝突。

為此,埠導出的任何 CMake 設定,不在上游連結庫中,都應該有 unofficial- 作為前置詞。 任何其他目標都應該位於 命名空間中 unofficial::<port>::

這表示用戶應該會看到:

  • find_package(unofficial-<port> CONFIG) 作為取得 unique-to-vcpkg 套件的方式
  • unofficial::<port>::<target> 做為從該埠匯出的目標。

範例:

  • brotliunofficial-brotli 建立封裝,產生目標 unofficial::brotli::brotli

每個埠必須在資料夾中${CURRENT_PACKAGES_DIR}/share/${PORT}提供名為 copyright 的檔案。 如果套件的授權內容可在其原始程式檔內使用,則應該透過呼叫 vcpkg_install_copyright()來建立此檔案。 vcpkg_install_copyright 如有必要,也會配套多個著作權檔案。

vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")

手動建立此檔案的較舊方法是使用 CMake 的內 file 建命令。 不建議 vcpkg_install_copyright 在新的埠中使用,但仍允許這樣做。

file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)

如果上游原始程式檔中的授權內容不是文字格式(例如 PDF 檔案), copyright 則應該包含使用者如何找到授權需求的說明。 可能的話,它也應該包含原始來源檔案的連結,指出這一點,讓使用者可以檢查它是否為最新狀態。

file(WRITE "${CURRENT_PACKAGES_DIR}/share/${PORT}/copyright" [[As of 2023-07-25, according to
https://github.com/GPUOpen-LibrariesAndSDKs/display-library/blob/master/Public-Documents/README.md#end-user-license-agreement
this software is bound by the "SOFTWARE DEVELOPMENT KIT LICENSE AGREEMENT" PDF located at
https://github.com/GPUOpen-LibrariesAndSDKs/display-library/blob/master/Public-Documents/ADL%20SDK%20EULA.pdf
]])

功能

請勿使用功能來實作替代專案

特徵必須被視為加法性功能。 如果 port[featureA] 安裝與 port[featureB] 安裝,必須 port[featureA,featureB] 安裝 。 此外,如果第二個埠相依 [featureA] ,而第三個埠相依於 [featureB],則安裝第二個和第三個埠應該符合其相依性。

在此情況下,連結庫必須選擇 vcpkg 中所表示的其中一個可用選項,而想要不同設定的使用者此時必須使用重迭埠。

我們目前不接受的現有範例會保留回溯相容性:

  • libgit2libzipopen62541 都有選取 TLS 或密碼編譯後端的功能。 curl 有不同的密碼編譯後端選項,但允許在運行時間進行選取,這表示會維護上述原則。
  • darknet 具有 opencv2opencv3功能,可控制要用於其相依性的 opencv 版本。

功能可能會參與預覽或 Beta 功能

儘管如此,如果有預覽分支或類似的分支,預覽功能很有可能不會中斷非預覽功能(例如,沒有 API 移除),則模型化這項設定是可接受的功能。

範例:

  • Azure SDK(形式 azure-Xxx為 )具有一項 public-preview 功能。
  • imguiexperimental-docking具有參與其預覽對接分支的功能,其使用附加至每個公用編號版本的合併認可。

默認功能應啟用行為,而非 API

如果取用者直接相依於連結庫,他們可以輕鬆地列出任何所需的功能(library[feature1,feature2])。 不過,如果取用者 不知道 他們正在使用連結庫,就無法列出這些功能。 如果該隱藏連結庫就像 libarchive 功能將額外的壓縮演算法(因此行為)新增至現有的泛型介面,則預設功能會提供一種方式,以確保即使最終取用者未直接命名它,還是會建置合理的功能可轉移連結庫。

如果功能新增了其他 API(或可執行檔或連結庫二進位檔),而且不會修改現有 API 的行為,則預設應該將其關閉。 這是因為任何可能想要使用這些 API 的取用者,都可以透過其直接參考輕鬆地要求它。

如有疑問,請勿將功能標示為預設值。

請勿使用功能來控制已發佈介面中的替代專案

如果埠的取用者只相依於該埠的核心功能,則開啟功能不可能中斷。 當替代專案不是由取用者直接控制,而是由像是的 /std:c++17 / -std=c++17編譯程式設定控制時,這更為重要。

我們目前不接受的現有範例會保留回溯相容性:

  • redis-plus-plus[cxx17] 會控制 polyfill,但不會將設定製作成已安裝的樹狀結構。
  • ace[wchar] 將所有 API 變更為接受 const wchar_t* ,而不是 const char*

功能可能會以別名取代 polyfill,前提是取代會模擬到已安裝的樹狀結構中

儘管如此,只要下列情況,埠可能會移除具有功能的 polyfills:

  1. 開啟功能會將 polyfills 變更為 polyfilled 實體的別名
  2. polyfill 的狀態會模擬到已安裝的標頭中,因此 ABI 不相符的「不可能」運行時間錯誤不太可能
  3. 埠的取用者可以撰寫這兩種模式中運作的程序代碼,例如,使用 polyfilled 或不是 polyfill 的 typedef

範例:

  • abseil[cxx17] 變更 absl::string_view 為取代 或 std::string_view; 修補程序 會實作烘焙需求。

如果公開基礎替代方案非常重要,建議您在建置階段提供訊息,以指示使用者如何將埠複製到私人重疊:

set(USING_DOG 0)
message(STATUS "This version of LibContoso uses the Kittens backend. To use the Dog backend instead, create an overlay port of this with USING_DOG set to 1 and the `kittens` dependency replaced with `dog`.")
message(STATUS "This recipe is at ${CMAKE_CURRENT_LIST_DIR}")
message(STATUS "See the overlay ports documentation at https://github.com/microsoft/vcpkg/blob/master/docs/specifications/ports-overlay.md")

建置技術

請勿使用廠商的相依性

請勿使用連結庫的內嵌複本。 所有相依性都應該分開分割和封裝,以便更新和維護它們。

偏好使用 CMake

當有多個建置系統可用時,偏好使用 CMake。 此外,適當時,使用指示詞將替代建置系統重寫為 CMake file(GLOB) 可能更容易且更容易維護。

範例: abseil

選擇靜態或共用二進位檔

根據預設, vcpkg_cmake_configure() 會針對 傳遞適當的設定 BUILD_SHARED_LIBS,但是對於不尊重該變數的連結庫,您可以開啟 VCPKG_LIBRARY_LINKAGE

string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" KEYSTONE_BUILD_STATIC)
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" KEYSTONE_BUILD_SHARED)

vcpkg_cmake_configure(
    SOURCE_PATH ${SOURCE_PATH}
    OPTIONS
        -DKEYSTONE_BUILD_STATIC=${KEYSTONE_BUILD_STATIC}
        -DKEYSTONE_BUILD_SHARED=${KEYSTONE_BUILD_SHARED}
)

定義功能時,明確控制相依性

定義擷取選擇性相依性的功能時,請確定未明確啟用此功能時,不會意外使用相依性。

set(CMAKE_DISABLE_FIND_PACKAGE_ZLIB ON)
set(CMAKE_REQUIRE_FIND_PACKAGE_ZLIB OFF)
if ("zlib" IN_LIST FEATURES)
  set(CMAKE_DISABLE_FIND_PACKAGE_ZLIB OFF)
  set(CMAKE_REQUIRE_FIND_PACKAGE_ZLIB ON)
endif()

vcpkg_cmake_configure(
  SOURCE_PATH ${SOURCE_PATH}
  OPTIONS
    -DCMAKE_DISABLE_FIND_PACKAGE_ZLIB=${CMAKE_DISABLE_FIND_PACKAGE_ZLIB}
    -DCMAKE_REQUIRE_FIND_PACKAGE_ZLIB=${CMAKE_REQUIRE_FIND_PACKAGE_ZLIB}
)

以下使用 vcpkg_check_features() 的代碼段是相等的。

vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
  FEATURES
    "zlib"    CMAKE_REQUIRE_FIND_PACKAGE_ZLIB
  INVERTED_FEATURES
    "zlib"    CMAKE_DISABLE_FIND_PACKAGE_ZLIB
)

vcpkg_cmake_configure(
    SOURCE_PATH ${SOURCE_PATH}
    OPTIONS
      ${FEATURE_OPTIONS}
)

ZLIB 代碼段中會區分大小寫。 如需詳細資訊,請參閱 CMAKE_DISABLE_FIND_PACKAGE_<PackageName>CMAKE_REQUIRE_FIND_PACKAGE_<PackageName> 檔。

如果連結庫執行下列任一項,則會被視為衝突:

  • 定義 main
  • 定義 malloc
  • 定義其他連結庫中也宣告的符號

衝突的連結庫通常是依設計而未視為瑕疵。 由於某些組建系統會連結至 lib 目錄中的所有專案,因此應該將這些專案移至名為 manual-link的子目錄。

指令清單和 CONTROL 檔案

新增埠時,請使用新的指令清單語法來定義埠;您也可以在修改現有的埠時變更為指令清單。 您可以藉由執行 vcpkg format-manifest 命令,輕鬆地執行 命令,將現有的 CONTROL 檔案轉換成指令清單檔。 請勿轉換尚未修改的 CONTROL 檔案。

版本管理

遵循欄位的 "version" 常見慣例

建立新的埠時,請遵循套件作者所使用的版本設定慣例。 更新埠時,除非上游另有說明,否則請繼續使用相同的慣例。 如需慣例的完整說明,請參閱我們的 版本控制檔

如果上游在一段時間內尚未發行發行,請勿將埠的版本設定配置變更為 version-date ,以取得最新的變更。 這些認可可能包含尚未準備好生產環境的變更。 相反地,請要求上游存放庫發佈新版本。

"port-version"更新任何已修改埠指令清單檔中的欄位

vcpkg 會使用此字段來判斷指定的埠是否過期,而且應該在埠的行為變更時變更。

我們的慣例是使用 "port-version" 欄位來變更不會變更上游版本的埠,並在進行上游版本的更新時,將 重設為 "port-version" 零。

例如:

  • Zlib 的套件版本目前 1.2.1為 ,沒有明確的 "port-version" (相當於 "port-version"0)。
  • 您已發現已部署錯誤的著作權檔案,並已修正 portfile 中的該檔案。
  • 您應該將 "port-version" 指令清單檔中的欄位更新為 1

如需詳細資訊, 請參閱版本控制檔

更新任何修改埠中的 versions/ 版本檔案

vcpkg 會使用一組元數據檔案來提供其版本設定功能。 這些檔案位於下列位置:

  • ${VCPKG_ROOT}/versions/baseline.json、(此檔案適用於所有埠) 和
  • ${VCPKG_ROOT}/versions/${first-letter-of-portname}-/${portname}.json (每個埠一個)。

例如,相關 zlib 檔案如下:

  • ${VCPKG_ROOT}/versions/baseline.json
  • ${VCPKG_ROOT}/versions/z-/zlib.json

我們預期每次更新埠時,您也會更新其版本檔案。

更新這些檔案的建議方法是執行 x-add-version 命令,例如:

vcpkg x-add-version zlib

如果您要同時更新多個埠,您可以改為執行:

vcpkg x-add-version --all

以一次更新所有已修改埠的檔案。

注意

這些命令會要求您先將變更認可至埠,再執行這些變更。 原因是這些版本檔案中需要埠目錄的 Git SHA。 但別擔心,如果您有尚未認可的本機變更, x-add-version 命令會警告您。

如需詳細資訊,請參閱 版本設定參考建立登錄

修補

vcpkg 是封裝解決方案,不是我們部署之元件的最終擁有者。 在某些情況下,我們確實需要套用修補程式,以改善元件與平臺的相容性,或彼此的元件相容性。

  • 我們想要避免修補程式:
    • 上游會不同意
    • 造成弱點或當機
    • 我們無法跨上游版本更新維護
    • 足以讓 vcpkg 存放庫本身發生授權糾纏

針對上游相關修補程式通知上游擁有者

如果上游可能有用修補程式,則上游必須收到修補程序內容的通知。 (套用 vcpkg 特定行為與上游無關的修補程式,例如取消裝飾相依性,不需要通知。

為了避免上游與修補程式不一致的情況,我們將等待至少 30 天來套用這類修補程式。

如果我們對變更正確充滿信心,我們會略過此等候期間。 高信賴修補程式的範例包括,但不限於:

  • 上游接受作為修補程式(例如,從提取要求上游反向移植特定變更已合併)。
  • 新增遺漏 #include的 s。
  • 小型且明顯的產品代碼修正(例如,初始化未初始化的變數)。
  • 停用組建中無關緊要的 vcpkg 元件,例如測試或範例。

偏好選項而不是修補

最好是在呼叫 vcpkg_configure_xyz() 中設定選項,以直接修補設定。

可讓您避免修補的常見選項:

  • [MSBUILD] <PropertyGroup> 項目檔內的設定可以透過 /p: 參數覆寫
  • [CMAKE] find_package(XYz) CMake 文本中的呼叫可以透過 停用 -DCMAKE_DISABLE_FIND_PACKAGE_XYz=ON
  • [CMAKE]快取變數(宣告為 set(VAR "value" CACHE STRING "Documentation")option(VAR "Documentation" "Default Value"))可以藉由在命令列上將其傳入 來覆寫為 -DVAR:STRING=Foo。 其中一個值得注意的例外狀況是,如果 FORCE 參數傳遞至 set()。 如需詳細資訊,請參閱 CMake set

偏好修補覆寫 VCPKG_<VARIABLE>

前面加上 VCPKG_<VARIABLE> 的某些變數具有相等 CMAKE_<VARIABLE>的 。 不過,並非所有套件都會傳遞至內部套件組建(請參閱實作:Windows 工具鏈)。

請考慮下列範例:

set(VCPKG_C_FLAGS "-O2 ${VCPKG_C_FLAGS}")
set(VCPKG_CXX_FLAGS "-O2 ${VCPKG_CXX_FLAGS}")

使用 vcpkg的內建工具鏈可正常運作,因為的值 VCPKG_<LANG>_FLAGS 會轉送至適當的 CMAKE_LANG_FLAGS 變數。 但是,不知道 vcpkg變數的自定義工具鏈不會轉寄它們。

因此,最好在設定 CMAKE_<LANG>_FLAGS時直接修補組建系統。

最小化修補程式

對連結庫進行變更時,請努力將最終差異降到最低。 這表示在進行會影響區域的變更時,您不應該重新格式化上游原始程式碼。 此外,停用條件時,最好將 或 && 0 加入AND FALSE條件,而不是刪除條件的每一行。

如果埠已過期,且將埠更新為較新版本,請勿新增修補程式,可解決相同的問題。 vcpkg 偏好更新埠,而不是修補過期的版本,除非版本顛簸中斷相當數量的相依埠。

這有助於將 vcpkg 存放庫的大小保持關閉,並改善修補程式將套用至未來程式代碼版本的可能性。

請勿在修補程式中實作功能

在 vcpkg 中修補的目的是要啟用與編譯程式、連結庫和平臺的相容性。 不實作新功能,而不是遵循適當的開放原始碼程式(提交問題/PR/等)。

默認不要建置測試/docs/examples

提交新的埠時,請檢查或 或 WITH_TESTSPOCO_ENABLE_SAMPLES 之類的BUILD_TESTS任何選項,並確定已停用其他二進位檔。 這會將平均使用者的建置時間和相依性降到最低。

或者,您可以新增功能 test 來建置測試,不過這不應該出現在 Default-Features 清單中。

讓連結庫的現有使用者切換至 vcpkg

不要新增 CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS

除非連結庫的作者已經使用它,否則我們不應該使用此 CMake 功能,因為它與 C++ 範本互動不佳,並中斷某些編譯程式功能。 未提供 .def 檔案且不使用 __declspec() 宣告的連結庫,只是不支援 Windows 的共享組建,且應該使用 vcpkg_check_linkage(ONLY_STATIC_LIBRARY)標示為 。

請勿在上游指定的名稱之外重新命名二進位檔

這表示如果上游連結庫在 release 和 debug 中有不同的名稱(libx 與 libxd),則不應該將偵錯連結庫重新命名為 libx。 相反地,如果上游連結庫在發行和偵錯中具有相同的名稱,我們不應該引進新的名稱。

重要注意事項:

  • 靜態和共用變體通常應該重新命名為通用配置。 這可讓取用者使用一般名稱,並忽略下游連結。 這是安全的,因為我們一次只提供一個。

如果連結庫產生 CMake 整合檔案 (foo-config.cmake),則必須透過修補 CMake 組建本身來完成重新命名,而不是只呼叫 file(RENAME) 輸出封存/LIB。

最後,Windows 上的 DLL 檔案不應該在建置後重新命名,因為它會中斷產生的 LIB。

體現

我們需要格式化指令清單檔。 使用下列命令來格式化所有指令清單檔:

> vcpkg format-manifest --all

三胞 胎

我們目前不接受新增非社群三胞胎的要求。 從社群升階到完整三元組狀態主要是根據硬體的預算來測試這類三胞胎,並由 vcpkg 提交的計量所驅動,以充分發揮人們實際使用的可能性進行完整測試。

如果:

  • 它表明,人們實際上會使用該社區三重:和
  • 我們不知道這樣的三重奏被打破了。

例如,我們並未在 中 https://github.com/microsoft/vcpkg/pull/29034 新增三元,因為作者只是嘗試「完成集合」,而不是指出它們實際會使用這類專案,而且直到 patchlf 解決方案建立可重新放置結果之前,我們才新增 linux-dynamic。

實用的實作注意事項

Portfiles 是在腳本模式中執行

雖然 portfile.cmakeCMakeLists.txt's 共用通用語法和核心 CMake 語言建構(也稱為「腳本命令」),但 portfiles 會在「腳本模式」中執行,而 CMakeLists.txt 檔案則以「專案模式」執行。 這兩種模式之間的最重要差異是「腳本模式」沒有「工具鏈」、「語言」和「目標」的概念。 任何行為,包括文稿命令,相依於這些建構 (例如 CMAKE_CXX_COMPILERCMAKE_EXECUTABLE_SUFFIXCMAKE_SYSTEM_NAME) 不會正確。

Portfiles 可直接存取在三重檔案中設定的變數,但 CMakeLists.txt不是 (雖然經常發生翻譯 -- VCPKG_LIBRARY_LINKAGEBUILD_SHARED_LIBS) 。

portfiles 叫用的 Portfiles 和 Project 組建會在不同的進程中執行。 概念:

+----------------------------+       +------------------------------------+
| CMake.exe                  |       | CMake.exe                          |
+----------------------------+       +------------------------------------+
| Triplet file               | ====> | Toolchain file                     |
| (x64-windows.cmake)        |       | (scripts/buildsystems/vcpkg.cmake) |
+----------------------------+       +------------------------------------+
| Portfile                   | ====> | CMakeLists.txt                     |
| (ports/foo/portfile.cmake) |       | (buildtrees/../CMakeLists.txt)     |
+----------------------------+       +------------------------------------+

若要判斷 portfile 中的主機,標準 CMake 變數很好(CMAKE_HOST_WIN32)。

若要判斷 portfile 中的目標,應該使用 vcpkg triplet 變數 (VCPKG_CMAKE_SYSTEM_NAME)。

另請參閱我們的 三重檔 ,以取得可能設定的完整列舉。