Hello everyone!
I’m creating this forum post to propose changes to the Swift extension for VS Code that will improve the out-of-box Swift debugging experience. Any feedback is greatly appreciated.
Motivation
The Swift extension currently relies on the CodeLLDB extension to provide debugging features which is maintained by an independent developer and includes a pre-built lldb
executable. However, this pre-built executable does not support Swift and requires User/Workspace settings to be applied in order to show variables and use the Swift REPL while debugging. The Swift extension displays a warning on startup if these settings are not applied, but this can be annoying since they need to be updated any time the Swift toolchain changes. Additionally, the auto-generated launch configurations created by the Swift extension frequently need to be updated when workspace settings change. This also pops up an annoying dialog asking for them to be updated.
The LLVM community has recently created their own official LLDB DAP extension for VS Code which can be used to launch debugging sessions via the lldb-dap
executable. The Swift extension can be modified to use this extension instead and point it at the lldb-dap
executable that is now available in Swift toolchain versions >=6.0.0. This will require some minor changes to the LLDB DAP extension, but this is a fantastic opportunity to collaborate.
New Launch Configuration Type
I would like to create a new launch configuration type called “swift”
that will be managed by the Swift extension. This new launch configuration type will be toolchain and debugger backend agnostic to make it more easily shareable via source control. The VS Code extension will delegate to the appropriate debug extension based on the current toolchain:
- lldb-dap: Will be the default option for toolchains >=6.0.0 as it is provided by the verified LLVM publisher and can be configured to use binaries from the toolchain directly.
- CodeLLDB: Will be used for toolchains older than 6.0.0. Needs some global configuration that requires paths within the toolchain to be set which we can prompt the user for when they try to launch a debug session for the first time. This message used to show on startup, but I think it makes more sense to prompt lazily.
This new launch configuration type will allow for three different launch types:
- Launch a Swift executable
- Attach to a Swift process by its PID
- Attach to a Swift process by name
Launch Executable
Launches and attaches to a Swift executable for debugging. The user must specify a program and any arguments/environment variables.
{
"type": "swift",
"request": "launch",
"args": [],
"env": {},
"cwd": "${workspaceFolder}",
"name": "Launch swift-executable",
"program": "${workspaceFolder}/.build/debug/swift-executable",
"preLaunchTask": "swift: Build Debug swift-executable",
}
Attach to Process
Attaches to a given process ID. Can use the built-in VS Code process selector to choose a process on launch.
{
"type": "swift",
"request": "attach",
"name": "Attach to Process",
"processId": "${command:PickProcess}",
}
Attach to Executable
Attaches to an already running Swift executable by name. Searches for the active program and attaches LLDB to it.
{
"type": "swift",
"request": "attach",
"name": "Attach to swift-executable",
"program": "${workspaceFolder}/.build/debug/swift-executable"
}
Additional Debugging Entry Points
The Swift extension should not automatically generate launch configurations. The standard point of entry for debugging in VS Code is to provide snippets to create launch configurations in the launch.json. However, it would also be nice to provide additional entry points to make debugging as discoverable as possible.
Code Lenses
SourceKit-LSP already provides code lenses for classes and structures decorated with @main. However, with a few minor changes it can be made to look a little bit cleaner:
- Include the name of the executable in the code lens: SourceKit-LSP knows about SwiftPM projects already and can provide this information easily.
- Add VS Code iconography to the code lens title: Can be done easily with middleware in the Language Client.
Editor Actions
VS Code provides a menu contribution point that can be used to insert commands that run/debug the active file. These commands will only appear when editing a Swift file that is part of an executable target and will launch a debug session of said target when clicked:
Extension Dependencies
Right now the Swift extension directly depends on CodeLLDB for debugging support. Given the switch to the LLDB-DAP extension, I propose that we remove the dependency on CodeLLDB and instead depend on the LLDB-DAP extension. Users on older Swift toolchains (<6.0.0) will get an error notification when they try to debug without CodeLLDB asking them to install CodeLLDB in order to do so. This notification will also mention that upgrading to Swift 6 is the recommended approach:
Final Thoughts
There are some open issues on the LLDB DAP extension that will need to be resolved before it can be used as a drop-in replacement for CodeLLDB:
- Breakpoints showing up as unresolved on startup: Breakpoints show up as Unverified (hollow gray circle) in lldb-dap · Issue #112629 · llvm/llvm-project · GitHub
- Add a process picker like CodeLLDB has: [lldb-dap] impl `${command:pickMyProcess}` please · Issue #96279 · llvm/llvm-project · GitHub
- Add the ability to attach to a process by name
- Allow setting the lldb-dap executable path in the launch configuration