microsoft / vscode-cmake-tools

CMake integration in Visual Studio Code
https://marketplace.visualstudio.com/items?itemName=vector-of-bool.cmake-tools
MIT License
1.46k stars 449 forks source link

CMakePrests.json toolset requires the VS version instead of the toolset version #1965

Closed barcharcraz closed 2 years ago

barcharcraz commented 3 years ago

I'm using the following CMakePresets.json file

{
    "version": 2,
    "configurePresets": [
        {
            "name": "base",
            "hidden": true,
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "cacheVariables": {
                "CMAKE_CXX_COMPILER": "cl.exe",
                "CMAKE_C_COMPILER": "cl.exe",
                "CMAKE_BUILD_TYPE": "Debug"
            },
            "toolset": {
                "value": "x64",
                "strategy": "external"
            }
        },
        {
            "name": "x86",
            "inherits": "base",
            "architecture": {
                "value": "x86"
            }
        },
        {
            "name": "x64",
            "inherits": "base",
            "architecture": {
                "value": "x64"
            }
        },
        {
            "name": "ARM",
            "inherits": "base",
            "architecture": {
                "value": "arm"
            }
        },
        {
            "name": "ARM64",
            "inherits": "base",
            "architecture": {
                "value": "arm64"
            }
        }
    ],
    "buildPresets": [
        {
            "name": "default",
            "configurePreset": "base",
            "verbose": true
        }
    ]
}

Whenever a new preset is selected cmake tools prints:

[preset] Configure preset x86: No toolset architecture specified for cl.exe, using x86 by default
[preset] Configure preset x86: No toolset version specified for cl.exe, using latest by default

and the x64 compiler is not selected, moving the preset selection to inside each derived preset does not work either.

Interestingly the architecture setting does seem to work even though "strategy" is not "external" (this is fine by me).

Also, in this example cmake tools is not selecting the latest toolset, I have vs 2022 installed and it's never selected, while the latest version of vs 2019 16.11 preview is selected for x86 and x64, and an older version of vs 2019 int preview is selected for arm and arm64, this could be sticky settings, but cmake tools does find all my VS installs when scanning for compilers.

barcharcraz commented 3 years ago

hmm after removing vs 2019 int preview the arm and arm64 presets don't even configure, referring to an non-existent compiler. and I get errors about kits pointing to deleted compilers. The thing is when preset mode is enabled all the options to edit kits are turned off! This seems wrong if the kits actually do influence compiler selection in preset mode.

barcharcraz commented 3 years ago

Indeed responding to the error about the missing compiler in a kit and reconfiguring the arm preset now selects the vs 2019 preview compiler that is installed. The toolset architecture is still wrong, however.

JasonDictos commented 3 years ago

Through much trial and error and source code diving, this is how I've silenced both of the above warnings:

Architecture:

"architecture": {
  "value": "x64",
  "strategy": "external"
},
"toolset": {
   "value": "version=16.11.31410.223,host=x64",
   "strategy": "external"
  },

Took too long to debug that version key, the code is here: https://github.com/microsoft/vscode-cmake-tools/blob/develop/src/preset.ts

Digging into it its parsing the toolset and architecture keys in the preset. They can both be a string, or an object. The version is from vswhere, example:

"C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere" -all -format json -utf8 -products * -legacy -prerelease

[
  {
    "instanceId": "6a2ed37c",
    "installDate": "2021-05-18T20:08:12Z",
    "installationName": "VisualStudioPreview/16.11.0-pre.2.0+31410.223",
    "installationPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Preview",
    "installationVersion": "16.11.31410.223",

Now installationVersion is what they are comparing so you can select the host (what version of cl to use, e.g. 64 bit version) and the version of the toolset (in this case 16.11 preview 2). Architecture is well, how its being built that should trigger a vcvars call for the chosen architecture string if external.

bobbrow commented 3 years ago

I'm not sure why I didn't see this issue earlier, but in the presets example shared, the issue is that "x64" was being set for toolset instead of "host=x64". I actually just submitted a PR to add logging about what to do in this case which should hopefully resolve the problem for most folks in the future.

VS 2022 isn't supported by a released version of CMake yet. It's coming in version 3.21.

Is it too distracting to make those messages about toolset and version into "warnings"? Is the request that we lower the severity and make them "info" instead?

barcharcraz commented 3 years ago

I think the solution is to document what toolset and architecture actually do, in particular the docs should say things follow the CMAKE_GENERATOR_TOOLSET convention. Right now I think the docs are just incorrect.

I'm using the ninja generator so cmake's support for vs2022 project files is not relevant to me, cmake can identify the compiler version shipped in vs2022 just fine. Also I think the copy of cmake that comes with VS2022 may be a pre-release that supports generating vs2022 project files. I'm not sure though, I have to check.

barcharcraz commented 3 years ago

Oh, the request is that there should be some way to get the x64 toolset, and the documentation on how to do it should actually be correct. I'm not worried about the very presence of the warnings but about the fact that I couldn't figure out how to actually set the toolset arch

bobbrow commented 3 years ago

There is a way to get the x64 toolset. You use:

  "toolset": {
    "value": "host=x64",
    "strategy": "external"
  }

This aligns with the CMake documentation. Previously, with Kits and Variants the extension patched up the syntax for you if you missed the "host=" part. We didn't do this for CMakePresets.json because CMake and VS would reject it and it would only work in VS Code.

Can you point out what's wrong with the documentation on toolset? I was just looking at it and didn't see anything wrong. It points to the CMake documentation for Toolset selection.

barcharcraz commented 3 years ago

I think I was confused by

You can set the host architecture (x64 or x86) and toolset by using toolset.value. This is equivalent to passing -T to CMake from the command line. For more information, see Toolset Selection.

from https://github.com/microsoft/vscode-cmake-tools/blob/develop/docs/cmake-presets.md

The problem with "stale" kits may still be an actual bug.

bobbrow commented 3 years ago

I'll talk to the team about re-enabling the "edit kits" command when presets are in use. Since we do use them to configure the MSVC environment in some cases, I also found it a pain to switch back to "cmake.usePresets": "never" to get the command to reappear.

barcharcraz commented 3 years ago

will "cmake.usePresets": "never" cause cmaketools to totally disable reading from the cmakePresets.json file? If so that's not what I want at all! The whole point is to make things more consistent and replace our CMakeSettings.json file.

Thanks for looking into re-enabling that command though!

barcharcraz commented 3 years ago

cmake tools can not find the copy of Ninja installed as part of my visual studio installation, Ninja must be on that path.

This is a little unexpected, and cmake-tools should probably provide some option to use the ninja from the selected compiler

Also, your example of

"architecture": {
  "value": "x64",
  "strategy": "external"
},
"toolset": {
   "value": "version=16.11.31410.223,host=x64",
   "strategy": "external"
  },

implies that the versions accepted by cmake tools differ from the versions accepted by the vsdevcommand and cmake. I think the latest toolset version is 14.30.30401.

Further I still get issues with:

{
    "version": 2,
    "configurePresets": [
        {
            "name": "base",
            "hidden": true,
            "generator": "Ninja",
            "binaryDir": "${sourceDir}/out/build/${presetName}",
            "cacheVariables": {
                "CMAKE_CXX_COMPILER": "cl.exe",
                "CMAKE_C_COMPILER": "cl.exe",
                "CMAKE_BUILD_TYPE": "Debug"
            }
        },
        {
            "name": "x86",
            "inherits": "base",
            "architecture": {
                "value": "x86",
                "strategy": "external"
            },
            "toolset": {
                "value": "host=x64",
                "strategy": "external"
            }
        }
   ]
}

It's selecting the x86 version of vs2019, when I would expect the x64 version of vs2020, or at least hte x64 version of something

barcharcraz commented 3 years ago

Actually, it occurs to me that the toolset selected should not influence which vs version cmake tools picks at all, since you can very well install have the same toolset installed in multiple different VS installs.

I would expect the toolset to result in the compiler I get when running vsdevcmd -arch=x86 -host_arch=amd64 -vcvars_ver=<whaever I put in verson=, exactly>

srnwk commented 3 years ago

It would be really handy if this could would work with the same syntax in both Visual Studio and vscode-cmake-tools, otherwise you will need a bunch of duplicated, near-identical presets for doing the same thing in VS and VSCode 😬

bobbrow commented 3 years ago

Sorry this fell off my radar. To summarize the current issue since this thread has meandered a few different ways:

Does that sound right? Is there anything else?

Djoulihen commented 2 years ago

Sorry this fell off my radar. To summarize the current issue since this thread has meandered a few different ways:

The toolset version is not correctly handled. It is being interpreted by CMake Tools as the VS version, but it should be interpreted as the Toolset version (which is unfortunately divergent). This has the result of making presets that specify a version incompatible between VS/CMake and VS Code.

Does that sound right? Is there anything else?

Just stumbled upon this issue which is related to a problem I've been investigating with cmake-tools' support for toolset versions in presets when using Ninja generators. Please let me know if this warrants opening a separate issue.

It seems that in addition to the toolset version being currently incorrectly compared to the VS installation version, the toolset name is also not taken into consideration at all. I'm working with the following preset:

        {
            "name": "Ninja",
            "generator": "Ninja Multi-Config",
            "architecture": {
                "strategy": "external",
                "value": "x64"
            },
            "toolset": {
                "strategy": "external",
                "value": "v141,host=x64"
            },
            "cacheVariables": {
                "CMAKE_CXX_COMPILER": "cl"
            }
        },

While this works exactly as intended in VS2019 (with the v141 toolset installed), it fails in vscode. This is what I get from the logs (with some paths redacted) :

[variant] Loaded new set of variants
[kit] Successfully loaded 8 kits from C:\Users\XXX\AppData\Local\CMakeTools\cmake-tools-kits.json
[presetController] Successfully validated presets in c:\XXX\CMakePresets.json
[preset] Configure preset Ninja: No toolset version specified for cl.exe, using latest by default

And when configuring

[cmake] -- The CXX compiler identification is MSVC 19.29.30136.0
[cmake] -- Detecting CXX compiler ABI info
[cmake] -- Detecting CXX compiler ABI info - done
[cmake] -- Check for working CXX compiler: C:/Program Files (x86)/Microsoft Visual Studio/2019/Professional/VC/Tools/MSVC/14.29.30133/bin/Hostx64/x64/cl.exe - skipped
[cmake] -- Detecting CXX compile features
[cmake] -- Detecting CXX compile features - done
[cmake] -- Performing Test COMPILER_HAS_DEPRECATED_ATTR
[cmake] -- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Failed
[cmake] -- Performing Test COMPILER_HAS_DEPRECATED
[cmake] -- Performing Test COMPILER_HAS_DEPRECATED - Success
[cmake] -- Configuring done
[cmake] -- Generating done

Here the toolset is 14.29.xxx when it should be 14.16 with v141. Doing the configuration in VS2019 shows the correct 14.16 toolset.

Solving the version= bug would probably help target a specific toolset but would also be a bit of a pain when you just want to specify v141 or v142 instead of a very precise version (14.29.30133) which may change with the next update.

carterols commented 2 years ago

@Djoulihen I can confirm that this fails for me too. As stated in the CMake docs for toolset specifiers, users are able to specify the following for the toolset:

Right now, it seems that I can (sort of) only get it to work using vscode-cmake-tools when I specify "toolset": { "value": "v141", "strategy": "external" } Using "toolset": { "value": "v141,host=x64", "strategy": "external" } gives me the following warnings:

[preset] Configure preset win64_ninja: No toolset version specified for cl.exe, using latest by default

Using "toolset": { "value": "version=14.16.27023,host=x64", "strategy": "external" } gives me the following warnings:

[preset] Configure preset win64_ninja: Compiler 'cl.exe' with toolset '14.16.27023,x64' and architecture 'x64' was not found, you may need to run 'CMake: Scan for Compilers' if it exists on your computer.

Another error I encountered is that when specifying "toolset": { "value": "v141", "strategy": "external"}, I found that this extension overwrites the CMAKE_C(XX)_FLAGS cache variables if you specify CMAKE_C(XX)_FLAGS: "".

Example: I added these lines to CMakePresets so that VSCode would stop automatically adding them to my CMakeCache. I set the values of CMAKE_C(XX)_FLAGS inside of my top level CMakeLists.txt

"cacheVariables": {
        "CMAKE_CXX_FLAGS": "",
        "CMAKE_C_FLAGS": "",
        "CMAKE_CXX_FLAGS_DEBUG": "",
        "CMAKE_C_FLAGS_DEBUG": "",
        "CMAKE_C_COMPILER": "cl.exe",
        "CMAKE_CXX_COMPILER": "cl.exe"
}

This leads to the following CMakeCache.txt:

//Flags used by the CXX compiler during all build types.
CMAKE_CXX_FLAGS:STRING=/DWIN32 /D_WINDOWS /GR /EHsc

//Flags used by the CXX compiler during DEBUG builds.
CMAKE_CXX_FLAGS_DEBUG:STRING=/Zi /Ob0 /Od /RTC1

//Flags used by the CXX compiler during MINSIZEREL builds.
CMAKE_CXX_FLAGS_MINSIZEREL:STRING=/O1 /Ob1 /DNDEBUG

//Flags used by the CXX compiler during RELEASE builds.
CMAKE_CXX_FLAGS_RELEASE:STRING=/O2 /Ob2 /DNDEBUG

//Flags used by the CXX compiler during RELWITHDEBINFO builds.
CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=/Zi /O2 /Ob1 /DNDEBUG
...

If I specify anything but an empty string inside of CMAKE_CXX_FLAGS, it doesn't get automatically filled in by VSCode. This is not the behavior of Visual Studio.

Edit: When I say that using v141 sort of works, I mean that the correct compiler is selected by VSCode, but when I try to build my application, it looks like incorrect include paths get set for the environment.

Example) With a toolset version of v141, I would expect that include paths would also be set accordingly. For example, my CMAKE_CXX_COMPILER is set correctly (C:/Program Files/Microsoft Visual Studio/2022/Professional/VC/Tools/MSVC/14.16.27023/bin/HostX64/x64/cl.exe). However, when going to compile, I get the following error:

C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.30.30705\include\yvals_core.h(581): fatal error C1189: #error: STL1001: Unexpected compiler version, expected MSVC 19.30 or newer.

This doesn't occur in Visual Studio, and it doesn't occur using the terminal, so I am assuming there is something that vscode-cmake-tools is doing under under the hood to try to add the correct include path to the environment. I could be wrong here though. Either way, the issue boils down to a lack of properly using the cmake toolset specifier.

bobbrow commented 2 years ago

The fix for this issue is available in 1.10 "pre-release". You can help us validate it by:

  1. Opening the extensions panel in VS Code
  2. Selecting the CMake Tools extension
  3. Clicking the "Switch to Pre-release Version" button

image

Djoulihen commented 2 years ago

Thank you for the update. I just tried the pre-release version and I would say that, for me, this issue is currently only partially fixed.

With the Ninja Multi-config generator, using "toolset": { "value": "v141,host=x64", "strategy": "external" } gives me:

[preset] Configure preset Ninja: No toolset version specified for cl.exe, using latest by default [preset] Using developer environment from Visual Studio (instance 59fddfac, version 16.11.31729.503, installed at "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional")

It then proceeds to use the toolset with version 14.29.30133 which corresponds to v142, not v141.

However, if I use "toolset": { "value": "v141,version=14.16.27023,host=x64", "strategy": "external" }, then it correctly selects the 14.16.27023 toolset.

So the pre-release version fixes the fact that the version= parameter now correctly uses the toolset version but we still cannot just specify the toolset name (e.g. v141) as we can with Visual Studio generators. But maybe that needs a separate issue...

bobbrow commented 2 years ago

Yes, it appears that version is currently required still, but it doesn't require a 3-part version. You can use 14.16. Could you open a new issue for this?

Djoulihen commented 2 years ago

Yes, it appears that version is currently required still, but it doesn't require a 3-part version. You can use 14.16. Could you open a new issue for this?

I just opened a new issue #2423 for the toolset name.

Thank you for mentioning that I can only specify 14.16, I was not aware of it and it makes specifying the version much more usable imo.

bobbrow commented 2 years ago

I just opened a new issue #2423 for the toolset name.

Thank you!