Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add script mode and ability to connect to externally launched CMake process. #3277

Merged
merged 26 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c706bc7
storing initial thoughts
gcampbell-msft Jul 21, 2023
a61c8bc
rough version of trying to work on new options for debugger configura…
gcampbell-msft Jul 24, 2023
b517b8a
made progress enabling script debugging from launch.json
gcampbell-msft Jul 26, 2023
bded134
add some output messaging regarding the debugger and script
gcampbell-msft Aug 2, 2023
2c7b854
add TODO's in case I don't get to it today
gcampbell-msft Aug 2, 2023
e3d3703
log statements, ensure package.json allows the right args in right si…
gcampbell-msft Aug 2, 2023
5c1d651
push worst case copying the description and settings of the debugger …
gcampbell-msft Aug 2, 2023
ee83c45
I think I've covered all launch config cases
gcampbell-msft Aug 2, 2023
ea036b9
better package.json schema, though still not perfect, matches other d…
gcampbell-msft Aug 3, 2023
a8a3721
localize error messages
gcampbell-msft Aug 3, 2023
663fa08
add 'The'
gcampbell-msft Aug 3, 2023
264a800
switch to double quotes
gcampbell-msft Aug 3, 2023
0484233
add docs page for debugging
gcampbell-msft Aug 3, 2023
fedd875
slight modifications
gcampbell-msft Aug 3, 2023
08511df
didn't handle case where scriptEnv was undefined
gcampbell-msft Aug 4, 2023
921de87
add configurationSnippets
gcampbell-msft Aug 10, 2023
b63c7d3
add stub for debugconfigurationprovider
gcampbell-msft Aug 10, 2023
496e4e0
add ability to 'run and debug' without launch.json on *.cmake files
gcampbell-msft Aug 10, 2023
c0e5b9e
Merge branch 'main' into dev/gcampbell/ScriptModeDebugger
gcampbell-msft Aug 10, 2023
9f1b1b5
modify when we sanity check
gcampbell-msft Aug 10, 2023
bd2846b
Merge branch 'dev/gcampbell/ScriptModeDebugger' of https://github.com…
gcampbell-msft Aug 10, 2023
bb7a69f
make adjustments based on feedback and add automatic configuration
gcampbell-msft Aug 21, 2023
7185e97
Merge branch 'main' into dev/gcampbell/ScriptModeDebugger
gcampbell-msft Aug 22, 2023
4dd775f
Merge branch 'main' into dev/gcampbell/ScriptModeDebugger
gcampbell-msft Sep 20, 2023
1987139
ensure that configure with debugger works with the right format
gcampbell-msft Sep 20, 2023
25dccb3
update changelog
gcampbell-msft Sep 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ CMake Tools is an extension designed to make it easy to work with CMake-based pr
* [Quick debugging](debug-launch.md#quick-debugging)
* [Debug using a launch.json file](debug-launch.md#debug-using-a-launchjson-file)
* [Run without debugging](debug-launch.md#run-without-debugging)
* [Debugging CMake](debug.md)

[Configure CMake Tools settings](cmake-settings.md)
* [CMake Tools settings](cmake-settings.md#cmake-settings)
Expand Down
72 changes: 72 additions & 0 deletions docs/debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# CMake Debugging
gcampbell-msft marked this conversation as resolved.
Show resolved Hide resolved

Starting with CMake 3.27, debugging CMake is supported in CMake Tools.

The following documentation will help you understand the various ways you can debug CMake scripts and cache generation.

## Debugging from CMake Tools UI entry points

The most common reason to debug CMake scripts and cache generation is to debug CMake cache generation. There are many ways that you can accomplish this:

* Commands
* CMake: Configure with CMake Debugger
* CMake: Delete Cache and Reconfigure with CMake Debugger
* Folder Explorer
* Right click on CMakeLists.txt -> Configure All Projects with CMake Debugger.
* Project Outline
* Right click on CMakeLists.txt -> Configure All Projects with CMake Debugger.
* Expand the "..." in the project outline. There is an entry to use the Debugger.

## Debugging from launch.json

CMake Tools provides a new debug type `cmake`.

The `cmake` debug type supports three different types of `cmakeDebugType`: `configure`, `external`, `script`. They each come with their own settings that can be used to modify and control the debug session.

### Example launch.json

```json
{
"version": "0.2.0",
"configurations": [
{
"type": "cmake",
"request": "launch",
"name": "CMake script debugging",
"cmakeDebugType": "script",
"scriptPath": "${workspaceFolder}/<script>.cmake"
},
{
"type": "cmake",
"request": "launch",
"name": "Debug externally launched CMake process",
"cmakeDebugType": "external",
"pipeName": "<insert-pipe-name>"
}
]
}
```

Listed below are the settings that are available for each configuration based on `cmakeDebugType`:
gcampbell-msft marked this conversation as resolved.
Show resolved Hide resolved

* `configure`
* required: none
* optional
* `pipeName` - Name of the pipe (on Windows) or domain socket (on Unix) to use for debugger communication.
* `clean` - Clean prior to configuring.
* `configureAll` - Configure for all projects.
* `dapLog` - Where the debug adapter protocol (DAP) communication should be logged. If omitted, DAP communication is not logged.
* `external`
* required
* `pipeName` - Name of the pipe (on Windows) or domain socket (on Unix) to use for debugger communication.
* optional
Copy link

@Neumann-A Neumann-A Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can this get an optional "command" : [] field/array? So that VS code executes the command I would normally use to start the cmake pipe externally?

Copy link
Collaborator Author

@gcampbell-msft gcampbell-msft Aug 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To help me think through the possible design implications, could you go into more detail regarding your use case for the external mode?

What kind of external processes are you expecting? It is a CMake invocation? Or is it invoking something else that internally invokes CMake?
What are you expecting or hoping to use in the "command" field?

Thanks!

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a CMake invocation? Or is it invoking something else that internally invokes CMake?

Could be both of those.

What are you expecting or hoping to use in the "command" field?

For example I could write a (CMake) script (not the debug target) which does the following:

  • FetchContent vcpkg
  • bootstrap vcpkg
  • vcpkg install (with some additional options to pass on the debugger pipe info)
  • vcpkg internally calls cmake -P which could be debugged
  • vcpkg internally calls cmake in configure mode which could be debugged

The intention of having a command field is to automate the process. E.g.
"command" : ["cmake", "-P", "my-internal-cmake-caller-script.cmake", "-DDEBUGGER_PIPE_NAME=<name_of_debugger_pipe>"]
DEBUGGER_PIPE_NAME is internally passed on to some process calling cmake. (doesn't really matter what it is)

But if "command" is added "workingDir" probably also makes sense to define where the command is executed.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That being said I am also happy with the current approach. It is just that it takes more manual labor for startup.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. I wonder if using a preLaunchTask is what you want. This way the pre launch task can be fully arbitrary. Do you think using that would suit your needs?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't know about that. If there is a possibility to detach then probably yes if it needs to return than probably no. Need to read up on that first.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tested and found that if you set up a tasks.json task with the following settings as part of that task:

"isBackground": true,
        // This task is run before some debug tasks.
        // Problem is, it's a watch script, and since it never exits, VSCode
        // complains. All this is needed so VSCode just lets it run.
        "problemMatcher": [
            {
            "pattern": [
                {
                "regexp": ".",
                "file": 1,
                "location": 2,
                "message": 3
                }
            ],
            "background": {
                "activeOnStart": true,
                "beginsPattern": ".",
                "endsPattern": ".",
            }
            }
        ]

then you can successfully have a preLaunch task.

Copy link

@Neumann-A Neumann-A Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I need some delay or some retry count to connect the debugger to the pipe since the debugger wants to start before the prelaunch task reached the point where the pipe is opened. (That being said: Hitting the run button simply twice works as expected; somehow vs code sees that the task is still running and does not rerun it.)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I think there is nothing to do here. I can just define a task and let it run via VS Code directly instead of manually typing it. Never used task since I mainly use CMake presets. Would be nice if there is a way to somehow get the pipename from a task.json via some variable.

* `script`
* required
* `scriptPath` - The path to the CMake script to debug.
* optional
* `scriptArgs` - Arguments for the CMake script to debug.
* `scriptEnv` - Environment for the CMake script to use.
* `pipeName` - Name of the pipe (on Windows) or domain socket (on Unix) to use for debugger communication.
* `dapLog` - Where the debug adapter protocol (DAP) communication should be logged. If omitted, DAP communication is not logged.

The `cmake` debug type only supports the `request` type: `launch`.
186 changes: 178 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"vscode": "^1.63.0"
},
"categories": [
"Other"
"Other",
"Debuggers"
],
"galleryBanner": {
"color": "#13578c",
Expand All @@ -49,6 +50,9 @@
"onCommand:cmake.executableTargets",
"onCommand:cmake.buildKit",
"onCommand:cmake.tasksBuildCommand",
"onDebugResolve:cmake",
"onDebugInitialConfigurations",
"onDebugDynamicConfigurations:cmake",
"workspaceContains:CMakeLists.txt",
"workspaceContains:*/CMakeLists.txt",
"workspaceContains:*/*/CMakeLists.txt",
Expand Down Expand Up @@ -692,7 +696,7 @@
},
"options": {
"type": "object",
"description": "%cmake-tools.taskDefinitions.properties.options.description",
"description": "%cmake-tools.taskDefinitions.properties.options.description%",
"properties": {
"cwd": {
"type": "string",
Expand Down Expand Up @@ -720,12 +724,52 @@
{
"type": "cmake",
"label": "%cmake-tools.debugger.label%",
"languages": [
"cmake"
],
"configurationAttributes": {
"launch": {
"properties": {
"scriptPath": {
"type": "string",
"descripttion": "%cmake-tools.debugger.scriptPath.description%",
"default": "script.cmake"
},
"scriptArgs": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "%cmake-tools.debugger.scriptArgs.description%"
},
"scriptEnv": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "%cmake-tools.debugger.name%"
},
"value": {
"type": "string",
gcampbell-msft marked this conversation as resolved.
Show resolved Hide resolved
"description": "%cmake-tools.debugger.value%"
}
}
},
"default": [],
"description": "%cmake-tools.debugger.scriptEnv.description%"
},
"dapLog": {
"type": "string",
"description": "%cmake-tools.debugger.dapLog.description%",
"default": ""
},
"pipeName": {
"type": "string",
"description": "%cmake-tools.debugger.pipeName.description%"
"description": "%cmake-tools.debugger.pipeName.description%",
"default": ""
},
"clean": {
"type": "boolean",
Expand All @@ -737,14 +781,140 @@
"description": "%cmake-tools.debugger.configureAll.description%",
"default": false
},
"dapLog": {
"cmakeDebugType": {
"type": "string",
"description": "%cmake-tools.debugger.dapLog.description%",
"default": ""
}
"enum": ["configure", "external", "script"],
"description": "%cmake-tools.debugger.debugType.description%"
}
},
"required": [
"cmakeDebugType"
],
"oneOf": [
{
"properties": {
"cmakeDebugType": {
"enum": [
"script"
]
},
"scriptPath": {
"type": "string",
"description": "%cmake-tools.debugger.scriptPath.description%",
"default": ""
},
"scriptArgs": {
"type": "array",
"items": {
"type": "string"
},
"default": [],
"description": "%cmake-tools.debugger.scriptArgs.description%"
},
"scriptEnv": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "%cmake-tools.debugger.name%"
},
"value": {
"type": "string",
"description": "%cmake-tools.debugger.value%"
}
}
},
"default": [],
"description": "%cmake-tools.debugger.scriptEnv.description%"
},
"dapLog": {
"type": "string",
"description": "%cmake-tools.debugger.dapLog.description%",
"default": ""
}
},
"required": [
"scriptPath"
]
},
{
"properties": {
"cmakeDebugType": {
"enum": [
"configure"
]
},
"clean": {
"type": "boolean",
"description": "%cmake-tools.debugger.clean.description%",
"default": false
},
"configureAll": {
"type": "boolean",
"description": "%cmake-tools.debugger.configureAll.description%",
"default": false
},
"dapLog": {
"type": "string",
"description": "%cmake-tools.debugger.dapLog.description%",
"default": ""
}
}
},
{
"properties": {
"cmakeDebugType": {
"enum": [
"external"
]
}
},
"required": [
"pipeName"
]
}
]
}
},
"initialConfigurations": [],
"configurationSnippets": [
{
"label": "%cmake-tools.debugger.configure.snippet.label%",
"description": "%cmake-tools.debugger.configure.snippet.description%",
"body": {
"type": "cmake",
"request": "launch",
"name": "%cmake-tools.debugger.configure.snippet.body.name%",
"cmakeDebugType": "configure",
"clean": false,
"configureAll": false
}
},
{
"label": "%cmake-tools.debugger.script.snippet.label%",
"description": "%cmake-tools.debugger.script.snippet.description%",
"body": {
"type": "cmake",
"request": "launch",
"name": "%cmake-tools.debugger.script.snippet.body.name%",
"cmakeDebugType": "script",
"scriptPath": "^\"\\${workspaceFolder}/<...>.cmake\""
}
},
{
"label": "%cmake-tools.debugger.external.snippet.label%",
"description": "%cmake-tools.debugger.external.snippet.description%",
"body": {
"type": "cmake",
"request": "launch",
"name": "%cmake-tools.debugger.external.snippet.body.name%",
"cmakeDebugType": "external",
"pipeName": "<...>"
}
}
}
]
}
],
"menus": {
Expand Down
15 changes: 15 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,21 @@
"cmake-tools.debugger.clean.description": "Clean prior to configuring.",
"cmake-tools.debugger.configureAll.description": "Configure for all projects.",
"cmake-tools.debugger.dapLog.description": "Where the debugger DAP log should be logged.",
"cmake-tools.debugger.scriptPath.description": "The path to the script to debug.",
"cmake-tools.debugger.scriptArgs.description": "Arguments for the script to debug.",
"cmake-tools.debugger.scriptEnv.description": "Environment for the script to use.",
"cmake-tools.debugger.name": "Name",
"cmake-tools.debugger.value": "Value",
"cmake-tools.debugger.debugType.description": "The type of the CMake debug session. Available options are: \"configure\", \"external\", \"script\".",
"cmake-tools.debugger.configure.snippet.label": "CMake: Configure",
"cmake-tools.debugger.configure.snippet.description": "Debug a CMake project configuration",
"cmake-tools.debugger.configure.snippet.body.name": "CMake: Configure project",
"cmake-tools.debugger.script.snippet.label": "CMake: Script",
"cmake-tools.debugger.script.snippet.description": "Debug a CMake script",
"cmake-tools.debugger.script.snippet.body.name": "CMake: Script debugging",
"cmake-tools.debugger.external.snippet.label": "CMake: External",
"cmake-tools.debugger.external.snippet.description": "Connect to an externally launched CMake invocation",
"cmake-tools.debugger.external.snippet.body.name": "CMake: Externally launched",
"cmake-tools.taskDefinitions.properties.label.description": "The name of the task",
"cmake-tools.taskDefinitions.properties.command.description": "CMake command",
"cmake-tools.taskDefinitions.properties.targets.description": "CMake build targets",
Expand Down
Loading
Loading