维护指南
本文档列出了添加或更新端口配方时应应用的一组策略。
它的目的是服务于以下角色: Debian 的政策手册, Homebrew 的维护者指南,以及 Homebrew 的配方食谱。
总体注册表设计目标
当前基线中的端口必须可同时安装
如果您希望向用户展示这种替代情况,请考虑描述如何有人可以创建一个 overlay port 来实现替代方案
在portfile.cmake中添加注释,而不是尝试添加从未内置的其他端口策划的注册表的持续集成。例如,参见
glad@0.1.36。
在引入 registries 之前,我们接受了一些未经测试的端口替代方案,例如boringssl,可能会使创作覆盖端口
更轻松。这不再被接受,因为注册表允许发布这些未经测试的端口无需修改策划的注册表。
PR 结构
为每个端口发出单独的拉取请求
尽可能将更改分为多个 PR。 这样更容易进行审查,并可防止一组更改的问题妨碍所有其他更改。
避免对未触及的文件进行微小的更改
例如,避免重新格式化或重命名端口文件中的变量,否则没有理由针对当前问题进行修改。但是,如果您需要出于 PR 的主要目的(更新库)修改文件, 那么显然有益的改变,如修复拼写错误,将受到赞赏!
对照其他存储库检查名称
端口名称应尽量明确端口是哪个包安装。理想情况下,在搜索引擎中搜索端口名称应该很快 引导您到相应的项目。服务很好,可以检查很多包裹一次跨多个存储库的名称是Repology。
名称简称或以常用词命名的项目可能需要消除歧义,特别是当没有具有强关联的项目时 到给定的单词。例如,名称为“ip”的端口是不可接受的因为多个项目很可能会被类似地命名。
好的消歧器的例子有:
- 存储库的所有者用户名或组织:
google-cloud-cpp。 - 该项目所属的一组库的名称:
boost-dll。
C++ 和开源项目使用的常见前缀和后缀无效 消歧符,一些示例包括但不限于:
cpp,free,lib,open,- numbers
例如,在比较以下端口名称时:ip-cpp、libip 和ip5 并删除无效的消歧符,它们都被简化为相同的
干(ip),因此被认为具有相同的名称。
对于强关联的名称,此准则有一个例外与单个项目。例如:libpng、openssl和zlib。
Portfiles
避免弃用的辅助函数
目前,以下助手已被弃用:
- 不推荐使用的不带“ARCHIVE”的“kmpkg_extract_source_archive()”重载应替换为支持的带“ARCHIVE”的重载。
kmpkg_copy_tool_dependency()应替换为kmpkg_copy_tools()- 删除“PREFER_NINJA”后,“kmpkg_configure_cmake”应替换为
kmpkg_cmake_configure() kmpkg_build_cmake应替换为kmpkg_cmake_build()kmpkg_install_cmake应替换为kmpkg_cmake_install()kmpkg_fixup_cmake_targets应替换为kmpkg_cmake_config_fixup
一些替换帮助程序功能位于“工具端口”中,以允许消费者固定他们的特定版本的行为,以允许将帮助程序的行为锁定在特定版本 版本。工具端口需要添加到端口的“依赖项”中,如下所示:
{
"name": "kmpkg-cmake",
"host": true
},
{
"name": "kmpkg-cmake-config",
"host": true
}
避免端口文件中过多的注释
理想情况下,端口文件应该简短、简单并且尽可能具有声明性。在提交 PR 之前,删除“create”命令引入的所有样板注释。
端口不得依赖于路径
端口不得根据已安装的端口来更改其行为,从而改变端口安装的内容。例如,给定:
> kmpkg install a
> kmpkg install b
> kmpkg remove a
and
> kmpkg install b
无论先前安装的a的影响如何,b安装的文件必须相同。这意味着端口在采取某些操作之前不得尝试检测另一个端口是否在已安装的树中提供了某些内容。下面的“定义功能时,显式控制依赖关系”中描述了这种“路径依赖”行为的具体且常见的原因。
唯一端口属性规则
在整个 kmpkg 系统中,用户预计同时使用的两个端口不可能提供相同的文件。如果端口尝试安装另一个文件已提供的文件,安装将失败。例如,如果端口想要对标头使用极其常见的名称,则应该将这些标头放置在子目录中而不是include中。
通过持续集成运行定期检查此属性,该运行尝试在注册表中安装所有端口,如果两个端口提供相同的文件,则会因FILE_CONFLICTS而失败。
在非官方命名空间中添加 CMake 导出
kmpkg 的核心设计理念是不要为用户造成“锁定”。 在构建系统中,根据系统中的库和 kmpkg 中的库,不应有区别。 为此,我们避免将 CMake 导出或目标添加到具有“明显名称”的现有库,以允许上游添加自己的官方 CMake 导出,而不会与 kmpkg 冲突。
为此,端口导出的任何 CMake 配置(不在上游库中)都应将 unofficial- 作为前缀。 任何其他目标都应位于 unofficial::<port>:: 命名空间中。
这意味着用户应看到:
find_package(unofficial-<port> CONFIG)作为获取unique-to-kmpkg包的途径unofficial::<port>::<target>作为从该端口导出的目标。
示例:
brotli创建unofficial-brotli包,生成目标unofficial::brotli::brotli。
安装版权文件
每个端口必须在文件夹${CURRENT_PACKAGES_DIR}/share/${PORT}中提供名为copyright的文件。如果包的许可证内容在其源文件中可用,
则应通过调用 kmpkg_install_copyright() 创建此文件。如果需要,kmpkg_install_copyright 还会捆绑多个版权文件。
kmpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
手动创建此文件的较旧方法是使用 CMake 内置的file命令。在新端口中不鼓励这样做,有利于kmpkg_install_copyright,但仍然允许。
file(INSTALL "${SOURCE_PATH}/LICENSE" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}" RENAME copyright)
如果上游源文件中的许可证内容不是文本形式(例如 PDF 文件), 则“版权”应包含用户如何找到许可证要求的说明。如果可能的话,它还应该包含指向原始源文件的链接来表明这一点,以便用户可以检查它是否是最新的。
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],则安装第二个和第三个端口应该满足它们的依赖关系。
在这种情况下, 库必须选择可用选项之一(以 kmpkg 表示),并且想要不同设置的用户此时必须使用覆盖端口。
为了向后兼容,我们今天不接受保留的现有示例:
libgit2、libzip、open62541都具有选择 TLS 或加密后端的功能。curl有不同的加密后端选项,但允许在运行时在它们之间进行选择,这意味着上述原则得以维持。darknet具有opencv2、opencv3功能来控制其依赖项使用哪个版本的 opencv。
某个功能可能涉及预览版或测试版功能
尽管有上述规定,如果存在预览分支或类似分支,其中预览功能很可能不会破坏非预览功能(例如,没有 API 删除),则可以接受一个功能来对此设置进行建模。
示例:
- Azure SDK(形式为“azure-Xxx”)具有“公共预览”功能。 -“imgui”具有“实验对接”功能,该功能参与其预览对接分支,该分支使用附加到每个公共编号版本的合并提交。
默认功能应该启用行为,而不是 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*。