{"id":27597,"date":"2021-02-18T01:54:07","date_gmt":"2021-02-18T01:54:07","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cppblog\/?p=27597"},"modified":"2024-04-01T17:55:08","modified_gmt":"2024-04-01T17:55:08","slug":"take-control-of-your-vcpkg-dependencies-with-versioning-support","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/take-control-of-your-vcpkg-dependencies-with-versioning-support\/","title":{"rendered":"Take control of your vcpkg dependencies with versioning support"},"content":{"rendered":"<p><em>Special thanks to Victor Romero for putting together the content for this blog post.<\/em><\/p>\n<p>We have an exciting new feature to announce in vcpkg: the long-awaited and highly requested package versioning! This feature makes it possible to install specific versions of dependencies and control installed versions over time. In order to use this feature, a <strong>vcpkg.json<\/strong> manifest file must be present in your repo to declare dependencies. Versioning is not currently available for libraries installed via the command line (i.e. <code>vcpkg install library_name<\/code> commands). The versioning feature is completely optional \u2013 you can choose not to specify library versions, and vcpkg will pick the most appropriate set of compatible versions for your dependencies from its baseline catalog. For now, we are considering this feature experimental. Please give us your feedback and let us know how we can improve.<\/p>\n<p>&nbsp;<\/p>\n<h3>Announcing package versioning support<\/h3>\n<p>For the past year we have been focusing our efforts on implementing highly requested features in vcpkg that will help our users in a wide variety of scenarios. Two such features are manifests and binary caching, <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/vcpkg-accelerate-your-team-development-environment-with-binary-caching-and-manifests\/\">which we announced some time ago<\/a>, and users have been successfully using them in their projects since then. Today, we are announcing support for another anticipated feature: Package versioning. With this feature users will be able to:<\/p>\n<ul>\n<li>Declare minimum version constraints on dependencies.<\/li>\n<li>Freeze dependencies at specific versions.<\/li>\n<li>Conveniently upgrade all declared dependencies at once via baselines.<\/li>\n<li>Get reproducible builds independent from the current state of the vcpkg ports registry.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h3>Getting started with versions<\/h3>\n<p>To enable versioning, you must turn on the \u201cversions\u201d feature flag. There are several ways to do this:<\/p>\n<ul>\n<li>Setting the <code>VCPKG_FEATURE_FLAGS<\/code> environment variable, example in Windows 10:<a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/versioning-feature-flag.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-27599\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/versioning-feature-flag.png\" alt=\"Image versioning feature flag\" width=\"1092\" height=\"307\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/versioning-feature-flag.png 1092w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/versioning-feature-flag-300x84.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/versioning-feature-flag-1024x288.png 1024w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/versioning-feature-flag-768x216.png 768w\" sizes=\"(max-width: 1092px) 100vw, 1092px\" \/><\/a><\/li>\n<li>Setting the <code>VCPKG_FEATURE_FLAGS<\/code> variable before invoking vcpkg in the command line (example in PowerShell):\n<code>$env:VCPKG_FEATURE_FLAGS=\"versions\"<\/code>\n<code>vcpkg install<\/code><\/li>\n<li>Passing the feature flags in the command line for vcpkg (example in PowerShell):\n<code>vcpkg --feature-flags=\"versions\" install<\/code><\/li>\n<\/ul>\n<p>In the example below, we will be using Visual Studio Code to create a simple CMake project that automatically reads a vcpkg manifest file and installs dependencies. You can do this in Visual Studio as well. For information on how to set up Visual Studio for use with vcpkg with manifests (for MSBuild or CMake), see <a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/vcpkg-accelerate-your-team-development-environment-with-binary-caching-and-manifests\/\">vcpkg: Accelerate your team development environment with binary caching and manifests<\/a>.<\/p>\n<h4>Example #1: Simple versioning<\/h4>\n<p>Begin by creating a folder with the following files:<\/p>\n<p><strong>vcpkg.json<\/strong><\/p>\n<pre class=\"prettyprint\">{\r\n\u00a0 \u00a0 \"name\": \"versions-test\",\r\n\u00a0 \u00a0 \"version\": \"1.0.0\",\r\n\u00a0 \u00a0 \"dependencies\": [\r\n\u00a0 \u00a0 \u00a0   {\r\n            \"name\": \"fmt\",\r\n\u00a0 \u00a0 \u00a0 \u00a0     \"version&gt;=\": \"7.1.3\"\r\n\u00a0 \u00a0 \u00a0 \u00a0 },\r\n\u00a0 \u00a0 \u00a0 \u00a0 \"zlib\"\r\n\u00a0 \u00a0 ],\r\n\u00a0 \u00a0 \"builtin-baseline\": \"b60f003ccf5fe8613d029f49f835c8929a66eb61\"\r\n}<\/pre>\n<p>vcpkg has new version declaration properties when you use manifests. Previously, you could only declare versions for your projects using the \u201cversion-string\u201d property. Now that versioning has come around, vcpkg is aware of some new versioning schemes.<\/p>\n<table style=\"width: 29.7662%;\">\n<tbody>\n<tr>\n<td style=\"width: 30.2663%;\"><strong>Version scheme<\/strong><\/td>\n<td style=\"width: 80.0773%;\"><strong>Description<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 30.2663%;\"><strong>version<\/strong><\/td>\n<td style=\"width: 80.0773%;\">Dot-separated numerals: <strong>1.0.0<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 30.2663%;\"><strong>version-semver<\/strong><\/td>\n<td style=\"width: 80.0773%;\">Compliant semantic versions: <strong>1.2.0, 1.2.1-rc<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 30.2663%;\"><strong>version-date<\/strong><\/td>\n<td style=\"width: 80.0773%;\">Dates in YYYY-MM-DD format: <strong>2021-01-01<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 30.2663%;\"><strong>version-string<\/strong><\/td>\n<td style=\"width: 80.0773%;\">Arbitrary strings: <strong>vista, xp<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>The selected versioning scheme has consequences in what vcpkg will allow as a valid version string and the rules for ordering versions. You can read more about versioning schemes in <a href=\"https:\/\/github.com\/microsoft\/vcpkg\/blob\/master\/docs\/users\/versioning.reference.md#version-schemes\">our documentation<\/a>.<\/p>\n<p>Second, we use the \u201c<code>version&gt;=<\/code>\u201d property to declare a minimum version constraint on <code>fmt<\/code>. Notice that we also declare a dependency on <code>zlib<\/code> without any version constraint.<\/p>\n<p>And lastly, we declare a \u201c<code>builtin-baseline<\/code>\u201d, the value of which is a commit SHA from the vcpkg repository.<\/p>\n<p>In our example, vcpkg will look inside commit <code>b60f003ccf5fe8613d029f49f835c8929a66eb61<\/code> and find what the latest versions of <code>fmt<\/code> and <code>zlib<\/code> at that point in time were:<\/p>\n<ul>\n<li><code>fmt 7.1.3<\/code><\/li>\n<li><code>zlib 1.2.11#9<\/code> (the #9 suffix indicates that this is the 9th version of this library build recipe)<\/li>\n<\/ul>\n<p>The set of libraries and versions listed above can be described as the baseline versions for the dependencies used in this project. Baseline versions get added as additional minimum version constraints when resolving package versions.<\/p>\n<p><strong>main.cpp<\/strong><\/p>\n<pre class=\"prettyprint\">#include &lt;fmt\/core.h&gt;\r\n#include &lt;zlib.h&gt;\r\n\r\nint main()\r\n{\r\n    fmt::print(\"fmt version is {}\\n\"\r\n               \"zlib version is {}\\n\",\r\n               FMT_VERSION, ZLIB_VERSION);\r\n    return 0;\r\n}<\/pre>\n<p><em>[Above] This is a simple single file program to test that dependencies are correctly installed.<\/em><\/p>\n<p><strong>CMakeLists.txt<\/strong><\/p>\n<pre class=\"prettyprint\">cmake_minimum_required(VERSION 3.18)\r\n\r\nset(VCPKG_FEATURE_FLAGS \"versions\")\r\nproject(versions-test CXX)\r\n\r\nadd_executable(main main.cpp)\r\n\r\nfind_package(ZLIB REQUIRED)\r\nfind_package(fmt CONFIG REQUIRED)\r\ntarget_link_libraries(main PRIVATE ZLIB::ZLIB fmt::fmt)<\/pre>\n<p><em>[Above] To use vcpkg manifests with a CMake project, it is necessary to add find_package and target_link_libraries functions to identify your dependencies in CMakeLists.txt. This experience is the same whether a package manager like vcpkg is being used or not. Including these lines makes it possible for dependencies to be included in builds.<\/em><\/p>\n<p><strong>.vscode\/settings.json<\/strong><\/p>\n<pre class=\"prettyprint\">{\r\n    \"cmake.configureSettings\": {\r\n        \"CMAKE_TOOLCHAIN_FILE\": \"D:\/vcpkg\/scripts\/buildsystems\/vcpkg.cmake\",\r\n        \"VCPKG_TARGET_TRIPLET\": \"x64-windows\"\r\n    }\r\n}<\/pre>\n<p><em>[Above] For Visual Studio Code, this is how to point a CMake project to the vcpkg CMake toolchain file. This file must be specified for any CMake project using vcpkg. Other IDEs or editors may have a different experience for pointing to CMake toolchain files.<\/em><\/p>\n<p>Next, generate the CMake cache using the Visual Studio Code <strong>CMake: Configure<\/strong> command:<\/p>\n<pre class=\"prettyprint\">[cmakefileapi-driver] Removing d:\/versions-test\/build\/CMakeCache.txt\r\n[proc] Executing command: \"C:\\Program Files\\CMake\\bin\\cmake.EXE\" --no-warn-unused-cli -DCMAKE_TOOLCHAIN_FILE:STRING=D:\/vcpkg\/scripts\/buildsystems\/vcpkg.cmake -DVCPKG_TARGET_TRIPLET:STRING=x64-windows -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -Hd:\/versions-test -Bd:\/versions-test\/build -G \"Visual Studio 16 2019\" -T host=x64 -A x64\r\n[cmake] -- Running vcpkg install\r\n[cmake] Detecting compiler hash for triplet x64-windows...\r\n[cmake] The following packages will be built and installed:\r\n[cmake]     fmt[core]:x64-windows -&gt; 7.1.3 -- D:\\vcpkg\\buildtrees\\versioning\\versions\\fmt\\d99b6a35e1406ba6b6e09d719bebd086f83ed5f3\r\n[cmake]     zlib[core]:x64-windows -&gt; 1.2.11#9 -- D:\\vcpkg\\buildtrees\\versioning\\versions\\zlib\\827111046e37c98153d9d82bb6fa4183b6d728e4<\/pre>\n<p><em>[Above] This is the output produced by the CMake command line when generating the CMake cache. In Visual Studio Code, with the CMake Tools extension installed, the cache can be generated with the &#8220;CMake: Configure&#8221; command.<\/em><\/p>\n<p>You will know that versioning is working if you notice the \u201c<code>&lt;path-to-vcpkg&gt;\/buildtrees\/versioning\/versions\/&lt;portname&gt;\/&lt;sha&gt;<\/code>\u201d pattern in the paths. The port files are being checked out by vcpkg for the declared versions at those locations.<\/p>\n<p>Lastly, run the program:<\/p>\n<pre class=\"prettyprint\">fmt version is 70103  \r\nzlib version is 1.2.11<\/pre>\n<h4>Example #2: Pinning older versions<\/h4>\n<p>Since baselines establish a version floor for all packages and explicit constraints get upgraded when they are lower than the baseline, we need another mechanism to downgrade versions past the baseline.<\/p>\n<p>The mechanism vcpkg provides for that scenario is overrides. When an override is declared on a package, vcpkg will ignore all other version constraints either directly declared in the manifest or from transitive dependencies. In short, overrides will force vcpkg to use the exact version declared, period.<\/p>\n<p>First, change your manifest to add an override on <code>fmt<\/code> and force vcpkg to use version 6.0.0:<\/p>\n<pre class=\"prettyprint\">{\r\n    \"name\": \"versions-test\",\r\n    \"version\": \"1.0.0\",\r\n    \"dependencies\": [\r\n        {\r\n            \"name\": \"fmt\",\r\n            \"version&gt;=\": \"7.1.3\"\r\n        },\r\n        \"zlib\"\r\n    ],\r\n    \"builtin-baseline\": \"b60f003ccf5fe8613d029f49f835c8929a66eb61\", \r\n    \"overrides\": [\r\n        { \"name\": \"fmt\", \"version\": \"6.0.0\" }\r\n    ]\r\n}<\/pre>\n<p>Next, delete your build folder, generate the CMake cache, and build again:<\/p>\n<pre class=\"prettyprint\">[cmake] -- Running vcpkg install\r\n[cmake] Detecting compiler hash for triplet x64-windows...\r\n[cmake] The following packages will be rebuilt:\r\n[cmake]     fmt[core]:x64-windows -&gt; 6.0.0 -- D:\\Work\\viromer\\versioning\\vcpkg\\buildtrees\\versioning\\versions\\fmt\\d99b6a35e1406ba6b6e09d719bebd086f83ed5f3<\/pre>\n<p>Lastly, run the program:<\/p>\n<pre class=\"prettyprint\">fmt version is 60000  \r\nzlib version is 1.2.11<\/pre>\n<h3>How versioning works in vcpkg<\/h3>\n<p>In the diagram below we depict the chronology of versions released for four different libraries: FMT, zlib, Boost and Azure\u2019s core C++ library.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/vcpkg-versioning-diagram.png\"><img decoding=\"async\" class=\"alignnone size-full wp-image-27634\" src=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/vcpkg-versioning-diagram.png\" alt=\"Image vcpkg versioning diagram\" width=\"784\" height=\"567\" srcset=\"https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/vcpkg-versioning-diagram.png 784w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/vcpkg-versioning-diagram-300x217.png 300w, https:\/\/devblogs.microsoft.com\/cppblog\/wp-content\/uploads\/sites\/9\/2021\/02\/vcpkg-versioning-diagram-768x555.png 768w\" sizes=\"(max-width: 784px) 100vw, 784px\" \/><\/a><\/p>\n<p>The vcpkg versioning system is comprised of the following pieces:<\/p>\n<h4>Baselines<\/h4>\n<p>To enable versioning, it is required that you set a baseline to a specific vcpkg commit. By selecting a baseline, you are selecting a snapshot of a certain point in time of the chronology.\nSetting the baseline will set a minimum version floor on all your dependencies, the minimum versions being the ones that existed at the selected snapshot. In the picture above, we would have version 7.1.0 for FMT, version 1.2.11 at port revision 9 for zlib, version 1.74.0 for Boost and the September 2020 release for Azure\u2019s Core C++ library.\nAn advantage of using baselines is that versions that are contemporary are more likely to be compatible. The main vcpkg registry does, after all, build all libraries it contains at the same time to try to ensure compatibility of the whole catalog at every commit.<\/p>\n<h4>Constraints<\/h4>\n<p>In contrast with baselines that set minimum versions for all packages, constraints allow you to specify a minimum version in a package-by-package basis.<\/p>\n<p>Constraints only allow you to upgrade versions further than those at the baseline. As stated above, the baseline sets a minimum version floor for all packages, so if you attempt to add a constraint that is lower than the baseline, the constraint will be upgraded.<\/p>\n<p>An important thing to notice about constraints is that they are transitive where baselines and overrides are not. Dependencies in the graph can express their own constraints and they will be considered by the version resolution algorithm.<\/p>\n<p>But what if you really need to set a version to be lower than the baseline? How can you do it without lowering the baseline? For those cases, you can use overrides.<\/p>\n<h4>Overrides<\/h4>\n<p>An override forces vcpkg to use a specific version while ignoring all other constraint (either explicit or transitive). This allows the user to solve some specific situations like:<\/p>\n<ul>\n<li>Downgrading versions lower than the baseline.<\/li>\n<li>Forcing upgraded\/downgraded versions on transitive dependencies.<\/li>\n<li>Solving version conflicts between different packages.<\/li>\n<\/ul>\n<p>In the scenario depicted in the diagram, given all that we know about baselines, constraints, and overrides. We can see that version resolution for a project using all four packages would result in:<\/p>\n<ul>\n<li>FMT: Version 7.1.2, as specified via constraint.<\/li>\n<li>zlib: Version 1.2.11 at port revision 2, as specified via override.<\/li>\n<li>Boost: Version 1.74, as defaulted by the baseline.<\/li>\n<li>azure-core-pp: Version 2020-09-01, as defaulted by the baseline.<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<h3>Versions and custom ports<\/h3>\n<p>The last thing to discuss is how overlay ports interact with versioning resolution. The answer is: they do not interact at all by design.\nGoing into more detail, when you provide an overlay for a port, vcpkg will always use the overlay port without caring what version is contained in it. The reasons are two-fold: (1) it is consistent with the existing behavior of overlay ports (completely masking the existing port), and (2) overlay ports do not (and are not expected to) provide enough information to power vcpkg&#8217;s versioning feature.<\/p>\n<p>If you want to have flexible port customization along with versioning features, you should consider making your own custom registry. See our <a href=\"https:\/\/github.com\/microsoft\/vcpkg\/blob\/master\/docs\/specifications\/registries-2.md\">registries specification for more details<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h3>Further reading<\/h3>\n<p>If you&#8217;re interested in delving deeper into the details of how versioning works we recommended that you read the <a href=\"https:\/\/github.com\/microsoft\/vcpkg\/blob\/master\/docs\/specifications\/versioning.md\">original versioning specification<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<h3>Give us your feedback!<\/h3>\n<p>Try out vcpkg by visiting our <a href=\"https:\/\/github.com\/microsoft\/vcpkg\/issues\">GitHub repo<\/a>. We welcome your feedback on the tool and the new features <a href=\"https:\/\/github.com\/microsoft\/vcpkg\/issues\">in our issue tracker<\/a>. To see what\u2019s next for vcpkg, including support for versioning and registries, <a href=\"https:\/\/aka.ms\/vcpkg\/roadmap\">check out our roadmap<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Special thanks to Victor Romero for putting together the content for this blog post. We have an exciting new feature to announce in vcpkg: the long-awaited and highly requested package versioning! This feature makes it possible to install specific versions of dependencies and control installed versions over time. In order to use this feature, a [&hellip;]<\/p>\n","protected":false},"author":1063,"featured_media":27634,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1,272],"tags":[273],"class_list":["post-27597","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cplusplus","category-vcpkg","tag-vcpkg"],"acf":[],"blog_post_summary":"<p>Special thanks to Victor Romero for putting together the content for this blog post. We have an exciting new feature to announce in vcpkg: the long-awaited and highly requested package versioning! This feature makes it possible to install specific versions of dependencies and control installed versions over time. In order to use this feature, a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/27597","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/1063"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=27597"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/27597\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/27634"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=27597"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=27597"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=27597"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}