I\'m new on Visual Studio Code and Docker. Now I want to use Visual Studio Code to edit my C++ code and Docker to compile/debug.
I don\'t know how to write the launch.js
This answer assumes that you are not trying to do anything with multiple containers... I'm assuming that you just want to use a single container to build some C++ code, and that all of your code is in a folder called C:\vsc_docker_cc_gdb
. I also assume you have the C++ and Docker extensions from Microsoft installed in Visual Studio Code.
Let's start with a simple C++ file, called hello.cc:
#include <iostream>
int main(int argc, char **argv) {
std::cout << "Hello from Docker" << std::endl;
}
Let's also add a Makefile:
CXXFLAGS = -O3 -ggdb -m64
LDFLAGS = -m64
all: hello.exe
.PRECIOUS: hello.exe hello.o
.PHONY: all clean
%.o: %.cc
$(CXX) -c $< -o $@ $(CXXFLAGS)
%.exe: %.o
$(CXX) $^ -o $@ $(LDFLAGS)
clean:
rm -f hello.o hello.exe
Here's a Dockerfile that extends gcc:latest
by adding GDB and gdbserver (note: I'm not sure gdbserver is needed):
FROM gcc:latest
LABEL Name=vsc_docker_cc_gdb Version=0.0.2
RUN apt-get -y update
RUN apt-get -y install gdb gdbserver
WORKDIR /root
Here's .vscode/tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "build (in container)",
"type": "shell",
"command": "docker run --privileged -v c:/vsc_docker_cc_gdb/:/root vsc_docker_cc_gdb make",
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"owner": "cpp",
"fileLocation": [
"relative",
"${workspaceFolder}"
],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
},
{
"label": "clean (in container)",
"type": "shell",
"command": "docker run --privileged -v c:/vsc_docker_cc_gdb/:/root vsc_docker_cc_gdb make clean",
"group": "build",
"problemMatcher": []
},
{
"label": "remove containers",
"type": "shell",
"command": "docker ps -a -q | % { docker rm $_ }",
"problemMatcher": []
},
{
"label": "run the code",
"type": "shell",
"command": "docker run --privileged -v c:/vsc_docker_cc_gdb/:/root vsc_docker_cc_gdb ./hello.exe",
"group": "build",
"problemMatcher": []
},
{
"label": "prepare to debug",
"type": "shell",
"command": "docker run --privileged -v c:/vsc_docker_cc_gdb/:/root --name debug_vsc -it vsc_docker_cc_gdb ",
"group": "build",
"problemMatcher": []
}
]
}
And finally, .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [{
"name": "(gdb) Pipe Launch",
"type": "cppdbg",
"request": "launch",
"program": "/root/hello.exe",
"cwd": "/root",
"args": [],
"stopAtEntry": true,
"environment": [],
"externalConsole": true,
"pipeTransport": {
"debuggerPath": "/usr/bin/gdb",
"pipeProgram": "docker.exe",
"pipeArgs": ["exec", "-i", "debug_vsc", "sh", "-c"],
"pipeCwd": "${workspaceRoot}"
},
"MIMode": "gdb",
"setupCommands": [{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}]
}, ]
}
There are two important things here. The first is that you'll notice that parts of launch.json are referring to paths in the container (/root/) and others are referring to paths on the Windows host (workspaceRoot). That is important.
The second is that you'll need to have a container running, and then you can launch a debug process into it. Here's a recipe to go from zero to starting that special container and launching a debugger in it.
docker pull gcc
From there, the Visual Studio Code Debug Console should work, and you should be able to set breakpoints, watch variables, and enter debug commands.
I set up a minimal working example on GitHub: https://github.com/fschwaiger/docker-cpp-vscode
The idea is as follows, assuming you have the ms-vscode.cpptools
extension:
gcc
and gdb
installed (can be the same)gdb
from within the containergcc
and gdb
gcc
is available directly from Docker Hub: docker pull gcc
. I did not find gdb
there, so there is a Dockerfile to build it:
FROM gcc:latest
RUN apt-get update && apt-get install -y gdb
RUN echo "set auto-load safe-path /" >> /root/.gdbinit
It builds on gcc:latest
and installs gdb
, so you can use the same image to compile and debug. It also sets option set auto-load safe-path /
in /root/.gdbinit
to suppress a warning when running gdb
in the container. Safety should not be a concern for local development.
Build the image using docker build -t gdb .
in the working directory, or in Visual Studio Code run the preconfigured task build docker gdb
from F1 → Run Task.
In the project, run docker run --rm -it -v ${pwd}:/work --workdir /work gcc make debug
from a PowerShell window in the working directory. Using Visual Studio Code, this can be done by the preconfigured task make debug
from F1 → Run Task.
You want to configure Visual Studio Code to run /usr/bin/gdb
from within the container. You can use the pipeTransport
option in launch.json
for that and make it run:
docker run --rm --interactive --volume ${workspaceFolder}:/work --workdir /work --privileged gdb sh -c /usr/bin/gdb
Explanation:
--privileged
: allow binary debugging--volume ${workspaceFolder}:/work --workdir /work
: mount the project folder into the container--rm
: remove the container after exit--interactive
: VSCode will issue interactive commands to the gdb shellsh -c
: defines a shell entrypoint within GDB is runThe overall launch.json
looks like follows. Notice that program
and cwd
are the paths within the container. sourceFileMap
allows the debugger to match the breakpoints with the source files. The rest is the default template stuff from the C++ extension.
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Docker",
"type": "cppdbg",
"request": "launch",
"program": "build/apps/program",
"args": [],
"stopAtEntry": true,
"cwd": "/work",
"environment": [],
"externalConsole": true,
"preLaunchTask": "make debug",
"targetArchitecture": "x64",
"sourceFileMap": { "/work": "${workspaceFolder}" },
"pipeTransport": {
"debuggerPath": "/usr/bin/gdb",
"pipeProgram": "docker.exe",
"pipeArgs": ["run","--rm","--interactive","--volume","${workspaceFolder}:/work","--workdir","/work","--privileged","gdb","sh","-c"],
"pipeCwd": ""
},
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
With this setup, all you need to do is press play in the debug workspace.