版本控制概念

最低版本要求

vcpkg 使用最少的选择方法进行版本控制,灵感来自 Go 使用的版本控制,但在某些方面进行了修改:

  • 总是从全新安装开始,以避免需要进行升级或降级操作。
  • 通过引入基线来允许不受约束的依赖项。

但是,最小选择原则保持不变。 给定一组约束后,vcpkg 将使用可以满足所有约束的包的“最早”可能版本。

使用最低版本方法具有以下优点:

  • 这是可预测的和易于理解的。
  • 用户控制何时进行升级,就像在新版本发布时一样,不会自动执行升级。
  • 避免使用 SAT 求解器。

若要提供示例,请考虑以下包图:

    (A 1.0) -> (B 1.0)

    (A 1.1) -> (B 1.0) 
            -> (C 3.0) 

    (A 1.2) -> (B 2.0)
            -> (C 3.0)

    (C 2.0)

以及以下清单:

{
    "name": "example",
    "version": "1.0.0",
    "dependencies": [ 
        { "name": "A", "version>=": "1.1" },
        { "name": "C", "version>=": "2.0" }
    ], 
    "builtin-baseline": "<some git commit with A's baseline at 1.0>"
}

在考虑可传递依赖项后,我们具有以下一组约束:

  • A >= 1.1
    • B >= 1.0
    • C >= 3.0
  • C >= 2.0

由于 vcpkg 必须满足所有约束,安装包集将变为:

  • A 1.1,即使 A 1.2 存在,也没有比 1.1 更高的约束,因此 vcpkg 选择了可能的最低版本。
  • B 1.0,由 A 1.1 传递依赖。
  • C 3.0A 1.1 添加的传递约束升级,以满足版本约束。

约束解析

给定具有一组版本控制依赖项的清单,vcpkg 将尝试计算满足所有约束的包安装计划。

版本约束具有以下风格:

  • 声明的约束:在顶级清单中使用version>=显式声明的约束。
  • 基线约束:由 builtin-baseline..隐式添加的约束。
  • 传递约束:由您的依赖项的依赖项间接添加的约束。
  • 重写约束:使用 overrides 声明在顶级清单中重写的约束。

若要计算安装计划,vcpkg 大致遵循以下步骤:

  • 将所有顶级约束添加到计划。
  • 以递归方式向计划添加可传递约束。
    • 每次向计划添加新包时,也将新包的基线约束添加到计划中。
    • 每次添加约束时:
    • 如果存在针对该软件包的重写选项
      • 选择替代中的版本。
    • 否则:
      • 如果没有选择先前的版本。
        • 选择满足约束的最低版本。
      • 如果选择了以前的版本:
        • 如果新约束的版本控制方案与以前选择的版本不匹配:
          • 添加版本冲突。
        • 如果约束的版本与以前选择的版本不相上下。 例如,将“version-string: apple”与“version-string: orange”进行比较:
          • 添加版本冲突。
        • 如果约束版本高于以前选择的版本:
          • 选择最高版本。
        • 否则:
          • 保留上一个选择。
  • 查看计划:
    • 如果没有冲突
      • 安装所选包
    • 否则:
      • 向用户报告冲突

获取端口版本

虽然包版本的概念一直存在于 vcpkg 中,但版本约束的概念尚未出现。

随着版本控制约束的引入,包现在可能依赖于与本地可用的端口版本不匹配的端口版本。 这引发了问题,因为 vcpkg 需要知道如何获取所请求版本的端口文件。

为了解决此问题,引入了一组新的元数据文件。 这些文件位于 versions/ vcpkg 存储库根级别的目录中。

versions/ 目录将包含注册表中可用的每个端口的 JSON 文件。 每个文件将列出可用于包的所有版本,并包含一个 Git 树式对象,以便 vcpkg 可以通过签出该对象来获取相应版本的 portfiles。

示例: zlib.json

{
  "versions": [
    {
      "git-tree": "2dfc991c739ab9f2605c2ad91a58a7982eb15687",
      "version-string": "1.2.11",
      "port-version": 9
    },
    ...
    {
      "git-tree": "a516e5ee220c8250f21821077d0e3dd517f02631",
      "version-string": "1.2.10",
      "port-version": 0
    },
    {
      "git-tree": "3309ec82cd96d752ff890c441cb20ef49b52bf94",
      "version-string": "1.2.8",
      "port-version": 0
    }
  ]
}

对于每个端口,其相应的版本文件应位于 versions/{first letter of port name}-/{port name}.json。 例如,zlib 的版本文件将位于 versions/z-/zlib.json. 除了端口版本文件外,当前基线文件位于 versions/baseline.json