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

Conversation

gcampbell-msft
Copy link
Collaborator

@gcampbell-msft gcampbell-msft commented Aug 3, 2023

This change addresses item #3248 as well as adding functionality.

This updates the options that are available in launch.json for the cmake debug type.

The following changes are proposed:

  • Add required cmakeDebugType to the launch.json that defines whether the user is trying to debug under the three available modes: configure, external, script.
  • Add the ability to debug externally launched CMake processes, or to debug a CMake script.
  • Adds an activation event when a debug session of type cmake is initiated.
  • Remove the check for whether cmakeDebugType is external regarding dapLog. We can simply assign it unconditionally, knowing that it will be ignored in the external mode. In script and configure it will be used as normal.
  • Adds the ability to run and debug CMake script files when there is no launch.json present through the "Run and Debug" button.
  • Adds initial snippets that help people create launch.json configurations.

The purpose of this change is to add the ability to debug externally launched CMake processes or debug Cmake scripts.

@gcampbell-msft
Copy link
Collaborator Author

NOTE: This should not be merged before we release 1.15.

@Neumann-A
Copy link

I got:
image
with the script stuff.

External debugging worked as expected.

Configure debugging still cannot be stopped if the pipe never connects. This only happens if you trick code to use a different CMake which only reacts like CMake without the debugger; e.g. set "cmake.cmakePath" to a batch file with the following:

@ECHO OFF
SETLOCAL EnableDelayedExpansion

set call_cmake=1
REM Call CMake always except if the debugger should be attached
FOR %%a IN (%*) do (
    set "_arg_=%%a"
    if !_arg_!==--debugger set call_cmake=0
)

@ECHO OFF
if !call_cmake!==1 cmake.exe %* && Exit /B %ERRORLEVEL%

* `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.

@gcampbell-msft
Copy link
Collaborator Author

gcampbell-msft commented Aug 4, 2023

I got: image with the script stuff.

External debugging worked as expected.

Configure debugging still cannot be stopped if the pipe never connects. This only happens if you trick code to use a different CMake which only reacts like CMake without the debugger; e.g. set "cmake.cmakePath" to a batch file with the following:

@ECHO OFF
SETLOCAL EnableDelayedExpansion

set call_cmake=1
REM Call CMake always except if the debugger should be attached
FOR %%a IN (%*) do (
    set "_arg_=%%a"
    if !_arg_!==--debugger set call_cmake=0
)

@ECHO OFF
if !call_cmake!==1 cmake.exe %* && Exit /B %ERRORLEVEL%

This may be because I haven't done any handling of variables. To confirm, could you attempt it again by putting either a relative or full path?

UPDATE: Actually, this seems to already be natively handled from launch.json. I realized I wasn't handling a case where scriptEnv was undefined. Could you please try it again?

@gcampbell-msft gcampbell-msft added this to the 1.16 milestone Aug 4, 2023
@Neumann-A
Copy link

Could you please try it again?

If you give me a new vsix, then yes. One problem I have is that code always tries to reinstall the current release extension.

@Brian-Ruff-CardinalPeak
Copy link

This PR was a timely discovery for me; I need to debug a cmake issue with several subprocess invocations of cmake. Is there an existing mechanism to get .vsix files for this branch? I was able to attach the debugger to the initial cmake process via configure/reconfigure with CMake debugger, but am not yet having success with an external to attach to a subprocess. I pulled the branch and was able to create a .vsix - I haven't done much with VSCode extensions at all.

@Brian-Ruff-CardinalPeak
Copy link

One item I noted, it seems like an extension can provide seed/snippets via the Add Configuration UI, though I'm not familiar with the mechanism/API.

@gcampbell-msft
Copy link
Collaborator Author

@benmcmorran @snehara99 This PR is ready for review and testing.

@gcampbell-msft
Copy link
Collaborator Author

@snehara99 @benmcmorran ping for review.

benmcmorran
benmcmorran previously approved these changes Aug 16, 2023
docs/debug.md Show resolved Hide resolved
docs/debug.md Outdated Show resolved Hide resolved
docs/debug.md Outdated Show resolved Hide resolved
docs/debug.md Outdated Show resolved Hide resolved
docs/debug.md Outdated Show resolved Hide resolved
package.json Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
package.json Outdated
"request": "launch",
"name": "%cmake-tools.debugger.script.snippet.body.name%",
"cmakeDebugType": "script",
"scriptPath": "^\"\\${workspaceFolder}/<...>\""
Copy link
Member

Choose a reason for hiding this comment

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

What's the ^ for? Does this act as a regex? If it's not, we can probably hardcode something like <script>.cmake even though it won't exist just to make the example clearer.

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 don't think so. I copied it from somewhere and it seemed to simply allow us to insert it without resolving the ${workspaceFolder} to an actual value.

When I created an automatic debug configuration using this, this is what appeared:
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@benmcmorran ping for review.

Specifically, #3277 (comment)

src/debug/debugConfigurationProvider.ts Show resolved Hide resolved
src/debug/debuggerScriptDriver.ts Outdated Show resolved Hide resolved
@Neumann-A
Copy link

@gcampbell-msft Is this waiting on something?

@gcampbell-msft
Copy link
Collaborator Author

@gcampbell-msft Is this waiting on something?

We are pending another code review. Our team hopes to get on this in the next week or two, thank you for the ping!

benmcmorran
benmcmorran previously approved these changes Sep 15, 2023
benmcmorran
benmcmorran previously approved these changes Sep 20, 2023
@gcampbell-msft gcampbell-msft enabled auto-merge (squash) September 20, 2023 17:20
@gcampbell-msft gcampbell-msft merged commit 661e9ed into main Sep 20, 2023
2 of 4 checks passed
@gcampbell-msft gcampbell-msft deleted the dev/gcampbell/ScriptModeDebugger branch September 20, 2023 17:20
@gcampbell-msft
Copy link
Collaborator Author

Merging without tests because they passed prior to the changelog changes, and the changelog doesn't affect tests.
The Windows tests fail due to other changes, they are not due to this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants