Skip to content

ChristopherPisz/DevContainerCpp

Repository files navigation

DevContainerCppEnv

A devcontainer environment with example app, lib, and test projects using conan and cmake, that can serve as a starting point for a C++ project. I've featured this repo on my youtube channel http://youtube.com/@ChristopherPisz but I have updated it at least a few times since then, so be aware it might not match exactly.

Building

This repo makes use of the DevContainer concept, which was first popularized by VSCode and it's remote containers extension. This allows you to use VSCode and issue a "Open Folder in Dev Container" from the command pallete, and have VSCode automatically create the appropriate docker image, container, and volumes for you.

Prerequisites

You'll need Docker installed and running.

Make sure you have the "Dev Containers" extension installed in VSCode on the host machine.

Also be aware there are local extensions (installed on host) and dev container extensions (those installed in the container). VSCode should install for you, via the devcontainer.json, the C++, Cmake Tools, etc, extensions in the container.

Locations

The docker-compose file will create a docker managed volume that will be the build directory and that will be mounted to /build VSCode's devcontainer setup will map the top level folder to /workspace in the docker container it creates Conan will put its config and cache in /home/developer/.conan2 inside the docker container

Naming

I wanted to setup my devcontainer infrastrucure such that I could copy paste and rename for new projects. As such, I've deleted the properties related to container name in devcontainer.json and docker-compose.yml. We rely on a combination of automatic naming done by docker compose and vscode's devcontainer.

If we rename the directories to be specific to the project where I used "myproject" in the following hierarchy: i.e .devcontainer |-- myproject-jammy-x86_64 |-- | -- devcontainer.json .. |-- myproject-noble-x86_64 |-- | -- devcontainer.json

Then we will get a container such as

PS D:\Programming\git-workspace\ReplacingInheritance> docker ps
CONTAINER ID   IMAGE                                 COMMAND                  CREATED          STATUS          PORTS     NAMES
945cdba194e2   devenvcpp-jammy-x86_64-image:latest   "/bin/sh -c 'echo Co…"   10 minutes ago   Up 10 minutes             myproject-jammy-x86_64-app-1

"app-1" comes from the service name in docker-compose.yml. The -1 is incrementally generated by docker compose so as to prevent name collision, which would come into play if we didn't rename our directories under .devcontainer from "myproject-xxxx-xxxx" to something else.

Note that the name that shows for the container in the GUI may be a truncated or "prettified" version of the name above, but the real name is shown via the command line command.

We should end up with a unique container for each project with its own unique volume for the build directory and the conan cache inside the container. I played with making a shared volume for conan cache for all projects and decided it was a bad idea.

Install Conan Dependencies

Once VSCode gets the container image made, unfortunatly it attaches to the container and tries to cmake configure before any attempt to run the necessary commands completes. So, we will have to let it fail the automatic configure the first time we enter the container.

Create new terminal window with bin/bash and manually tell conan to install dependencies, via ./dependencies/install-dependencies.sh. Then tell VSCode to reconfigure cmake.

I already tried:

  • postCreateCommand in devcontainer.json
  • ENTRYPOINT calling a copied script from Dockerfile These fail to timing issues.

You should only have to do this once, or until your build_dir mount is blown away.

Installing the dependencies can take a long time, if we are using Boost for example, because it is huge.

Presets

Note that conan 2.x writes the CMakeUserPresets.json file. This is where the presets conan-debug, conan-release, and conan-relwithdebuginfo come from

If you want to customize..for example specify a gdb debugger..you have to inherit from those presets in a CMakePresets.json file.

It seems backwards as user presets should be for customization and presets should be the base, but conan flips it.

Summary

Steps:

  • In VSCode on host machine-> Choose "Dev Containers: Open folder in container" from the command palette
  • Choose the top level folder on your host machine
  • Let it finish and ignore any message about Ninja or cmake-toolchain file.
  • Open a terminal in VSCode and optionally /bin/bash
  • Run ./dependencies/install-dependencies.sh to have conan go grab any missing dependencies
  • Choose "CMake: reconfigure" from the command palette now that we have our dependencies
  • Click Build
  • VSCode should prompt to select a preset: conan-debug, conan-release, or conan-relwithdebinfo
  • Build should actually build

clang-format and clang-tidy

I've set up the container to install these via the docker file. I've also told vscode to use the clangd language server rather than C/C++ from microsoft. This seem to work better in the linux container and integrates well with clang-format and clang-tidy.

These tools depend on compile_commands.json to tell them what code is compiled, and that is generated by cmake in the build directory corresponding to the build preset (debug, release, etc). This uses is pointed to by the devcontainer.json with --compile-commands-dir=${command:cmake.buildDirectory}. If build paths change, keep this in mind.

If clang-tidy complains about something you don't think is important, you can exclude certain rules in the .clang-tidy file.

Likewise formatting on save rules can be customized using the .clang-format file.

If you make changes to the files for these tools, you can select restart language server from the command pallete to ensure they take effect. This command is also handy if it seems like "intellisense" is failing.

Multi-Container Branch

If you'd like to see how to setup and use multiple containers at once, checkout branch multicontainer-with-postgres, which creates an additional container that runs postgres, sets up network communication between the app container and the postgres container, gets the C++ libs to interact with postgres, and installs the postgres client into the container.

About

Devcontainer setting up a minimal environment using conan and cmake

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors