May 9, 2021
Last week I wrote about how to install and use lldb-vscode and Emacs dap-mode to visually debug Swift Package Manager projects outside of Xcode. Unfortunately the process still depended on the
LLDB.framework packaged with Xcode, which meant that you still needed a Mac with Xcode installed.
In this post we'll go through a similar process, except we'll do it on Linux and without any need for Xcode. By the end you'll be able to use Emacs (or VSCode or other editor that can use VSCode extensions) to visually debug Swift Package Manager projects on Debian 10 ("buster").
Building Swift requires a newer
binutils than the one included with Debian 10. I think it's related to this bug in ld. We'll need to upgrade to the unstable version of
binutils (2.35.2 as of this writing).
First, enable the unstable and testing repos for apt.
Now, install the unstable
sudo apt update sudo apt-get install binutils/unstable
ld --version. You should see
2.35.2 or newer.
I think that if you install a new version of
ld (like we just did) you need to configure it so that linked executables correctly look for libraries in
/etc/local/lib. On Debian 10 we just need to run:
I'm starting with a fairly minimal installation of Debian 10 so I'll need to install some dependencies that you may or may not need. This will vary for other distributions of course.
sudo apt-get install cmake ninja-build libedit-dev libpython3-dev libcurl4-gnutls-dev libsqlite3-dev
Last week we cloned the
llvm-project repository and built it standalone, without Swift. This time we'll clone the Apple Swift project and use its build scripts to pull in and build
llvm-project as a dependency. This is the longest step of this procedure so leave yourself ample time.
My personal projects directory is
~/Proj and I'll be using it through the rest of this post. Feel free to substitute your own.
cd ~/Proj git clone https://github.com/apple/swift git checkout swift-5.4-RELEASE ./utils/update-checkout --clone ./utils/update-checkout --tag swift-5.4-RELEASE ./utils/build-script \ --clean \ --lldb \ --llbuild \ --release --no-assertions \ --xctest \ --foundation \ --libdispatch \ --libicu \ --swiftpm \ --install-destdir="~/Proj/swift-install" \ --install-all
I had this fail several times, each time with a missing library dependency. If that happens to you install the missing library with
sudo apt-get install and then reissue the same
./build-script command but omit the
--clean flag. This will allow the build to pick up from roughly where it left off.
Eventually you'll have a fully built Swift project in the
sudo cp -R ~/Proj/swift-install/usr/* /usr/local/
Create the required directory in your home folder and copy the extension:
mkdir -p ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin cd ~/Proj/build/Ninja-Release/lldb-linux-x86_64 cp bin/lldb-vscode ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin
For some reason the
build_script doesn't create the
package.json file required for the
lldb-vscode extension. You can download the one we built last week and save it into this directory:
You should now be able to start
lldb-vscode. From the command-line
cd ~/.vscode/extensions/llvm-org.lldb-vscode-0.1.0/bin ./lldb-vscode
If you don't see any errors you're in good shape. Hit Ctrl-C and let's continue.
You can use any SwiftPM project for this step but we'll continue to use Vapor for our example. I'm using version 3.1.9 here but choose whatever you like.
cd ~/Proj git clone https://github.com/vapor/toolbox.git cd toolbox git checkout 3.1.9 make install
vapor --help to confirm that it is installed. Now create and build the Hello World project.
cd ~/Proj vapor new hello -n cd hello swift build
Assuming you're using Emacs and have installed and configured dap-mode (you can read more about this in last week's post), you need to add a debug template to your Emacs config for the Hello World we've just built. Here's the one I'm using.
(dap-register-debug-template "Vapor Hello World Linux" (list :type "lldb-vscode" :cwd "/home/gene/Proj/hello/.build/x86_64-unknown-linux-gnu/debug" :request "launch" :program "/home/gene/Proj/hello/.build/x86_64-unknown-linux-gnu/debug/Run" :name "Run"))
Evaluate this region or reload your Emacs config.
The steps in this section are identical to what we did on the Mac last week.
In Emacs, start debugging with
M-x dap-debug. Select the template you just added: that should launch the Vapor web server and the Hello World app.
Find the file
Sources/App/routes.swift in the Hello World project. Move the point to the line that says
return "It works!" (line 5 for me). Issue
M-x dap-breakpoint-add. You should see a breakpoint indicator dot appear to the left of the line.
Open a web browser and navigate to
http://127.0.0.1:8080. Your breakpoint should hit and you'll see something like this.
Under Locals (top-right on my screen), if you click on
req it will expand and show you the Vapor request properties at the time your breakpoint was hit.
The stack trace is available by clicking the
Run label in the
Debug Sessions pane. To stop debugging issue
And there we have it: a full visual debugging solution for Swift Package Manager projects in Linux, with no Xcode required.