Debugging C++ in a container with VS Code, Fig. Why so hard? This option tells the debugger to map /source on the remote to our local path so that our sources our properly found. All rights reserved. RUN echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config && \, echo 'PermitEmptyPasswords yes' >> /etc/ssh/sshd_config && \, echo 'PasswordAuthentication yes' >> /etc/ssh/sshd_config && \, RUN apt-get update && apt-get install -y docker.io. name - This is the name that appears in the debug dropdown menu. This made us decide to try the clangd extension first, and were happy to report that it works really, really well. Looking forward, we will introduce a helper container that provides a proxy for our service and to deploy our containers to Azure. #-------------------------------------------------------------------------------------------------------------. The steps are divided in three main groups: To compile and debug applications on VSCode, you should install the following extensions: If you need some help to install extesions on VSCode, please follow the official tutorials. As always, we welcome your feedback. Embedded Systems and Cross Compilation Primer. This is so that when we edit files on our host those changes are available in the container without having to rebuild the image or copy them into the running container. venvx: Managing Multiple Python *2* Virtual Environments, Rube Goldberg Machines: OpenID Authentication Process, Why so hard? This installed three extensions: Remote - SSH, Remote - Containers, and Remote - WSL. I found that VSCode has the capability to target a container for application building and/or debugging :). I have created an image for vscode-devcontainer with GCC, CMake and Vcpkg which makes installing popular dependencies very easy, you can check it at: https://hub.docker.com/r/aharonamir/vscode-remote-gcc-vcpkg. This task has already been created in tasks.json under the .vscode folder in the repo were using with this post. "description": "Enable pretty-printing for gdb", // type specific configuration attributes. #MicroPython: Taking photos with an ESP32-CAM. Login to edit/delete your existing comments, This is the only place Ive found information on the ssh command, really useful arcticle, thanks! The first one is required to remotely build and debug applications. To build this image, type the following on a terminal inside the folder, in which you created the Dockerfile file: The image will be built with a name gdb-cpp-image. code-server downloads aarch64 version of C/C++ extension. If you are on Windows, or you want your IntelliSense to exactly match your target system, you will need to get your headers onto your local machine. Basically youre Dockerfile should start the same as the Develop Dockerfile, then add the CMake commands to build the target/s, after this stage is completed you start a new stage from a minimal image (the minimal OS you compiled on, e.g ubuntu:18.04/Alpine etc) and copy only the target and its dependencies (libs) to the new image, the trick here is to use ldd for finding the shared libs. Therefore in this container definition we will use interactively we are mapping our local src directory to /source so it doesnt conflict with what is already present in the build container. The configuration we need is not one of the default options, so once you have your tasks.json select Add Configuration and choose C/C++: (gdb) Pipe Launch. Im following along but using VS Code on linux and my project successfully builds inside the container and displays the ouput in terminal tab. Inform me every time a new article is published, Get periodic summaries and other interesting news, #VSCode: C++ Development and Debugging using containers, #Raspberry Pi 4: Hardware accelerated video decoding (GPU) in Chromium, #Raspberry Pi HQ Camera: Autofocus for the Telephoto Lens (JiJi). Note that our build container copied our src directory to /src. Something to point out here is that it isn't just a matter of volume mounting for the win we must also add docker to our code-server image and setup permissions so the container docker matches to host docker service group ids and user ids. With this in mind, we started looking at the remote Docker support of VS Code. and a DRM solution! The provided launch.json is configured to break on entry ("stopAtEntry": true,) so you can immediately see that it is working. Thanks for waiting! Python, Node). Now with a new arsenal of toolchains and development environments that I've been accumulating throughout 2020, I want to reacquaint myself with runtime debugging. : Building Firmware Images without GNU, Use Case: Running Application Containers With Different Credentials per Project, Use Case: You're Away From Home And Your Windows VM Host Reboots, Bare Metal CMake Development: Multiple Toolchains and Containers. Common task definitions include actions like, build, clean, run, unit test, and so forth. Throughout this series of posts we have been using vcpkg to get our libraries. We needed extensions for this, and luckily, VS Code has a ton of them! the launch.json setup is pretty straightforward: After debugging and building your targets you can use a multi-stage build Dockerfile for creating an image with your target and its dependencies. We automatically test our C++ code on each platform we support, but the easiest setup we have is for testing on Linux using Docker. That container already has all our basic development prerequisites, but for VS Code usage we need a few more things enumerated above. 3: Is It Worth the Time? If you use vcpkg on your host system, and have acquired the same libraries using it, then your IntelliSense should work for your libraries. Wed love to hear from you about what youd like to see covered in the future about containers. If you look at Dockers documentation, youll find that volumes are usually preferred over bind mounts today. There are several known ways to accomplish this connection with a containerized debugger. Because were using Debian, we used mcr.microsoft.com/vscode/devcontainers/base:0-debian-10. If you encounter other problems or have a suggestion for Visual Studio please let us know throughHelp > Send Feedback > Report A Problem / Provide a Suggestion in the product, orviaDeveloper Community. Therefore, after the incorrect group addition, we remove that group and add our own with our own host matched group id. This brought major advantages like not having to deal with RDP or VNC and not having to worry about host setups. The other new parameter were using is -v, which creates a bind mount that maps our local file system into the container. I created a build-image.sh script to fetch and inject that bit for me. However, sharing source code with a container is considered a good use of a bind mount. One of the new parameters we havent covered before is security-opt. # Licensed under the MIT License. code-server is basically a way for me to host Visual Studio Code over a web connection so that no matter where I go, so long as I have access to the code-server host, I can bring up the Visual Studio Code from that host with all the same (saved) settings. Because the debugger in VSCode has to maintain a constant connection with the debugger, setting this up is a lot less straight forward than setting up tasks. We prefer using LLDB as our debugging tool of choice, mostly because this is what is automatically available when using Xcode, and we wrote our own small extensions to make things easier. environment - Any additional environment variables to inject into the debugged process can be performed here. // This mounts the workspace. My container simply run a sleep infinity, Puede ser mucho mas simple, // Tell the CMake extensions where to find CMake. Since code-server is a service, I always launch it with docker-compose up -d. My docker-compose.yaml looks like: Assuming docker is working from code-server integrated terminal, you should now be able to proceed to the next sections. Think Twice. The task is usually defined in a tasks.json file inside the .vscode folder. If all of this were to work out, wed be able to work more quickly than we can now, even using an old laptop! I usually have a build script for my docker images so that I don't have to retype/fat-finger the image name for each rebuild or update. We use cookies to improve our services. This post builds on using multi-stage containers for C++ development. Our code works on many different compilers, but most platforms use Clang. Do you know I can set this up? When you are done with your development simply stop the container. "source=${localEnv:HOME}/Work/PSPDFKit,target=/workspace,type=bind,consistency=cached", DEVELOPMENT | Web Docker Server Insights. First, lets configure a building task. As you may have noticed, you need to create this build.sh file aside your source code. # will be updated to match your local UID/GID (when using the dockerFile property). Assuming you already had the container up and running, you can setup the debug session's pipeTransport with something like the following for an SSH tunnel, assuming you know the user/ip/port and have credentials for the SSH connection. sourceFileMap - This maps the container path to the VSCode path for source file mapping. We wont go too much into the specifics of configuring them because this is out of scope for this blog post, but in general, they all mostly just worked. By user, I mean I would always use GDB from the command line without TUI, performing breaks, watches, examine, and control commands. Docker: Automating the over-the-shoulder Docker setup help. If you have the docker run capability from VSCode (as we do), than you can setup a pipe transport for this channel. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. The debugger path option is the default and is correct for this example. Configuring the devcontainer.json was the next step. This means that its really up to the user how they intend to use it for development. The source for this article is the same as that of the previous article: the findfaces GitHub repo. Python, node, and chrome debugging is managed quit differently and thus isn't really covered here. Tom. The command here is ssh (which is available on Windows 10). Is this to do with intelisense not being set up properly? Heres the one were using, with extra comments: With both of these files, we were able to try running this on a local Docker! You should consider that this Docker image should have all libraries that you need to compile your application. Before we start, lets set all the extensions we need in VSCode: After the Remote-Containers extension installed, you will see a new Status bar item at the far left. Thank you, // We add extra permissions which are needed for debugging, etc. For our purposes, we want a task to be able to build our code. My goals are to be able to build my code with a containerized toolchain, debug my builds with a containerized environment, and manage as much of this in the VSCode Server GUI as much as possible (from a containerized code-server.) We found the VS Code extension CodeLLDB worked pretty much out of the box. Notably, we need SSH for communication with VS Code for debugging which is configured in the RUN command. It will start building the image, then run the image and map the folder onto the running container. Bare Metal on Raspberry Pi 4: Getting Started, Remote Containerized Debugging with VSCode C/C++. Microsoft has some more information about this here. // Specifies where to find the Dockerfile to use. This will automatically create a docker group that will likely not match the host docker group's gid number. The arguments are passing the parameters to sshpass to login using ssh to the container with the correct password (root), port (2222) and the run script after the log-in (/source/build.sh). Lets look at another Dockerfile for use with VS Code, Dockerfile.vs. For testing, we found C++ TestMate, which also just worked. Love podcasts or audiobooks? I've created one with the following Dockerfile: A Quick Note: I 100% prefer to use lldb for debugging and have attempted to use lldb with the following process for quite a few hours without success. Why So Hard? Note: When I attempted to install this from VSCode Marketplace, it actually installed the ARM64 version of the extension in my x86_64 Ubuntu VM. Here well show how our setup looks. // Specifies where the workspace can be found in the running container. For general debugging/debugger usage, please refer to the official documentation. Here is an example task.json to accomplish this with our toolchain docker image: This task essentially launches a short lived docker container that simply builds the binary and then destroys itself. We can be reached via the comments below or via email (visualcpp@microsoft.com). Youll want to modify the following options in the generated Pipe Launch configuration. Reload the page and try again! The above parameters in the configuration specify the program to launch on the remote system, any arguments, whether to stop at entry, and what the current working directory on the remote is. Also, out of pure laziness I've added user abc to the docker group because that happens to match my uid, but using the docker group id approach could be done for the user id as well. Note that the vscode remote container images adds a non-root user vscode, so youll need to switch to USER root before doing running root privileged commands, dont forget to switch to USER vscode after to avoid permission issues after. On Linux, the container user's GID/UIDs. I prefer to think of it as a toolkit of development widgets with an amazing community and sane defaults built in. Were excited to see more people in the C++ community start producing their own content about using C++ with containers. Remember that in this example we have our output configured under our source directory on the host. After this is set up, you can run a build at any time from within VS Code, as long as your container is running. The -p parameter links the port 2222 to the exposed 22 port of the container. # Required for /var/run/docker.sock mapping. // we decided to checkout our repository in `$HOME/Work/PSPDFKit`. Security is not a priority at the moment, but security should be considered with all decisions for easier mitigation later on. It did not show you how to use a containers with your development environment. Since CMake runs inside the container it sees all the installation except vcpkg, We need to add the vcpkg toolchain, include and libs: Since the remote container contains a vscode agent, the debugging is like local debugging, only it runs on the remote container. The conclusion from that article is that, for our purposes, we must volume mount /var/run/docker.sock into our code-server docker image so it can control the host docker and sibling containers. As we are enabling root login, this container definition is not appropriate for anything other than local development. Last week, I was working on a C++ application on a remote machine in the cloud, and I didn't want to install all the compiling and debugging tools/libraries/dependencies on the host OS, but I wanted to have all of them in a container. Here is the Dockerfile I constructed to extend the linuxserver/code-server docker image: What we're doing here is first installing the docker engine via APT. Despite the huge potential for C++ in the cloud with containers, there is very little material out there today. How to Bypass Anti-Scraping Tools on Websites? The pipe arguments are just the parameters to pass to ssh to start the remote connection. Think Twice. here is an example multi-stage build Dockerfile: This way the created image is much smaller. Major security ramifications here, we could alternatively use keys. VSCode will build the image and re-open the project inside the running container, then you can start developing as usual. The next block shows how to start the pipe. If you could spare a few minutes to take our C++ cloud and container development survey, it will help us focus on topics that are important to you on the blog and in the form of product improvements. Someting went wrong! The content of that script reads as follows: Don't remove the -DCMAKE_BUILD_TYPE=Debug flag, otherwise you won't be able to debug the compiled code. Our configured build task appears as follows. export DOCKER_GID=`echo $DOCKER_ENT | cut -d: -f3`, - /var/run/docker.sock:/var/run/docker.sock, - /home/$USER/.gitconfig:/config/.gitconfig. # To fully customize the contents of this image, use the following Dockerfile as a base and add the RUN statement from this file: # https://github.com/microsoft/vscode-dev-containers/blob/v0.112.0/containers/debian-10-git/.devcontainer/Dockerfile, mcr.microsoft.com/vscode/devcontainers/base:0-debian-10, # This Dockerfile's base image has a non-root user with sudo access. We could see which environment we were running in by looking at the bottom-left of VS Code: Once we got everything running locally in Docker, we were able to move on to getting it to run remotely! Hit F5 to start debugging in the container. Copyright 2010-2022 PSPDFKit GmbH. Your comment has been updated! We simply chose Remote-Container: Open Folder in Container again and VS Code connected to our configured server, built the Docker container, and connected to it. For this command the container need not be running. The command here is sshpass (which needs to be installed on your OS - sudo apt-get install sshpass). More often I have been able to get away from using debuggers by simply getting better at static analysis through tools like objdump. This can all be found in the documentation. # !! Microsoft has several base Docker images for use with VS Code, one of which we used as our base. Open VSCode in the project folder, click on the remote-container status icon and choose Remote-Containers: Add Development Container Configuration Files , Then you can choose Existing Dockerfile..(Ext) , this will create a .devcontainer folder with only a devcontainer.json file which will have the keys: dockerFile: Dockerfile, and context: .. , which points to a Dockerfile in your project folder (Its better to call it Dockerfile.develop to distinguish from the Dockerfile of the final running image), in that Dockerfile you can choose which remote container image to use, you have a full list at: https://hub.docker.com/_/microsoft-vscode-devcontainers and start adding your dependencies. Hope this post was helpful, give me a if you liked it. The -v parameter creates a bind mount that maps the local file system ($PWD - print working directory) into the container (/source). Build Systems for Embedded Development: From 30000 feet. Versatile networking shell scripts with gethostbyname() and ip_route_addr(). The entry point for this container is SSH specified in the CMD line. #Nginx: Docker, Flask and Let's Encrypt (SSL), #Raspberry Pi: Controlling Philips HUE Lights (ZigBee & CC2531), #Portainer: Managing Docker Engines remotely over TCP socket (TLS), #MicroPython: VSCode IntelliSense, Autocompletion & Linting capabilities, #Zigbee: Reading Xiaomi Sensors with a Raspberry Pi (no Xiaomi gateway needed!). Why so hard? The content of that script reads as follows. In addition to shell commands, task types can be defined from extensions for more advanced usage (e.g. Here we will show how to use those containers with VS Code. program - This is the path of the binary to debug (from the perspective of the container). # Copyright (c) Microsoft Corporation. In contrast, if you can't use docker for accessing the process to be debugged for any reason, you can also use SSH as the pipe transport. The provided launch.json is configured to break on entry so you can immediately see it is working. Building this container is simple. After compiling our test binary, it simply picked it up and showed the available tests, and we were able to run them. That directory will be copied into the build container if you dont delete it (which you dont want), so delete the output directory contents before rebuilding your containers (or adjust your scripts to avoid this issue). The first thing we needed to do was install the remote development extension. Linux Is DOS: Windows returns to its roots. As an alternative to scp, you can also use Docker directly to get your headers. Microsoft announced a while ago that it added support for using Visual Studio Code remotely. with VSCode Remote Container you can . You can also find us on Twitter (@VisualC). Your comment has been submitted! We plan to continue our exploration of containers in future posts. Youll note here that pipeProgram is not just ssh, the full path to the executable is required. In this post, well be using the Remote - Containers extension. There are several options on how to configure this, but. Follow the signs from there to install and reload vscode. In the FROM statement were basing this definition on the local image we created earlier in our multi-stage build. In our case, this is our. Well need to change our container definition a bit to enable using it with VS Code. https://github.com/newsages/docker-cpp-dev. Here are a list of the ones I've found most commonly used: A nice tip I got from the bottom of the documentation on these variables Use an echo task to output the value of a variable if its in question: Similar to how we were able to setup tasks in VSCode, we can setup special debug sessions for VSCode. // We configure clang-10 as our default compiler. // Set *default* container-specific `settings.json` values on container creation. System headers are another thing. When your project is ready, you can stop the container using: This setup helps you reducing your time while writing, compiling, and debugging C++ applications. substitution variables provided by VSCode, Building Code With Containerized Toolchain from Container, Debugging Builds With Containerized Debugger. First, lets configure our build task. The trick is that we are invoking this via ssh in our container. Its based on an example Dockerfile created by VS Code, along with additions from our own Dockerfile that we use to compile our code on our build servers. That post showed how to use a single Dockerfile to describe a build stage and a deployment stage resulting in a container optimized for deployment. There are a couple of ways you can setup IntelliSense for use with your C++ code intended for use in a container. But still we had to have some stuff on our machine, e.g if we wanted to see the third-party include files, we had to have them on our machine, IntelliSense issues and more. Now you can configure your C++ IntelliSense to use those locations. To continue we need to install a crucial dependency, the C/C++ Extension. To configure it in a new project, press Ctrl+Shift+B and follow the prompts until you get to other. In addition to having the extension installed, we also need a toolchain/debugger docker image to work with. However in my code there are various warnings I expect to see when building. type - This is the string that indicates which extension is going to handle the launch. The trick is that we are invoking this via ssh inside the container. The following lines install and enable SSH with user and password root:root and expose the port 22. cwd - Current working direction (from the perspective of the container). If you have already a running project, you can create this file by yourself. We need to specify a bit more to run a container based on this image so VS Code can debug processes in it. The configuration consists of two files. Create a Dockerfile inside a folder and add the following in that file: I like to use Debian images because of Debian simplicity. Github Webhooks, Jenkins, and Docker Oh My. As debugging requires running privileged operations, were running the container in unconfined mode. Anonymous statistical cookies help to understand how visitors use the website. Is it possible to debug a gcc-compiled program using lldb, or debug a clang-compiled program using gdb? We needed SSH access to a host that had Docker installed, and we had to make sure our code was checked out at the location specified in the devcontainer.json. As debugging requires running privileged operations, you'll run the container in unconfined mode, thus the --security-opt set to seccomp:unconfined. linux.MIMode - This is the machine interface mode and can be. // For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.112.0/containers/cpp. Therefore, to configure/create it in a new project, press Ctrl+Shift+B and follow the prompts until you get to "Others" (see Fig. Therefore I've installed gdb as a dependency for VSCode but fully intend on using lldb for any manual debugging sessions. Create a directory where you want to save your headers, navigate there in your shell, and run the following command. 1). Using Docker-in-Docker for your CI or testing environment? To bring up the Debug view, click the Run icon (Ctrl+Shift+D) in the Activity Bar and create a launch.json file and select the option C/C++: (gdb) from the prompt. A bit of looking around found the github issue code-server downloads aarch64 version of C/C++ extension. These sessions are defined in .vscode/launch.json. We need to add one new parameter at the end of the configuration. : QEmu User Networking and Dropbox. At PSPDFKit, we have a pretty big C++ codebase, which is something that can easily suffer from too little computer power, so we figured wed look into using the new remote support! The path in the example above is the full path to ssh on Windows, it will be different on other systems. stopAtEntry - Whether or not to break at start of the program execution. The build output also shows in the output tab and not the terminal tab. Microsoft has documentation on how to get Docker installed here. This enables us to have much more CPU power available, which big C++ projects definitely need. This container will be accessed via SSH to compile the application; You'll need to setup a task that will compile the application code; You'll need to setup a launch task that will debug the application.