Installing everything we need to develop C++ applications can be a lengthy, even painful process. Docker makes it possible to build a development environment once and deploy it everywhere.
The pain of a manually maintained environment
Most of us, probably all of us have been there: Install your IDE. Install your compiler. Install a build tool, static analysis tools, sanitizers, package management, coverage tools, profiler. The list is long, and just getting everything to work smoothly can take hours, even days.
And then you switch to another computer and have to do it all over again. Or your colleague calls and tells you whatever you just did would not compile in their setup. And if you are involved in the DevOps side of thing (you should!), you get to do the whole installation on a CI/CD server as well.
Virtual machines can alleviate these problems somewhat. However, people like to do customizations to their workflows, install tools on their own, etc. VM environments diverge over time, and if we decide to switch versions of one of our tools, it gets more complicated.
Docker to the rescue
With Docker, we can define an exact isolated environment for our builds. We still can use VMs if we want to. For example, I use a Linux VM on my Windows machine at work and a Docker container inside that for the actual build environment.
Docker images also are much smaller than complete VM images. They can be stored in a container registry of your choice, and they can be rebuilt in a matter of minutes if something changes. Also, most CI/CD solutions support the use of Docker images as build nodes natively.
With the learnings from past projects that use Docker containers as their build environment, I have started an open-source repository to build a generic container for C++ development. You can find it on GitHub.
The container built in that project does not claim to be complete. Instead, it is intended as a good starting point with a range of commonly used tools. At the beginning of a project, it may be sufficient to clone the repository or use the containers that are built from it in the GitHub container registry.
What’s in it
The content of the container is based on the “4C development environment”, a Vagrant VM I built 5 years ago. Among other things, it contains three of the four “C”s: The Clang compiler, the CMake build tool, and the Conan package manager.
The fourth “C”, CLion, is an IDE and therefore does not belong in the container. However, beginning with the upcoming 2021.2 release of CLion, it supports development in Docker containers pretty well.
Some of the tools in the container are:
– Clang and GCC compilers (
c++ default to Clang)
– CMake, make, and Ninja build tools
– Clang-tidy, Cppcheck, and include-what-you-use for static analysis
– Sanitizers that come with Clang, but also Valgrind, Gcov, Perf
– Conan for package management
– Python 3 for scripting, and behave for BDD
The Dockerfile of Docker4c consists of two stages: the CI stage contains everything that is needed to build a project and run the tests. The DEV stage is built from the CI stage and adds a dedicated dev user plus a small handful of tools that are not needed in CI builds.
The repository also contains a small compose file and a script for convenience of use. It has shortcuts for building the container and entering it or running commands inside. You can see it in action here in the screenshot:
Work in progress
I have tested the container using a modified version of Jason Turner’s cpp_starter_project, to have the range of tools that the project uses. I’ve tested it with CLion, but it should work well e.g. with VSCode remote containers and other IDEs that support remote development.
I hope you’ll find that the container and the cpp_starter_project play well together. In fact, they’re created with similar intentions: While Jason’s project provides a starting point for a new C++ code-base, my project is meant to provide a starting point for a development environment for that code-base.
At the time I write this, the project is far from done, but I’d say it is ready to be played with. I have a couple of ideas for future extensions. If you come up with ideas and improvements, let me hear them – open an issue on the GitHub project or drop me a comment here!