Repository: conan-io/conan
Pull request #15588 (2024-02-02 20:57:43)

fix for msvc toolset version overflow
Changelog: Fix: Fix for future ``msvc`` toolset version overflow
Docs: Omit

After https://github.com/conan-io/conan/pull/15947

Close https://github.com/conan-io/conan/issues/15583
Close https://github.com/conan-io/conan/issues/16239

memsharded: @jcar87 I have proposed a full ``compiler.version=194`` => VS 17 2022 mapping, please review and lets discuss
Nekto89: I've tried this branch locally with VS2022 Update 10 Preview 6 + CMake 3.29.2 and it doesn't work

```
conan install --remote conancenter --requires=sqlite3/3.45.3 --build=sqlite3/3.45.3 -pr:b test_profile -pr:h test_profile

======== Input profiles ========
Profile host:
[settings]
arch=x86_64
build_type=Release
compiler=msvc
compiler.cppstd=17
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.update=0
compiler.version=194
os=Windows
[conf]
tools.cmake.cmaketoolchain:generator=Visual Studio 17 2022

Profile build:
[settings]
arch=x86_64
build_type=Release
compiler=msvc
compiler.cppstd=17
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.update=0
compiler.version=194
os=Windows
[conf]
tools.cmake.cmaketoolchain:generator=Visual Studio 17 2022


======== Computing dependency graph ========
sqlite3/3.45.3: Not found in local cache, looking in remotes...
sqlite3/3.45.3: Checking remote: conancenter
sqlite3/3.45.3: Downloaded recipe revision 1b6b291b7d3730cef1f0264370964d2c
Graph root
    cli
Requirements
    sqlite3/3.45.3#1b6b291b7d3730cef1f0264370964d2c - Downloaded (conancenter)

======== Computing necessary packages ========
sqlite3/3.45.3: Forced build from source
Requirements
    sqlite3/3.45.3#1b6b291b7d3730cef1f0264370964d2c:a1ba2c5fa80c7ce590ee96bd34de63fd16172f7f - Build

======== Installing packages ========
sqlite3/3.45.3: Sources downloaded from 'conancenter'
sqlite3/3.45.3: Calling source() in D:\conan2s\sqlitcfd8cb20ebdfc\s\src
sqlite3/3.45.3: Unzipping 10.6MB, this can take a while
Unzipping 100 %

-------- Installing package sqlite3/3.45.3 (1 of 1) --------
sqlite3/3.45.3: Building from source
sqlite3/3.45.3: Package sqlite3/3.45.3:a1ba2c5fa80c7ce590ee96bd34de63fd16172f7f
sqlite3/3.45.3: Copying sources to build folder
sqlite3/3.45.3: Building your package in D:\conan2s\b\sqlit36f41fbbdecce\b
sqlite3/3.45.3: Calling generate()
sqlite3/3.45.3: Generators folder: D:\conan2s\b\sqlit36f41fbbdecce\b\build\generators
sqlite3/3.45.3: CMakeToolchain generated: conan_toolchain.cmake
sqlite3/3.45.3: CMakeToolchain generated: D:\conan2s\b\sqlit36f41fbbdecce\b\build\generators\CMakePresets.json
sqlite3/3.45.3: Generating aggregated env files
sqlite3/3.45.3: Generated aggregated env files: ['conanbuild.bat', 'conanrun.bat']
sqlite3/3.45.3: Calling build()
sqlite3/3.45.3: Running CMake.configure()
sqlite3/3.45.3: RUN: cmake -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE="generators/conan_toolchain.cmake" -DCMAKE_INSTALL_PREFIX="D:/conan2s/b/sqlit36f41fbbdecce/p" -DCMAKE_POLICY_DEFAULT_CMP0091="NEW" "D:/conan2s/b/sqlit36f41fbbdecce/b/src/.."
-- Using Conan toolchain: D:/conan2s/b/sqlit36f41fbbdecce/b/build/generators/conan_toolchain.cmake
-- Conan toolchain: CMAKE_GENERATOR_TOOLSET=v144,version=14.40
-- Conan toolchain: Setting BUILD_SHARED_LIBS = OFF
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
CMake Error at CMakeLists.txt:2 (project):
  Failed to run MSBuild command:

    C:/Program Files/Microsoft Visual Studio/2022/Professional/MSBuild/Current/Bin/amd64/MSBuild.exe

  to get the value of VCTargetsPath:

    MSBuild version 17.10.4+10fbfbf2e for .NET Framework
    Build started 5/3/2024 10:49:18 AM.

    Project "D:\conan2s\b\sqlit36f41fbbdecce\b\build\CMakeFiles\3.29.2\VCTargetsPath.vcxproj" on node 1 (default targets).
    C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Microsoft\VC\v170\Microsoft.CppBuild.targets(456,5): error MSB8020: The build tools for v144 (Platform Toolset = 'v144') cannot be found. To build using the v144 build tools, please install v144 build tools.  Alternatively, you may upgrade to the current Visual Studio tools by selecting the Project menu or right-click the solution, and then selecting "Retarget solution". [D:\conan2s\b\sqlit36f41fbbdecce\b\build\CMakeFiles\3.29.2\VCTargetsPath.vcxproj]
    Done Building Project "D:\conan2s\b\sqlit36f41fbbdecce\b\build\CMakeFiles\3.29.2\VCTargetsPath.vcxproj" (default targets) -- FAILED.

    Build FAILED.

    "D:\conan2s\b\sqlit36f41fbbdecce\b\build\CMakeFiles\3.29.2\VCTargetsPath.vcxproj" (default target) (1) ->
    (PrepareForBuild target) ->
      C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Microsoft\VC\v170\Microsoft.CppBuild.targets(456,5): error MSB8020: The build tools for v144 (Platform Toolset = 'v144') cannot be found. To build using the v144 build tools, please install v144 build tools.  Alternatively, you may upgrade to the current Visual Studio tools by selecting the Project menu or right-click the solution, and then selecting "Retarget solution". [D:\conan2s\b\sqlit36f41fbbdecce\b\build\CMakeFiles\3.29.2\VCTargetsPath.vcxproj]

        0 Warning(s)
        1 Error(s)

    Time Elapsed 00:00:00.20


  Exit code: 1



-- Configuring incomplete, errors occurred!

sqlite3/3.45.3: ERROR:
Package 'a1ba2c5fa80c7ce590ee96bd34de63fd16172f7f' build failed
sqlite3/3.45.3: WARN: Build folder D:\conan2s\b\sqlit36f41fbbdecce\b\build
ERROR: sqlite3/3.45.3: Error in build() method, line 159
        cmake.configure(build_script_folder=os.path.join(self.source_folder, os.pardir))
        ConanException: Error 1 while executing
```

What exactly should be used in profile?
memsharded: I am not sure what would be the issue, Conan seems to be doing the right thing, and using ``v144`` which is the version that Microsoft documents to be used, but for some reason it is not being found? Maybe Microsoft didn't explain this correctly?

> ERROR: Invalid setting '10' is not a valid 'settings.compiler.update' value.
Possible values are ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

Yes, this is expected, 193+10 doesn't exist, it is 194+0 because Conan models the compiler version, not the IDE update version

Nekto89: > I am not sure what would be the issue, Conan seems to be doing the right thing, and using `v144` which is the version that Microsoft documents to be used, but for some reason it is not being found? Maybe Microsoft didn't explain this correctly?
> 
> > ERROR: Invalid setting '10' is not a valid 'settings.compiler.update' value.
> > Possible values are ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
> 
> Yes, this is expected, 193+10 doesn't exist, it is 194+0 because Conan models the compiler version, not the IDE update version

in CMake you need to still use v143 for new update
v143,version=14.40 / v143,version=14.40.17.10 / v143,version=14.40.17.10,host=x64
memsharded: > in CMake you need to still use v143 for new update

But that doesn't make sense? Microsoft documented the right toolset is v144, isn't it?
Nekto89: > > in CMake you need to still use v143 for new update
> 
> But that doesn't make sense? Microsoft documented the right toolset is v144, isn't it?

![image](https://github.com/conan-io/conan/assets/4276548/a3f3dabc-ebbe-43f2-a451-ae824b945c45)

memsharded: Oh, you are right, thanks very much for pointing this!

I have just uploaded a fix, could you please re-try?
Nekto89: > Oh, you are right, thanks very much for pointing this!
> 
> I have just uploaded a fix, could you please re-try?

With fix conan has successfully built sqlite3 with proper toolset `compiler.version=194` `compiler.update=0`
```
-- Conan toolchain: CMAKE_GENERATOR_TOOLSET=v143,version=14.40
-- Conan toolchain: Setting BUILD_SHARED_LIBS = OFF
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The C compiler identification is MSVC 19.40.33808.0
```
jcar87: Thanks for testing @Nekto89 

Indeed the compiler with "MSVC toolset 19.40.xxx" is still part of the `v143` platform toolset.

@memsharded I think it looks okay now, but I will double check the activation of vcvars, and the ability to force the 193 compiler version when the 19.4 is also available (and would otherwise be picked up by default)

There is another place that is worth looking into:
https://github.com/conan-io/conan/blob/a56c6395d6b039184859726d37b854cd1ab84256/conan/tools/microsoft/visual.py#L132-L135

The code there parses the `compiler.runtime_version` setting, which is only optionally when the compiler is `clang` on Windows - but now we can't disambiguate whether the vcvars need to be for `193` or `194`. I would probably consider checking which update is installed and available, and use the most recent? Otherwise, using the `193` runtime should be compatible _anyway_, so it is the safest choice, but I would then leave a comment.
jcar87: Tested:

* `conan profile detect` detects `194` when the preview is installed ✅

* When consuming a package with `compiler.version=194`, and a binary exists for `193` but not for `194`, it falls back to finding the compatible binary: ✅

```
======== Computing necessary packages ========
zlib/1.3.1: FACTORS [[{'compiler.version': '193'}]]
zlib/1.3.1: COMbINATIONS [{'compiler.version': '193'}]
zlib/1.3.1: Checking 1 compatible configurations
zlib/1.3.1: Main binary package 'bf083199c71b5d660bf9523713b0cd79bc0919fb' missing. Using compatible package 'ea5dc84deb25b32a77ec23c39a1811e3f441ee54': compiler.version=193
``` 

* Creating a package with `compiler.version=194` results in CMake picking up v143 toolset with the `19.40` compiler ❌
What I get instead:
```
-- Using Conan toolchain: C:/xxx/conan-center-index/recipes/zlib/all/test_package/build/msvc-194-armv8-14-release/generators/conan_toolchain.cmake
-- Conan toolchain: CMAKE_GENERATOR_TOOLSET=v143
-- Conan toolchain: C++ Standard 14 with extensions OFF
-- The C compiler identification is MSVC 19.39.33523.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/bin/Hostarm64/arm64/cl.exe - skipped
```

Here there seem to be multiple factors at play:
* the `CMakeToolchain` generators only appends the version `,version=14.xx` when we have `compiler.update` set. But if we only have `compiler.version=194` and no update, we don't provide additional information - leaving CMake to detect its own
* In absence of (1), CMake says it chooses a default: https://cmake.org/cmake/help/latest/variable/CMAKE_VS_PLATFORM_TOOLSET_VERSION.html#variable:CMAKE_VS_PLATFORM_TOOLSET_VERSION - it doesn't say it chooses the "latest", only that it chooses a default.
* CMake is choosing the VS 17.9 instance, rather than the 17.10 preview - so even if I define the `compiler.update` setting, it won't find it, unless I also pass `CMAKE_GENERATOR_INSTANCE` set to `C:/Program Files/Microsoft Visual Studio/2022/Preview`

* It looks like even in Microsoft tools,  the "default" for platform toolset 143 is still 19.39 - unsure if this only during the preview, or if I have a bad installation. However I can see evidence that "default" is not always the latest: https://developercommunity.visualstudio.com/t/Default-value-of-MSVC-Toolset-is-not-doc/10398953, 
    

Only when using `CMAKE_GENERATOR_INSTANCE` so that CMake uses the Visual Studio 2022 Update 10 preview:
* Without defining the `compiler.update` setting, CMake still detects and uses the 19.39 compiler, even if the `compiler.version=194`
* Setting `compiler.version=193` and `compiler.update=0` AND setting then CMake detects the correct compiler (19.40)


A meson-toolchain recipe seems fine, which also instantiates vcvars:

```
conanvcvars.bat: Activating environment Visual Studio 17 - amd64_arm64 - winsdk_version=None - vcvars_ver=14.4
[vcvarsall.bat] Environment initialized for: 'x64_arm64'
The Meson build system
Version: 1.2.2

Build type: cross build
..\src\meson.build:1: WARNING: Keyword argument "default_options" defined multiple times.
WARNING: This will be an error in future Meson releases.
Project name: pkgconf
Project version: 2.2.0
C compiler for the host machine: cl (msvc 19.40.33808 "Microsoft (R) C/C++ Optimizing Compiler Version 19.40.33808 for ARM64")
C linker for the host machine: link link 14.40.33808.0
C compiler for the build machine: cl (msvc 19.40.33808 "Microsoft (R) C/C++ Optimizing Compiler Version 19.40.33808 for ARM64")
C linker for the build machine: link link 14.40.33808.0
```
jcar87: if my understanding is correct, there are some scenarios


### A user that has side-by-side installations of VS2022 and VS2022.10 preview:

##### A) User runs `conan profile detect`
* `conan profile detect` will detect `compiler.version=194`
* But CMake will not even consider the preview installation, and will use the `19.3x` compiler regardless (with no error) -  all binaries still work, but it's not the newer compiler - this is wrong

#### B) User still has a profile with `compiler.version=193`
Everything works fine, both CMake and conan profile "agree"

#### C) User has a profile with `compiler.version=194` and `compiler.update=0`
CMake will fail. 

### User only has Visual Studio 2022.10 preview installed OR tells cmake which installation to use via `CMAKE_GENERATOR_INSTANCE`

##### A) User runs `conan profile detect`
* `conan profile detect` will detect `compiler.version=194`
* CMake detects the preview installation, but _still_ picks up the `19.3x` compiler - this seems to be the current default set in Visual Studio altogether - everything builds and works, but it's not using the `19.4x` compiler

#### B) User has a profile with `compiler.version=194` and `compiler.update=0`
This works fine - Conan passes `v143,version=14.40` as the generator toolset, and it uses the new compiler version.

#### C) User still has a profile with `compiler.version=193`
This is "correct" - since CMake uses the 19.3x MSVC toolset by default, however, if upon release it moves to use 19.4x instead, then this would be wrong.


As it stands, I wouldn't merge this PR - all the right things are there, but
* `conan profile detect` assumes `compiler.version=194` if Update 10 is installed - but unsure it is the default version
* If the Preview is installed side by side with a released version, CMake defaults to the release 
* If preview is installed on its own or we tell CMake to use it, CMake _still_ picks up the 19.3x toolset in the abscence of `compiler.update` being defined.

All the right things are there - but at the moment if the  update 10 is using the `19.3x` toolset as the default, nothing is wrong - I would reassess on release



Nekto89: >     * If preview is installed on its own or we tell CMake to use it, CMake _still_ picks up the 19.3x toolset in the abscence of `compiler.update` being defined.

What do you mean by this? I just checked without conan
```
cmake -G"Visual Studio 17 2022" -Tv143 ..
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The C compiler identification is MSVC 19.40.33808.0
```

`VC\Auxiliary\Build\Microsoft.VCToolsVersion.v143.default.txt` and `.props` contain latest `14.40.33807`

jcar87: Hi @Nekto89 thanks for following up. Could you paste the bit of the CMake configuration log where it prints the location of cl.exe?
Nekto89: > Hi @Nekto89 thanks for following up. Could you paste the bit of the CMake configuration log where it prints the location of cl.exe?
> 
> On my machine in that directory `C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build` some contain `14.40`, but some point to `14.39`, and CMake uses 14.39 (and I've not touched any of these files)

```
cmake -G"Visual Studio 17 2022" ..
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The C compiler identification is MSVC 19.40.33808.0
-- The CXX compiler identification is MSVC 19.40.33808.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (8.2s)
-- Generating done (0.0s)
```
```
cmake -G"Visual Studio 17 2022" -Tv143 ..
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The C compiler identification is MSVC 19.40.33808.0
-- The CXX compiler identification is MSVC 19.40.33808.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (8.1s)
-- Generating done (0.1s)
```
```
cmake -G"Visual Studio 17 2022" -Tv143,version=14.40 ..
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The C compiler identification is MSVC 19.40.33808.0
-- The CXX compiler identification is MSVC 19.40.33808.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (7.9s)
-- Generating done (0.0s)
```
```
cmake -G"Visual Studio 17 2022" -Tv143,version=14.40.17.10 ..
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.19044.
-- The C compiler identification is MSVC 19.40.33808.0
-- The CXX compiler identification is MSVC 19.40.33808.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.40.33807/bin/Hostx64/x64/cl.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (7.7s)
-- Generating done (0.0s)
```

Patch:
diff --git a/conan/internal/api/detect_api.py b/conan/internal/api/detect_api.py
index 5f2eabebd..e90894b29 100644
--- a/conan/internal/api/detect_api.py
+++ b/conan/internal/api/detect_api.py
@@ -384,9 +384,14 @@ def detect_default_compiler():
         return None, None, None
 
     if platform.system() == "Windows":
-        compiler, version, compiler_exe = detect_msvc_compiler()
-        if compiler:
-            return compiler, version, compiler_exe
+        ide_version = _detect_vs_ide_version()
+        version = {"17": "193", "16": "192", "15": "191"}.get(str(ide_version))  # Map to compiler
+        if ide_version == "17":
+            update = detect_msvc_update(version)  # FIXME weird passing here the 193 compiler version
+            if update and int(update) >= 10:
+                version = "194"
+        if version:
+            return 'msvc', Version(version), None
 
     if platform.system() == "SunOS":
         sun_cc, sun_cc_version, compiler_exe = detect_suncc_compiler()
@@ -409,7 +414,7 @@ def detect_default_compiler():
 
 
 def default_msvc_ide_version(version):
-    version = {"193": "17", "192": "16", "191": "15"}.get(str(version))
+    version = {"194": "17", "193": "17", "192": "16", "191": "15"}.get(str(version))
     if version:
         return Version(version)
 
diff --git a/conan/tools/microsoft/visual.py b/conan/tools/microsoft/visual.py
index 8c929e979..1632e3b95 100644
--- a/conan/tools/microsoft/visual.py
+++ b/conan/tools/microsoft/visual.py
@@ -59,7 +59,8 @@ def msvc_version_to_vs_ide_version(version):
                 '190': '14',
                 '191': '15',
                 '192': '16',
-                '193': '17'}
+                '193': '17',
+                '194': '17'}  # Note both 193 and 194 belong to VS 17 2022
     return _visuals[str(version)]
 
 
@@ -75,7 +76,8 @@ def msvc_version_to_toolset_version(version):
                 '190': 'v140',
                 '191': 'v141',
                 '192': 'v142',
-                "193": 'v143'}
+                "193": 'v143',
+                "194": 'v143'}
     return toolsets.get(str(version))
 
 
@@ -140,6 +142,7 @@ class VCVars:
                 compiler_update = conanfile.settings.get_safe("compiler.update", "")
                 # The equivalent of compiler 19.26 is toolset 14.26
                 vcvars_ver = "14.{}{}".format(compiler_version[-1], compiler_update)
+
         vcvarsarch = _vcvars_arch(conanfile)
 
         winsdk_version = conanfile.conf.get("tools.microsoft:winsdk_version", check_type=str)
diff --git a/conans/client/conf/__init__.py b/conans/client/conf/__init__.py
index 15836051d..129ceb76f 100644
--- a/conans/client/conf/__init__.py
+++ b/conans/client/conf/__init__.py
@@ -94,14 +94,14 @@ compiler:
                     "10", "10.1", "10.2", "10.3", "10.4", "10.5",
                     "11", "11.1", "11.2", "11.3", "11.4",
                     "12", "12.1", "12.2", "12.3",
-                    "13", "13.1", "13.2", 
+                    "13", "13.1", "13.2",
                     "14", "14.1"]
         libcxx: [libstdc++, libstdc++11]
         threads: [null, posix, win32]  # Windows MinGW
         exception: [null, dwarf2, sjlj, seh]  # Windows MinGW
         cppstd: [null, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23]
     msvc:
-        version: [170, 180, 190, 191, 192, 193]
+        version: [170, 180, 190, 191, 192, 193, 194]
         update: [null, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
         runtime: [static, dynamic]
         runtime_type: [Debug, Release]
diff --git a/conans/client/conf/detect_vs.py b/conans/client/conf/detect_vs.py
index f0c48c749..4db783a87 100644
--- a/conans/client/conf/detect_vs.py
+++ b/conans/client/conf/detect_vs.py
@@ -12,7 +12,7 @@ def vs_installation_path(version):
 
 
 def vs_detect_update(version):
-    version = {"193": "17", "192": "16", "191": "15"}.get(str(version))
+    version = {"194": "17", "193": "17", "192": "16", "191": "15"}.get(str(version))
     full_version = _vs_installation_path(version)[1]
     components = full_version.split(".")
     if len(components) > 1:
diff --git a/conans/client/graph/compatibility.py b/conans/client/graph/compatibility.py
index c72c4377c..967ddc90e 100644
--- a/conans/client/graph/compatibility.py
+++ b/conans/client/graph/compatibility.py
@@ -30,26 +30,43 @@ from conan.errors import ConanException
 def cppstd_compat(conanfile):
     # It will try to find packages with all the cppstd versions
     extension_properties = getattr(conanfile, "extension_properties", {})
-    if extension_properties.get("compatibility_cppstd") is False:
-        return []
     compiler = conanfile.settings.get_safe("compiler")
     compiler_version = conanfile.settings.get_safe("compiler.version")
     cppstd = conanfile.settings.get_safe("compiler.cppstd")
-    if not compiler or not compiler_version or not cppstd:
+    if not compiler or not compiler_version:
         return []
     base = dict(conanfile.settings.values_list)
-    cppstd_possible_values = supported_cppstd(conanfile)
-    if cppstd_possible_values is None:
-        conanfile.output.warning(f'No cppstd compatibility defined for compiler "{compiler}"')
-        return []
-    ret = []
-    for _cppstd in cppstd_possible_values:
-        if _cppstd is None or _cppstd == cppstd:
+    factors = []  # List of list, each sublist is a potential combination
+    if cppstd is not None and extension_properties.get("compatibility_cppstd") is not False:
+        cppstd_possible_values = supported_cppstd(conanfile)
+        if cppstd_possible_values is None:
+            conanfile.output.warning(f'No cppstd compatibility defined for compiler "{compiler}"')
+        else:
+            factors.append([{"compiler.cppstd": v} for v in cppstd_possible_values if v != cppstd])
+
+    if compiler == "msvc":
+        msvc_fallback = {"194": "193"}.get(compiler_version)
+        if msvc_fallback:
+            factors.append([{"compiler.version": msvc_fallback}])
+
+    combinations = []
+    for factor in factors:
+        if not combinations:
+            combinations = factor
             continue
+        new_combinations = []
+        for comb in combinations:
+            for f in factor:
+                comb = comb.copy()
+                comb.update(f)
+                new_combinations.append(comb)
+        combinations = new_combinations
+
+    ret = []
+    for comb in combinations:
         configuration = base.copy()
-        configuration["compiler.cppstd"] = _cppstd
+        configuration.update(comb)
         ret.append({"settings": [(k, v) for k, v in configuration.items()]})
-
     return ret
 """
 


Test patch:
diff --git a/conans/test/integration/package_id/test_cache_compatibles.py b/conans/test/integration/package_id/test_cache_compatibles.py
index f98dd7fe6..702b11e6d 100644
--- a/conans/test/integration/package_id/test_cache_compatibles.py
+++ b/conans/test/integration/package_id/test_cache_compatibles.py
@@ -377,6 +377,27 @@ class TestDefaultCompat:
         c.run("install --requires=app/0.1  --build=missing")
         assert re.search(r"Skipped binaries(\s*)tool/0.1", c.out)
 
+    def test_msvc_194_fallback(self):
+        c = TestClient()
+        save(c.cache.default_profile_path, "")
+        c.save({"conanfile.py": GenConanfile("mylib", "1.0").with_settings("os", "arch",
+                                                                           "compiler", "build_type"),
+                "profile_build": "[settings]\nos=Windows\narch=x86_64"})
+
+        c.run("create . -s os=Windows -s arch=x86_64 -s build_type=Release "
+              "-s compiler=msvc "
+              "-s compiler.version=193 -s compiler.cppstd=17 "
+              "-s compiler.runtime=dynamic -pr:b=profile_build")
+        package_id1 = c.created_package_id("mylib/1.0")
+
+        # Try to install with cppstd 14, it will find cppstd 17 as compatible
+        c.run("install --requires=mylib/1.0@ -s os=Windows -s arch=x86_64 -s build_type=Release "
+              "-s compiler=msvc "
+              "-s compiler.version=194 -s compiler.cppstd=14 "
+              "-s compiler.runtime=dynamic -pr:b=profile_build")
+        assert "mylib/1.0: Main binary package 'e340edd75790e7156c595edebd3d98b10a2e091e' missing."\
+               f"Using compatible package '{package_id1}'"
+
 
 class TestErrorsCompatibility:
     """ when the plugin fails, we want a clear message and a helpful trace
diff --git a/conans/test/unittests/tools/cmake/test_cmaketoolchain.py b/conans/test/unittests/tools/cmake/test_cmaketoolchain.py
index b08dc13b7..8bba79509 100644
--- a/conans/test/unittests/tools/cmake/test_cmaketoolchain.py
+++ b/conans/test/unittests/tools/cmake/test_cmaketoolchain.py
@@ -194,7 +194,7 @@ def test_osx_deployment_target(conanfile_apple):
 def conanfile_msvc():
     c = ConanFile(None)
     c.settings = Settings({"os": ["Windows"],
-                           "compiler": {"msvc": {"version": ["193"], "cppstd": ["20"],
+                           "compiler": {"msvc": {"version": ["193", "194"], "cppstd": ["20"],
                                                  "update": [None, 8, 9]}},
                            "build_type": ["Release"],
                            "arch": ["x86"]})
@@ -226,6 +226,14 @@ def test_toolset_update_version(conanfile_msvc):
     assert 'set(CMAKE_GENERATOR_TOOLSET "v143,version=14.38" CACHE STRING "" FORCE)' in toolchain.content
 
 
+def test_toolset_update_version_overflow(conanfile_msvc):
+    # https://github.com/conan-io/conan/issues/15583
+    conanfile_msvc.settings.compiler.version = "194"
+    conanfile_msvc.settings.compiler.update = "8"
+    toolchain = CMakeToolchain(conanfile_msvc)
+    assert 'set(CMAKE_GENERATOR_TOOLSET "v143,version=14.48" CACHE STRING "" FORCE)' in toolchain.content
+
+
 def test_toolset_x64(conanfile_msvc):
     # https://github.com/conan-io/conan/issues/11144
     conanfile_msvc.conf.define("tools.cmake.cmaketoolchain:toolset_arch", "x64")
diff --git a/conans/test/unittests/tools/microsoft/test_msvs_toolset.py b/conans/test/unittests/tools/microsoft/test_msvs_toolset.py
index b5f8b1a5d..14574127e 100644
--- a/conans/test/unittests/tools/microsoft/test_msvs_toolset.py
+++ b/conans/test/unittests/tools/microsoft/test_msvs_toolset.py
@@ -15,6 +15,7 @@ def test_invalid_compiler():
 
 
 @pytest.mark.parametrize("compiler_version,expected_toolset", [
+    ("194", "v143"),
     ("193", "v143"),
     ("192", "v142"),
     ("191", "v141"),