microsoft / vscode-cmake-tools

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

CmakePresets: Selecting of build targets seems not to be supported or not working #1872

Closed hwmaier closed 3 years ago

hwmaier commented 3 years ago

Brief Issue Summary

The CMake Tools when using kits and variants allow easy selection of the current build target using either a command or a selector in the toolbar next to the Build icon. It is very easy to switch between different compilation targets in multi-target cmake files or alternatively selecting of [all].

Example: 2021-05-13_12-47-51

2021-05-13_12-49-40

The new CMake Tools "CmakePresets" feature does unfortunately not offer changing the target. Neither is there a similar target icon/selector in the toolbar nor seems there to be a way to change the target otherwise. The Cmake: Set Build Target command is not even listed on my machine nor does running CMake: Set Debug Target work either, but at least the command is listed.

Snag_b337d2

Snag_b5c246

Platform and Versions

andreeis commented 3 years ago

Setting a build target via a command or a UI element is disabled when presets are used. This is by design for now. I will consult with the team about the possibility of supporting something like this in the future and get back to you.

In the meantime, you can use the keyword "targets" within a build preset, as described in the official presets CMake documentation: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html.

Regarding the "CMake: Set Debug Target" command not working, I've seen this happening when using presets with Ninja generator and without defining a CMAKE_BUILD_TYPE. Add it as a preset cache variable (with value "Debug" for example) and let us know if you are able to select a debug target.

andreeis commented 3 years ago

We will definitely improve in time the UI experience of creating a new preset (which can allow build targets selection which doesn't now) or maybe even extend that UI experience for edit mode (besides the creation mode). Would that work for you instead of what you propose? But since what you are asking is slightly different than what I imagine above, I will let @esweet431 comment more about why this is by design or if we could offer an UI scenario for this in the future.

hwmaier commented 3 years ago

Regarding the "CMake: Set Debug Target" command not working, I've seen this happening when using presets with Ninja generator and without defining a CMAKE_BUILD_TYPE. Add it as a preset cache variable (with value "Debug" for example) and let us know if you are able to select a debug target.

Yes, I can confirm that Ninja is used in my use case as generator and CMAKE_BUILD_TYPE was not set. Once set to "Debug" I can select a debug target,

hwmaier commented 3 years ago

@andreeis Thank you for explaining.

I think moving from the Kit/Variant method to the official CMake Preset method is the right move and it greatly improves transitioning between IDE and command line use.

But I still think there is a use case for being able to select a target in addition or alternatively to selecting a build preset in the IDE (as the CMake command line supports this as well).

From my understanding of CMake's preset, you either use a Configuration Preset or a Build Preset on the command line. Never both. A target can be added optionally.

So I would expect that the CMake Tools would reflect that somehow and either allow you choose a Configuration Preset OR a Build Preset. But the selection of a Build Preset should be optional and target selection should be possible too (unless a targets field is specified in the Build Preset).

The Target selection then also could be used automatically as the debug target.

There are others finding the loss of target selection a stop backwards: refer to https://devblogs.microsoft.com/cppblog/cmake-presets-integration-in-visual-studio-and-visual-studio-code/#comment-1693

esweet431 commented 3 years ago

Hi @hwmaier,

Running "CMake: Build Target" allows you to build a single target with the instructions encoded in the active Build Preset. This is the equivalent of passing --target and --preset from the command line. Does this unblock your scenario, or do you need a way to persist a single active build target? If you always want to build the same target, then I recommend creating a Build Preset that specifies the target with the 'targets' option. If you frequently toggle between build targets, then hopefully the "CMake: Build Target" command will work for your needs.

Invoking Configure Presets and Build Presets from the command line are two discrete steps, but they can be (and often are) paired together. The Configure Preset encodes instructions that are specific to the configure step, while the Build Preset encodes instructions that are specific to the build step. That's why cmake-tools surfaces both your active Configure Preset and your active Build Preset. Let me know if you have any more questions about this design.

hwmaier commented 3 years ago

Hello @esweet431,

Thank you so much for looking into this use case.

Running "CMake: Build Target" allows you to build a single target with the instructions encoded in the active Build Preset. This is the equivalent of passing --target and --preset from the command line. Does this unblock your scenario, or do you need a way to persist a single active build target? If you always want to build the same target, then I recommend creating a Build Preset that specifies the target with the 'targets' option. If you frequently toggle between build targets, then hopefully the "CMake: Build Target" command will work for your needs.

That's exactly my point. Most of our projects don't have a single target but multiple targets and we switch between them frequently. In addition we have typically between 4 to 8 configurations (different processor architectures). So embedding the target into the buildPresets is not feasible as we would have to create too many buildPresets entries to cover all combinations of configurations and targets.

We currently are using two methods. Method A is not using build presets, only configuration presets. On the command line we configure like this:

cmake --preset stm32f4-disco    

and then build using this :

cmake --build build\stm32f4-disco --target uhttpd

Method B is a bit more involved, we add for each configuration preset a build preset with the same name and keep the targets field empty.

    "configurePresets": [
        ...
        {
            "name": "stm32f4-disco",
            "description": "STM32F4-DISCO board",
            "inherits": "arm-embedded",
            "cacheVariables": {
               ...
            }
        }
    ],
    ...
    "buildPresets": [
        {
            "name": "stm32f4-disco",
            "configurePreset": "stm32f4-disco"
        }
    ]
 cmake --preset stm32f4-disco    

and then build using this :

cmake --build --preset stm32f4-disco --target uhttpd

In both scenarios we can specify the build target using the --target command line option rather than building all targets.

So it would be nice if VSCode supports both or at least one of above approaches. One where only configuration presets are used and build presets are not used and the target can be optionally selected from a menu. The other where both configuration and build presets are used but no targets field is specified in the preset and again the target can be selected from a drop-down menu

All which would be required is to re-introduce the target selection drop-down menu which the former kits/variants model already has.

Here is a little mock-up how this could look like: 2021-05-18_11-17-03

esweet431 commented 3 years ago

Thanks for the feedback! We do support this scenario:

One where only configuration presets are used and build presets are not used and the target can be optionally selected from a menu.

To achieve this:

  1. Select your active Configure Preset (CMake: Select Configure Preset)
  2. Select the "Default" Build Preset (CMake: Select Build Preset). The default Build Preset is implicit (never written to CMakePresets.json) and a full build is equivalent to running cmake --build build\stm32f4-disco from the command line.
  3. Build using the "CMake: Build Target" command. This command will prompt you with a list of targets to build. The selected target will be the only target that VS Code builds. This is the same as adding --target <target> to the command above, ie cmake --build build\stm32f4-disco --target <target>

Since you aren't passing any additional command line arguments to --build, I agree that option 1 is the cleanest approach. You shouldn't need to maintain any Build Presets at all. Please let me know if this approach works for your team.

hwmaier commented 3 years ago

@esweet431

3. Build using the "CMake: Build Target" command. This command will prompt you with a list of targets to build. The selected target will be the only target that VS Code builds. This is the same as adding --target <target> to the command above, ie cmake --build build\stm32f4-disco --target <target>

Confirmed, using the command "CMake: Build Target" (or Shift F7) does allow selection of the target from the menu for the next build. Somehow I missed that. Thank you for pointing it out.

So when I compare the "CMake Preset" build workflow to the former "CMake Kit/Variant" method, the former has theses advantages:

Are there any plans to match the functionality and make the target selection persistent for the session and also to be able to pass it with the ${command:cmake.tasksBuildCommand} command (see https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/cmake-settings.md)?

That would be a huge productivity boost as the command:cmake.tasksBuildCommand can be used in tasks and bound to a hotkey (like Ctrl-Shift-B).

Addendum: I just went through the doc on https://github.com/microsoft/vscode-cmake-tools/blob/develop/docs/cmake-presets.md#cmake-build again. There is says there would be a command "CMake: Set Build Target.". For some reason this command is not available on my system. What would prevent this from be available?

hwmaier commented 3 years ago

Addendum: I just went through the doc on https://github.com/microsoft/vscode-cmake-tools/blob/develop/docs/cmake-presets.md#cmake-build again. There is says there would be a command "CMake: Set Build Target.". For some reason this command is not available on my system. What would prevent this from be available?

I just had a look at the source code of vscode-cmake-tools, according to file package.json , the command "CMake: Set Build Target." is not available when using presets, see when clause:

      {
        "command": "cmake.setDefaultTarget",
        "title": "%cmake-tools.command.cmake.setDefaultTarget.title%",
        "when": "cmake:enableFullFeatureSet && !useCMakePresets",
        "category": "CMake"
      },

This is in contrary to the documentation (https://github.com/microsoft/vscode-cmake-tools/blob/develop/docs/cmake-presets.md#cmake-build) which states "Run CMake: Build Target from the command palette to build a single target. You can switch the active build target by running CMake: Set Build Target."

esweet431 commented 3 years ago

You're right. I have a PR out now to update the documentation to match the current implementation (#1893).

We can keep this issue open to track the 4 feature gaps you identified above that surface when "CMake: Set Build Target" is not supported.

  • Default target selection is persistent during the editor session.
  • The selected target is passed down to CMake when running the ${command:cmake.tasksBuildCommand} command from a task
  • The selected target is available in the ${command:cmake.buildTargetName} variable (I also tried "${command:cmake.tasksBuildCommand} --target ${command:cmake.buildTargetName}" but it passes always all as target.)
  • The selected target is shown in the toolbar and can be changed from the toolbar
hwmaier commented 3 years ago

You're right. I have a PR out now to update the documentation to match the current implementation (#1893).

I wished instead of updating the documentatiuon the PR would unhide the already existing "CMake: Set Build Target" feature. I patched my local extension code and managed to have "CMake: Set Build Target" available from the menu and it works. So all the code is already there, its simply "hidden".

But I appreciate that you keep the feature request open for the future and I am happy to assist with testing and discussions. Thank you so much for providing the enhanced CMake plugin and all the documentation and blog posts.

KUGA2 commented 3 years ago

We got excactly the same usecase as @hwmaier.

Multiple platforms and toolchains and big projects with many targets. Users want to build only a single targets, they currently develop for faster test build or debug.

PS: the proposed target selection statusbar button should also be used for the play and debug button! image (similar to this request https://github.com/microsoft/vscode-cmake-tools/issues/1941)

sorenfriis commented 3 years ago

We have a similar use case and would like to see the option of setting a single build target, again.

Our application has multiple libraries, and a few executables that link with the libraries. If working on one library, I am only interesting in compiling that, so I would select that as my build target and just press "F7" while working to run a compile.

The way we work around it now, is to ask people to create a CMakeUserPresets.json and add a "BuildPreset" entry for the target they are working on.

craigscott-crascit commented 3 years ago

Hey folks, CMake co-maintainer here. I'm seeing this issue really hurting adoption of CMake presets among the user community. Anyone who works on a non-trivial sized project is going to be hitting this problem.

I was trying out the suggested workaround of using Shift+F7 to build a specific target, but I found that when I did that, I didn't get a list of defined targets to pick from and instead had to manually type in a target name. No developer is going to be happy doing that every time they want to do a build in their day-to-day workflow. The combinatorial explosion that would result from having to create a build preset for every target and every configuration is also not practical and not friendly to users. There's some further context in the upstream CMake issue: https://gitlab.kitware.com/cmake/cmake/-/issues/22538

Is it possible to consider @hwmaier 's suggestion and re-enable the "CMake: Set Build Target" code, at least for now while a deeper solution is being worked on? That would at least give users a considerably better experience with presets in the short term for what seems like pretty low cost (given the code is already there and was used previously before presets came along). Even if it was hidden behind some kind of experimental or "use at your own risk" flag, that would be considerably better than what we have now.

And to re-iterate, this is really hurting adoption.

hwmaier commented 3 years ago

I totally agree with @craigscott-crascit sentiment here. It has been a few month since my original suggestion that a mechanism needs to be available to switch targets. And this mechanism needs to be simple and convenient. Basically as it used to be, before presets came along. Before presets we switched targets by a simple click on the status bar. Shift-F7 is no practical work around as the selection is not persistent, next time you hit F7 all targets are built again, Also no visual indication is given in the status bar which target you are working on.

bobbrow commented 3 years ago

@craigscott-crascit thanks for chiming in. I am in agreement that the flow currently sucks. We used to have a good solution for combinatorial explosion with Variants, but that feature is unavailable with presets. It would be nice if something like that could be engineered into presets somehow because I think there is explosion with configure presets as well (not just build presets). How to select a given combination on the CLI would need to be determined though.

If @esweet431 is ok with it, we can add support for persisting a target back for the presets case.

esweet431 commented 3 years ago

Sure, I fully support adding this back.

That said, I'm not sure how this alone will help the customer in the upstream CMake issue. As of CMake 3.21, that customer will still need to maintain an explosion of build presets due to the enforced mapping between configure presets and build presets. The customer in the upstream issue relies on build presets to set configuration, and they will still need all of those build presets until configurePreset becomes either an array or regex.

bobbrow commented 3 years ago

@esweet431 great! @xisui-MSFT I'm adding this issue to the 1.9 backlog so if you can look at it first, that would be great. To summarize, we're adding back the build target selection to the status bar and allowing the "set build target" command for presets.

@esweet431 if targets are specified in the currently selected build preset, should we filter out any additional ones not in that list?

esweet431 commented 3 years ago

@esweet431 if targets are specified in the currently selected build preset, should we filter out any additional ones not in that list?

Yes, I think that makes sense. If targets is unspecified then we should list all build presets. I've opened a suggestion ticket to maintain similar behavior in VS.

craigscott-crascit commented 3 years ago

I'm not sure how this alone will help the customer in the upstream CMake issue.

@esweet431 I linked that issue mostly for context, since it highlights how needing to define build presets for whatever you want to build quickly gets away from you and requires defining many build presets to do even basic things. This issue here is effectively another layer on top of that combinatorial explosion - not only do you need at least one build preset per configure preset, you also need one build preset per target you want to build. This last part is particularly painful, because projects often have many targets. Being able to have VS Code automatically provide the list of targets as it did before presets came along removes this last layer of combinatorial expansion of presets. For many, it will also mean they don't need to define any build presets at all.

And thanks folks for moving forward with this for 1.9, it's much appreciated.

hwmaier commented 3 years ago

Just updated to v1.9.0 and I am very pleased to see this feature implemented now. Thank you so much.