{"id":107601,"date":"2022-12-19T07:00:00","date_gmt":"2022-12-19T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107601"},"modified":"2022-12-15T15:55:07","modified_gmt":"2022-12-15T23:55:07","slug":"20221219-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20221219-00\/?p=107601","title":{"rendered":"On the large number of ways of expressing Microsoft Visual C++ compiler versions"},"content":{"rendered":"<p>When you ask someone what version of the Microsoft Visual C++ compiler they&#8217;re using, or if somebody tells you &#8220;This feature requires version X of the Microsoft Visual C++ compiler&#8221;, you can get the answer is a large number of ways, because the Microsoft Visual C++ compiler has apparently decided that if one version number is good, then more must be better.<\/p>\n<p>The first version number that enters the picture is the name of the Visual Studio product the compiler comes with. This is probably something like &#8220;Visual Studio YYYY&#8221; for some year, like &#8220;Visual Studio 2019&#8221;.<\/p>\n<p>The next version number is the product version of that Visual Studio product. For example, &#8220;Visual Studio 2019 version 16.11.&#8221;<\/p>\n<p>The next version number is the platform toolset that you specify in your project file, like <code>&lt;PlatformToolset&gt;v142&lt;\/PlatformToolset&gt;<\/code>.<\/p>\n<p>Another version number is the actual toolchain version, like &#8220;14.29&#8221;.<\/p>\n<p>And then there&#8217;s the version number reported by the <code>_MSC_VER<\/code> predefined macro, like &#8220;1929&#8221;.<\/p>\n<p>On top of that is the version number reported by the <code>_MSC_FULL_VER<\/code> predefined macro, like &#8220;192930100&#8221;.<\/p>\n<p>And finally, there&#8217;s the version number reported by the compiler itself when you type <code>cl \/?<\/code>.<\/p>\n<p>How are all of these version numbers related?<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"border: solid 1px gray;\">Product name<\/td>\n<td>?<br \/>\n\u21d4<\/td>\n<td style=\"border: solid 1px gray;\">Product version<\/td>\n<td>?<br \/>\n\u21d4<\/td>\n<td style=\"border: solid 1px gray;\">Platform toolset<\/td>\n<td>?<br \/>\n\u21d4<\/td>\n<td style=\"border: solid 1px gray;\">Toolchain<\/td>\n<td>?<br \/>\n\u21d4<\/td>\n<td style=\"border: solid 1px gray;\"><code>_MSC_<wbr \/>VER<\/code><\/td>\n<td>?<br \/>\n\u21d4<\/td>\n<td style=\"border: solid 1px gray;\"><code>_MSC_<wbr \/>FULL_<wbr \/>VER<\/code><\/td>\n<td>?<br \/>\n\u21d4<\/td>\n<td style=\"border: solid 1px gray;\">Compiler banner<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Okay, let&#8217;s do the easy one first: <a href=\"https:\/\/learn.microsoft.com\/en-us\/cpp\/preprocessor\/predefined-macros?view=msvc-170#microsoft-specific-predefined-macros\"> The last three version numbers are related to each other in a straightforward way<\/a>. If the compiler&#8217;s self-reported version is <code>aa.bb.ccccc.dd<\/code>, then the <code>_MSC_VER<\/code> is <code>aabb<\/code> and the <code>_MSC_FULL_VER<\/code> is <code>aabbccccc<\/code>. In other words, <code>_MSC_VER = aa * 100 + bb<\/code> and <code>_MSC_FULL_VER = aa * 10000000 + bb * 100000 + cc<\/code> .<\/p>\n<p>Okay, so that lets us build a relationship among the last three boxes: The compiler banner is the basis for the other two.<\/p>\n<p>The first two boxes are also related, but in a less obvious way: The product name and product major version line up according to <a href=\"https:\/\/en.wikipedia.org\/wiki\/Visual_Studio#History\"> this table on Wikipedia<\/a>. For example, Visual Studio 2019 corresponds to product versions 16.*.<\/p>\n<p>The next two boxes also appear to be related, although I can&#8217;t find any official documentation to that effect. The platform toolset appears to be the letter &#8220;v&#8221;, followed by the toolchain major version, followed by the first digit of the minor version. For example, a toolchain version of &#8220;14.29&#8221; corresponds to a platform toolset of &#8220;v142&#8221;.<\/p>\n<p>That leaves three major categories: The Visual Studio product, the toolchain, and the compiler. These three categories follow their own path, so you have to use a cheat sheet to see how they correspond to each other.\u00b9<\/p>\n<p>Let&#8217;s build that cheat sheet. I got the raw data from <a href=\"https:\/\/en.wikipedia.org\/wiki\/Microsoft_Visual_C%2B%2B#Internal_version_numbering\"> this table on Wikipedia<\/a>, with gaps filled in from the archived <a href=\"https:\/\/learn.microsoft.com\/en-us\/visualstudio\/releases\/\"> Visual Studio release notes<\/a>.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"1\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<th>Name<\/th>\n<th>Product<\/th>\n<th>Toolset<\/th>\n<th>Toolchain<\/th>\n<th><code>_MSC_<br \/>\nVER<\/code><\/th>\n<th><code>_MSC_<br \/>\nFULL_<wbr \/>VER<\/code><\/th>\n<th>Compiler<\/th>\n<\/tr>\n<tr>\n<td rowspan=\"10\">Visual<br \/>\nStudio<br \/>\n2017<\/td>\n<td>15.0<\/td>\n<td rowspan=\"10\">v141<\/td>\n<td rowspan=\"3\">14.1<\/td>\n<td rowspan=\"3\">1910<\/td>\n<td rowspan=\"3\">1910xxxxx<\/td>\n<td rowspan=\"3\">19.10.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>15.1<\/td>\n<\/tr>\n<tr>\n<td>15.2<\/td>\n<\/tr>\n<tr>\n<td>15.3<\/td>\n<td rowspan=\"2\">14.11<\/td>\n<td rowspan=\"2\">1911<\/td>\n<td rowspan=\"2\">1911xxxxx<\/td>\n<td rowspan=\"2\">19.11.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>15.4<\/td>\n<\/tr>\n<tr>\n<td>15.5<\/td>\n<td>14.12<\/td>\n<td>1912<\/td>\n<td>1912xxxxx<\/td>\n<td>19.12.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>15.6<\/td>\n<td>14.13<\/td>\n<td>1913<\/td>\n<td>1913xxxxx<\/td>\n<td>19.13.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>15.7<\/td>\n<td>14.14<\/td>\n<td>1914<\/td>\n<td>1914xxxxx<\/td>\n<td>19.14.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>15.8<\/td>\n<td>14.15<\/td>\n<td>1915<\/td>\n<td>1915xxxxx<\/td>\n<td>19.15.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>15.9<\/td>\n<td>14.16<\/td>\n<td>1916<\/td>\n<td>1916xxxxx<\/td>\n<td>19.16.xxxxx<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"12\">Visual<br \/>\nStudio<br \/>\n2019<\/td>\n<td>16.0<\/td>\n<td rowspan=\"12\">v142<\/td>\n<td>14.20<\/td>\n<td>1920<\/td>\n<td>1920xxxxx<\/td>\n<td>19.20.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.1<\/td>\n<td>14.21<\/td>\n<td>1921<\/td>\n<td>1921xxxxx<\/td>\n<td>19.21.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.2<\/td>\n<td>14.22<\/td>\n<td>1922<\/td>\n<td>1922xxxxx<\/td>\n<td>19.22.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.3<\/td>\n<td>14.23<\/td>\n<td>1923<\/td>\n<td>1923xxxxx<\/td>\n<td>19.23.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.4<\/td>\n<td>14.24<\/td>\n<td>1924<\/td>\n<td>1924xxxxx<\/td>\n<td>19.24.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.5<\/td>\n<td>14.25<\/td>\n<td>1925<\/td>\n<td>1925xxxxx<\/td>\n<td>19.25.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.6<\/td>\n<td>14.26<\/td>\n<td>1926<\/td>\n<td>1926xxxxx<\/td>\n<td>19.26.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.7<\/td>\n<td>14.27<\/td>\n<td>1927<\/td>\n<td>1927xxxxx<\/td>\n<td>19.27.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.8<\/td>\n<td rowspan=\"2\">14.28<\/td>\n<td rowspan=\"2\">1928<\/td>\n<td rowspan=\"2\">1928xxxxx<\/td>\n<td rowspan=\"2\">19.28.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.9<\/td>\n<\/tr>\n<tr>\n<td>16.10<\/td>\n<td rowspan=\"2\">14.29<\/td>\n<td rowspan=\"2\">1929<\/td>\n<td rowspan=\"2\">1929xxxxx<\/td>\n<td rowspan=\"2\">19.29.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>16.11<\/td>\n<\/tr>\n<tr>\n<td rowspan=\"5\">Visual<br \/>\nStudio<br \/>\n2022<\/td>\n<td>17.0<\/td>\n<td rowspan=\"5\">v143<\/td>\n<td>14.30<\/td>\n<td>1930<\/td>\n<td>1930xxxxx<\/td>\n<td>19.30.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>17.1<\/td>\n<td>14.31<\/td>\n<td>1931<\/td>\n<td>1931xxxxx<\/td>\n<td>19.31.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>17.2<\/td>\n<td>14.32<\/td>\n<td>1932<\/td>\n<td>1932xxxxx<\/td>\n<td>19.32.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>17.3<\/td>\n<td>14.33<\/td>\n<td>1933<\/td>\n<td>1933xxxxx<\/td>\n<td>19.33.xxxxx<\/td>\n<\/tr>\n<tr>\n<td>17.4<\/td>\n<td>14.34<\/td>\n<td>1934<\/td>\n<td>1934xxxxx<\/td>\n<td>19.34.xxxxx<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>But wait, the story isn&#8217;t over yet.<\/p>\n<p>Internally, the compiler team delivers periodic compiler updates to the Windows team. These updates are named LKG followed by a number, like &#8220;LKG14&#8221;, and there is an internal Web site that maps LKG values to compiler version numbers. Fortunately, only people who work at Microsoft need to worry about these LKG version numbers.<\/p>\n<p><b>Bonus chatter<\/b>: The term LKG stands for &#8220;Last Known Good&#8221;, meaning that it is the latest version of the compiler that has been validated against the Windows code base. There is another term FKG, which you think might stand for &#8220;First Known Good&#8221;, but it doesn&#8217;t. It originally stood for &#8220;Fast Known Good&#8221; because it contained compilers even newer than the Last Known Good. That policy has changed, and now the FKG is used for other purposes, but the name FKG stuck, even though it&#8217;s completely wrong.<\/p>\n<p>\u00b9 It appears that starting in Visual Studio 2017, the compiler minor version increases by one each time the toolchain minor version increases by one, so that&#8217;s handy. Starting in August 2017, the compiler version is equal to the toolchain version plus five. I don&#8217;t know whether this is a rule or a coincidence.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So many version numbers.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[26],"class_list":["post-107601","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>So many version numbers.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107601","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=107601"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107601\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=107601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}