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!
There is absolutely nothing wrong with having your IDE in a container. In fact, it is much better than keeping it outside.
“The fourth “C”, CLion, is an IDE and therefore does not belong in the container”
Not quite true. Jetbrains has released docker images for their IDEs that you can run and connect to using their Projector. This way you can even run your container with clion on one (more powerful) computer and connect from a different (or the same) computer. Should work great in docker-compose.
Thanks, good to know, I’ll have a look at that. Though I still don’t think the IDE belongs into a container like the one I’m building because I believe the choice of the IDE or editor should be up to each individual developer.
Sure. This is why docker have layers. We have a setup with a common Docker image and individual IDE setups as derived images.
Thanks. I am still learning how far containerization can go. I have a few questions about your setup:
How do you deal with different projects that have different toolchains, i.e. different containers? Do you have an IDE layer for each of them?
You probably mount the personal configuration of the IDEs into the containers, so that you don’t have to reconfigure everything from scratch each time the container is rebuilt, right?
I also have not tried to use GUI applications out of containers yet. How well does that work in Windows and MacOS?
That is really cool. I have been trying to do that. However I ran across “file updates not reflected in source when docker fs is mounted for edit.”
I hope to see it working in your edition. 😋
Never heard of that problem. We have been using that kind of setup at work for several months now and it went well with CLion, Eclipse, and VSCode as IDEs
Apparently, the problem is solved. Too bad it never existed, at list, on Linux. I have a setup scripts for apt and rpm based Linux, that is usually installed within 15 minutes with zero effort. Includes CLion, too, and about twenty different libraries we are using.
That is nice to know. How do you deal with multiple projects that need conflicting setups of compilers, tools, and libraries? I am sure there are use cases for both solutions.