背景
在实际项目中,您的项目代码需要依赖第三方库的历史版本,以往的做法是将vcpkg回退到需要使用的版本,或者是自定义版本,这会导致其他的库也回退到以前的版本。 现在vcpkg提供了versioning 特性,可以方便地解决这个问题。Versioning 特性是默认开启的,不需要额外的设置来启用。注意:此特性依赖于manifest模式,使用这个特性前请先了解manifest特性。
使用示例
1. 创建一个简单的cmake工程, 然后让它依赖于 fmt 和 zlib, 假设需要依赖fmt版本大于等于 7.1.3。 创建文件夹 versioning 并包含以下3个文件 vcpkg.json,main.cpp, CMakeLists.txt:
vcpkg.json:
{ "name": "versions-test", "version": "1.0.0", "dependencies": [ { "name": "fmt", "version>=": "7.1.3" }, "zlib" ], "builtin-baseline": "99dc49dae7e170c3be63dd097230007f3bb73c4f" }
main.cpp:
#include <fmt/core.h> #include <zlib.h> int main() { fmt::print("fmt version is {}\n" "zlib version is {}\n", FMT_VERSION, ZLIB_VERSION); return 0; }
CMakeLists.txt:
cmake_minimum_required(VERSION 3.18) project(versionstest CXX) add_executable(main main.cpp) find_package(ZLIB REQUIRED) find_package(fmt CONFIG REQUIRED) target_link_libraries(main PRIVATE ZLIB::ZLIB fmt::fmt)
现在可以构建和运行cmake工程:
1. 创建cmake工程构建目录:
E:\vcpkg\vcpkgtest\versioning>mkdir build E:\vcpkg\vcpkgtest\versioning>cd build
2. 配置CMake工程:
cmake -G "Visual Studio 16 2019" -DVCPKG_TARGET_TRIPLET=x64-windows "-DCMAKE_TOOLCHAIN_FILE=E:/vcpkg/vcpkg_debug/vcpkg/scripts/buildsystems/vcpkg.cmake" ..
E:\vcpkg\vcpkgtest\versioning\build>cmake -G "Visual Studio 16 2019" "-DCMAKE_TOOLCHAIN_FILE=E:/vcpkg/vcpkg_debug/vcpkg/scripts/buildsystems/vcpkg.cmake" .. -- Running vcpkg install Detecting compiler hash for triplet x64-windows... A suitable version of powershell-core was not found (required v7.1.3). Downloading portable powershell-core v7.1.3... Extracting powershell-core... The following packages will be built and installed: fmt[core]:x64-windows -> 7.1.3 -- E:\vcpkg\vcpkg_debug\vcpkg\buildtrees\versioning\versions\fmt\dd8cf5e1a2dce2680189a0744102d4b0f1cfb8b6 zlib[core]:x64-windows -> 1.2.11#9 -- E:\vcpkg\vcpkg_debug\vcpkg\buildtrees\versioning\versions\zlib\827111046e37c98153d9d82bb6fa4183b6d728e4 Using cached binary package: C:\Users\phoebe\AppData\Local\vcpkg\archives\c1\c1284fcdc26b903209c61a3a1cdaf0c511f63183f33d6586b7012a778638af17.zip Could not locate cached archive: C:\Users\phoebe\AppData\Local\vcpkg\archives\66\6651ef3a357c7ae220bedb6037b75b52421c637c7ecce7da40b8ac8a5067686c.zip Starting package 1/2: fmt:x64-windows … Stored binary cache: C:\Users\phoebe\AppData\Local\vcpkg\archives\66\6651ef3a357c7ae220bedb6037b75b52421c637c7ecce7da40b8ac8a5067686c.zip Building package zlib[core]:x64-windows... done Installing package zlib[core]:x64-windows... Installing package zlib[core]:x64-windows... done Elapsed time for package zlib:x64-windows: 12.73 s Total elapsed time: 13.39 s -- Running vcpkg install - done -- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19043. -- The CXX compiler identification is MSVC 19.28.29915.0 -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Community/VC/Tools/MSVC/14.28.29910/bin/Hostx64/x64/cl.exe - skipped -- Detecting CXX compile features -- Detecting CXX compile features - done -- Found ZLIB: optimized;E:/vcpkg/vcpkgtest/versioning/build/vcpkg_installed/x64-windows/lib/zlib.lib;debug;E:/vcpkg/vcpkgtest/versioning/build/vcpkg_installed/x64-windows/debug/lib/zlibd.lib (found version "1.2.11") -- Configuring done -- Generating done -- Build files have been written to: E:/vcpkg/vcpkgtest/versioning/buildOutput
3. 构建cmake工程:
E:\vcpkg\vcpkgtest\versioning\build>cmake --build . Microsoft (R) Build Engine version 16.9.0+5e4b48a27 for .NET Framework Copyright (C) Microsoft Corporation. All rights reserved. Checking Build System Building Custom Rule E:/vcpkg/vcpkgtest/versioning/CMakeLists.txt main.cpp main.vcxproj -> E:\vcpkg\vcpkgtest\versioning\build\Debug\main.exe Building Custom Rule E:/vcpkg/vcpkgtest/versioning/CMakeLists.txt
4. 运行cmake工程:
E:\vcpkg\vcpkgtest\versioning\build>.\Debug\main.exe fmt version is 70103 zlib version is 1.2.11
请重点关注以下输出:
fmt[core]:x64-windows -> 7.1.3 -- E:\vcpkg\vcpkg_debug\vcpkg\buildtrees\versioning\versions\fmt\dd8cf5e1a2dce2680189a0744102d4b0f1cfb8b6 zlib[core]:x64-windows -> 1.2.11#9 -- E:\vcpkg\vcpkg_debug\vcpkg\buildtrees\versioning\versions\zlib\827111046e37c98153d9d82bb6fa4183b6d728e4
可以看到 fmt选用了7.1.3版本, 而不是使用了本地 .\ports\fmt 提供的版本。注意:cmake3.18 及以后的版本才支持输出日志到命令框。如果使用cmake 3.18之前的版本,则需要从当前目录vcpkg-manifest-install.log 文件查看输出信息。
Versioning 字段
下面介绍versioning特性中涉及到的3个关键字段:
overrides
如果想指定fmt的版本,例如6.0.0, 而不是自动从baseline中查找,可以通过添加overrides去实现。它会覆盖任何其他的配置,而使用指定的 6.0.0 版本,这个方式对于解决版本之间的冲突问题特别实用。示例:
vcpkg.json 文件:
{ "name": "versions-test", "version": "1.0.0", "dependencies": [ { "name": "fmt", "version>=": "7.1.3" }, "zlib" ], "builtin-baseline": "99dc49dae7e170c3be63dd097230007f3bb73c4f", "overrides": [ { "name": "fmt", "version": "6.0.0" } ] }
builtin-baseline
关注以上示例中的zlib,可以发现 vcpkg.json 文件中并没有声明任何版本,它使用的版本为1.2.11#9,这个版本其实就是来源于 builtin-baseline。以下是获取 builtin-baseline 的方法:
1. builtin-baseline 实际上是vcpkg仓库包含的 commit id,实际操作中我们可以通过执行以下git命令来获取vcpkg库最新的 commit id:
git rev-parse HEAD
实际上,vcpkg是通过以下命令来获取该commit中包含的baseline.json 文件版本。
git show 99dc49dae7e170c3be63dd097230007f3bb73c4f:versions/baseline.json
2. 若需要查找某个库对应的历史版本,可以使用以下命令:
vcpkg x-history PORT_NAME
注意:只能选择 date > 1/22/2021 以后的 version 所对应的 vcpkg commit, 将其设置为 builtin-baseline。这是因为在这之后,vcpkg才支持versioning特性,才有 baseline.json 文件。 例如:
E:\vcpkg\clean\vcpkg> ./vcpkg x-history fmt version date vcpkg commit 7.1.3#5 2021-07-01 9a7d5a29dd0e066ff4a7dbeba4bd8af4daae8b60 7.1.3#4 2021-04-28 345921bce4ee724d4c5b164eb93d051667d2d990 7.1.3#3 2021-04-07 5f77fef68d9f2f5ddc921432914dcbf92b31e989 7.1.3#2 2021-03-18 c8f6537b80831b1bd951b764bb4fa1f1c7973d83 7.1.3#1 2021-02-28 3426db05b996481ca31e95fff3734cf23e0f51bc 7.1.3#0 2020-11-30 1380e8fd4aabfb502023fb8c640fb7b5d73834e9 7.1.2#0 2020-11-06 d218ca7e6f6eab8679d2e968b43a208e689ac920 7.1.1#0 2020-11-03 c4c020828aa1b743707876ffaeb0dccf091e96f5 7.1.0#0 2020-10-26 c31cfd3c81a792d7073e71e8e4f9ab604f0f305e 7.0.3#3 2020-10-08 54dbd5ca9e808d3437a364c434bff7c6621f42ae 7.0.3#2 2020-09-04 d951a0033260a63e8d82c64ee1514b1c53364b55 7.0.3#0 2020-08-07 fbb5131bbc6a66d3950fdd44fbeca85d67fb0ff0 7.0.2#0 2020-08-06 4f9117c0dea8e58be6dc4102e40238f57b7b8533 6.2.1#0 2020-06-11 8d399bd86b94fdb4abf8d5c56f2a94b2d3aefda5 6.2.0-1#0 2020-06-02 c5c350086508005af936a185949e910bfda2821d 6.2.0#0 2020-04-09 279867cb0c22b1251c5dd50f2dc17030ed9861c9 6.1.2#0 2020-03-02 705764c63549953c049b34c7a2d67b377d0bd006 6.0.0-1#0 2020-01-06 153cab79c76175118f5b5d28135a57e00ae75a8d 6.0.0#0 2019-08-27 8b7f940d82f829bb7d6dbf986225d69b07cbcb40 5.3.0-2#0 2019-06-15 18b029a5e3997fa4fdc7d3d06d56568a1d6f74ad 5.3.0-1#0 2019-03-16 d7bf0e581942fca27ef9bf79c6684c8d19ae1967 5.3.0#0 2019-01-14 e86780d75ffb4476f58c725d40e2456eb503b766 5.2.1#0 2018-10-25 9c62c6a37ac940abbb4f19237d9a891881421a1a 5.2.0#0 2018-09-19 64a7483a4a4c9d176896ec7aec08a6acef4ea8f3 5.1.0#0 2018-07-10 0606add12f907733deba699611eb8692c6c4be9e 5.0.0-1#0 2018-06-28 3a5b12004e4d9854f4a44337d5fa986b910c6bd6 5.0.0#0 2018-05-29 b82bbc4945a550c070af351fd769885047b54557 4.1.0#0 2017-12-26 178517052f42d428bb2f304946e635d3c1f318e9 4.0.0-1#0 2017-09-09 26516fe485b0e9048dd4809256a7e4526957c6e9 4.0.0#0 2017-06-27 0ee8ad5cb2ed21731885fa40bd0e2776eec39c71 3.0.2#0 2017-06-15 2752e690b9230e8078d0688f0b9830874d0662df 3.0.1-4#0 2017-02-09 43665857a3ad11de8135c7fd6cd9839269212d7d 3.0.1-3#0 2017-02-03 95af9aac7c39765d1524b7c9c39dc283e9f0facf 3.0.1-2#0 2017-02-02 62e7557545c17462670b7741d74dd2db4f5612eb 3.0.1-1#0 2017-01-10 4f5f52ff470e83fa041ac4c6797bfa4e61ed2501 3.0.1#0 2016-11-22 1f22f927e2f2ba1eb8c702ced4bc6ad811da2bdc 3.0.0-1#0 2016-11-10 b56819ec88f85d401160197b578b508916ac9962 3.0.0#0 2016-09-28 36799555441089420f29fcb2724d9fde23bc9ec1vcpkg x-history fmt
builtin-baseline 具体作用过程:
1. 从给定的 builtin-baseline(commit id)版本中查找是否含有 baseline.json 文件,如果有,就从这个文件中查找该库的版本。
2. 如果没有baseline.json,就会报错。
3. 如果有baseline.json,但是它不包含库的历史版本,也会报错。
version>=
以上示例中,zlib 的版本号 1.2.11#9 是由 version 和 port-version 两部分组成,version(1.2.11) 是zlib的实际的版本号,port-version(9) 是这个版本在vcpkg中的补丁版本。两者组合可以获取该库在vcpkg中的具体版本。
当version 版本更新时,port-version 重置为0 ,每次改动都加1。如上图所示,记录中从上到下显示了fmt版本的补丁修正与版本更新。
在vcpkg中,版本是如何比较大小呢?实际是比较版本的新旧,例如:
1.2.0 < 1.2.0#1 < 1.2.0#2 < 1.2.0#10 2021-01-01#20 < 2021-01-01.1 windows#7 < windows#8
注意:
1. Version>= 主要用于表示需要使用的最低版本,只有作为 "dependencies"的一部分时才是被允许的。
2. 如果使用Version>=, vcpkg会从所有满足条件的版本中选用最低版本,这种做法的好处是更新vcpkg时,避免依赖升级出现异常的问题。可以总结为:
如果使用 overrides,那么会使用 overrides 提供的版本,例如 fmt 6.0.0。如果没有,会选择 version>= 和 builtin-baseline 中最高的版本,例如:
version>= 7.1.3 + builtin-baseline(7.1.4) , 会安装 fmt 7.1.4;
version>= 7.1.3 + builtin-baseline(7.1.2) , 会安装 fmt 7.1.3。
3. Vcpkg允许升级版本,例如: 如果zlib依赖fmt,而且声明依赖fmt 的 7.1.4 版本,那么vcpkg就会安装 7.1.4 版本,而不是 7.1.3。
4. 在您的项目中,如果想升级依赖库的版本,只需把最低版本改掉,或者是把 builtin-baseline 改为更新的版本。
5. Vcpkg 不会比较version类型不同的版本,例如:同一个库的2 个版本 ‘version-string: 7.1.3’ 与 `version: 7.1.4`,version 类型不同,所以不能比较。
Versions 文件
在vcpkg 的仓库中,文件夹https://github.com/microsoft/vcpkg/tree/master/versions 目录下,有baseline.json文件及对应 portname.json 文件。
例如 zlib:baseline.json 文件包含zlib 当前最新的版本,versions/z-/zlib.json 中包含vcpkg 中 zlib的所有可选版本:
{ "versions": [ { "git-tree": "53a4615c8bb9b98a3864b834a6bbe51cc6c849ef", "version-string": "1.2.11", "port-version": 10 }, { "git-tree": "827111046e37c98153d9d82bb6fa4183b6d728e4", "version-string": "1.2.11", "port-version": 9 } }
示例中git-tree是 SHA 哈希值,是由 以下 git 命令获取的:
git rev-parse <commit>:<path>
E:\vcpkg\vcpkg_debug\vcpkg> git rev-parse HEAD:ports/zlib 53a4615c8bb9b98a3864b834a6bbe51cc6c849ef
每次更新时,只需要执行 'vcpkg x-add-version zlib' 或者 'vcpkg x-add-version --overwrite-version zlib' 会自动更新zlib.json文件,不需要手动获取git-tree SHA 哈希值。可以使用 'vcpkg x-add-version --all' 去更新所有port的版本。
参考:
https://github.com/microsoft/vcpkg/blob/master/docs/examples/versioning.getting-started.md
https://github.com/microsoft/vcpkg/blob/master/docs/users/versioning.md