zl程序教程

您现在的位置是:首页 >  后端

当前栏目

随心所欲地对vcpkg依赖进行版本控制

依赖 进行 版本控制
2023-09-14 09:10:46 时间

特别鸣谢

感谢Victor Romero对本文内容的贡献。

今天,我们高兴地宣布vcpkg的一项新特性:包版本控制。开发者等待这项新特性已经很久了,今天它终于来了。这项特性可以实现软件包特定依赖版本的安装,同时控制现有已安装的版本。为了使用这项新特性,你需要在你的仓库里创建一个vcpkg.json的清单文件,用来声明各个程序包的依赖关系。请注意,在命令行模式下安装的程序库还暂未支持版本控制(例如,使用vcpkg install library_name)。版本控制特性是完全可选的,也就是说,你可以选择不指定程序库的版本,这样的话,vcpkg将会替你从基线目录中选择最为合适的兼容版本。
目前,这项特性还是实验性质的,那大家就试试看呗,体验体验也好。

关于新特性:程序包版本控制

在过去的一年,我们一直致力于实现开发者希望的新特性,以使vcpkg可以广泛地使用在各种工作场景。清单(manifests)和二进制文件缓存(binary caching)就是其中的2项新特性,我们已经在之前的文章中有专门介绍过它们,从那时开始,开发者就已经在他们的项目中用上它们了。
今天,我们再次官宣一项群众呼声高的新特性:程序包版本控制。有了这一新特性,开发者就可以做如下的事情:
> 在依赖项上声明最小版本约束。
> 冻结指定版本的依赖项。
> 通过使用基线方便地更新所有已声明的依赖项。
> 获取独立于当前vcpkg的ports注册表状态的可重现构建版本。

让我们开始吧

首先,你需要在环境变量中打开”versions”特性标志。有如下几种方法:
> 如果是在Windows 10中,可以通过设置VCPKG_FEATURE_FLAGS环境变量,如下图所示:

 

> 通过在命令行(例如,PowerShell)中设置VCPKG_FEATURE_FLAGS变量:
$env:VCPKG_FEATURE_FLAGS=”versions” vcpkg install

> 通过在命令行(例如,PowerShell)中向vcpkg传入新特性标志:
vcpkg –feature-flags=”versions” install

在下面的例子中,我们将会使用到Visual Studio Code来创建一个简单的CMake工程,它会自动读取vcpkg的清单文件并安装其需要的依赖包。在Visual Studio中,你也可以这样做。如果需要了解有关如何在Visual Studio中使用vcpkg和清单的更多信息,请查看我们之前的一篇讲解vcpkg的介绍性文章。

第一个例子:简单的版本控制

如下图所示,通过在vcpkg.json中编写如下语句以创建一个文件夹:

 

当你使用清单文件的时候,vcpkg有一个新的版本声明的属性可用。在之前的版本中,你只能使用属性”version-string”为你的项目声明版本。现在,版本控制的方法变了,vcpkg可以感知到新的版本控制结构,如下图所示:

 

首先,被选中的版本结构可以影响vcpkg的程序包查找的顺序规则。
其次,我们使用属性”version>=”来声明最小版本约束。请注意,我们还使用不带特定版本约束的声明添加了一项对zlib的依赖。
最后,我们声明了”builtin-baseline”,它的值是vcpkg仓库的一项代码提交的SHA哈希值。

在上面的例子中,vcpkg将会查找”
b60f003ccf5fe8613d029f49f835c8929a66eb61″对应的提交版本,然后会找到最新的fmt版本以及当时的zlib版本,如下:
> fmt 7.1.3
> zlib 1.2.11#9 (这里的#9后缀表明这个是程序库的第9个构建版本)

上面列出来的程序包集合被定义在工程依赖的基线版本中。当需要解决程序包版本冲突的时候,基线版本添加了最小版本约束信息。

下面是一个简单的源文件,它演示了如何测试依赖项是否安装:

 

为了在一个CMake工程中使用vcpkg清单文件,需要在CMakeLists.txt文件中添加find_package和target_link_libraries这两个函数来定位所有的依赖项。不管是否使用像vcpkg那样的程序包管理器,都可以使用这两个函数,这样就可以在工程的构建中包含所需要的依赖项。

 

如果你使用的是Visual Studio Code,则下面的配置演示了如何将一个CMake工程指向一个vcpkg CMake工具链文件。对于使用vcpkg的任何CMake工程,这个文件必须被设置。另外,其他的集成开发环境或者编辑器可能有不同的方式来配置CMake工具链文件。

接下来,使用Visual Studio Code中的”CMake: Configure”指令,就可以生成CMake缓存了,如下图所示:

 

上图是当使用CMake命令行创建CMake缓存时的信息输出。在Visual Studio Code中,如果安装了CMake Tools工具扩展,则可以通过执行”CMake: Configure”指令生成缓存。

如果你注意到路径中的”
/buildtrees/versioning/versions//”,你就可以明白新的版本控制特性已经正在工作起来了。vcpkg会检查仓库中的程序包的版本。

最后,我们执行我们的测试程序,会有如下的输出:
fmt version is 70103
zlib version is 1.2.11

第二个例子:固定旧版本

因为基线版本确定了所有程序包的基础版本信息,以及当程序包低于基线版本时需要做的一些显式约束检查,所以,我们需要另外一种机制来对版本进行降级以通过基线检查。

vcpkg提供的新的机制是:override。
当我们在一个程序包上声明一个override时,vcpkg将会忽略所有其他的版本约束和在清单里直接声明的版本或者依赖的版本。简单说来,就是重写会强制vcpkg使用准确声明的版本。

首先,请修改你的清单文件,在fmt上添加一个override并强制vcpkg使用6.0.0这一版本,如下图所示:

 

接下来,请删除你的工程构建文件夹,并生成CMake缓存并重新执行一次构建:

 

最后,还是执行我们的测试程序,我们会观察到如下的输出:
fmt version is 60000
zlib version is 1.2.11

vcpkg中的版本控制是如何工作的?

下图我们描述了四个程序包的版本发布时间表:FMT, zlib, Boost and Azure Core C++库。

 

vcpkg内部的版本系统包含如下几个部分:

基线

为了使用版本控制,你需要将基线设置到一个特定的vcpkg提交版本。通过选择一个基线,你可以选择版本发布时间表中的一个版本快照。通过设置基线,可以为所有的依赖项设置一个最小的版本。
在上图中,我们有FMT的7.1.0版本,zlib的v1.2.11修订版v9版本,Boost的1.74.0版本以及2020年9月发布的Azure Core C++库。
使用基线的一个好处在于:同时期的版本非常可能就是能互相兼容的。主vcpkg注册表会构建它包含的所有同时期的程序库,以确保整个程序库目录的整体兼容性。

约束条件

与为所有软件包设置最低版本的基准相反,约束使你可以逐个软件包指定最低版本。

约束条件仅允许你升级版本,而不是基线版本。 如上所述,基线为所有软件包设置了最低版本限制,因此,如果你尝试添加一个低于基线的约束,则该约束将被升级。

关于约束的一个重要注意事项是,它们在基线和替代项不存在的情况下是可传递的。图中的依赖项可以表达自己的约束,版本解析算法将考虑它们。

但是,如果你确实需要将版本设置为低于基准,该怎么办? 如何在不降低基准的情况下做到这一点? 对于这些情况,可以使用替代。

Overrides

Overrides会强制vcpkg使用特定版本,同时忽略所有其他约束(显式或传递性)。 这使用户可以解决某些特定情况,例如:
> 降级版本低于基准。
> 在传递依赖项上强制升级/降级版本。
> 解决不同软件包之间的版本冲突。
在该图所示的场景中,给出了我们对基线,约束和替代的全部了解。 我们可以看到,使用所有四个软件包的项目的版本解析将导致:
FMT:版本7.1.2,通过约束指定。
zlib:端口修订版2的版本1.2.11(通过覆盖指定)。
Boost:版本1.74,由基线默认设置。
azure-core-cpp:版本2020-09-01(基线默认设置)。

版本和自定义ports

最后要讨论的是覆盖ports如何与版本控制解析的交互。
答案是:它们根本不会做任何交互。更详细地讲,当你为一个port提供覆盖时,vcpkg将始终使用覆盖ports,而无需关心其中包含的版本。
原因有两个:
(1)与覆盖ports的现有行为一致(完全掩盖了现有ports)
(2)覆盖ports没有(也不希望提供)足够的信息来支持vcpkg的版本控制特征。

总结

我希望,老大哥的包管理器越办越好。

最后

Microsoft Visual C++团队的博客是我非常喜欢的博客之一,里面有很多关于Visual C++的知识和最新的开发进展。大浪淘沙,如果你对Visual C++这门古老的技术还是那么感兴趣,则可以经常去他们那(或者我这)逛逛。
本文来自:《Take control of your vcpkg dependencies with versioning support》