Skip to content

Add dedicated C++ devcontainer - #1606

Open
bferanmi806-sketch wants to merge 1 commit into
PowerGridModel:mainfrom
bferanmi806-sketch:feature/1272-cpp-devcontainer
Open

bferanmi806-sketch wants to merge 1 commit into
PowerGridModel:mainfrom
bferanmi806-sketch:feature/1272-cpp-devcontainer

Conversation

@bferanmi806-sketch

@bferanmi806-sketch bferanmi806-sketch commented Sep 25, 2026 •

Copy link
Copy Markdown

Add dedicated C++ devcontainer

References #1272 (does not close it — no merge/close performed from this PR).

What

Adds a separately selectable C++ devcontainer while keeping the existing
Python devcontainer untouched as the default:

  • .devcontainer/cpp/Dockerfile — Ubuntu 26.04 (resolute)-based image with the
    pinned Linux C++ toolchain (gcc-14/g++-14, clang-18, CMake, Ninja,
    gdb, clang-format/clang-tidy) and the C++ dependencies (boost,
    eigen3, nlohmann-json, msgpack-cxx, doctest). Unversioned
    gcc/g++/clang/clang++ symlinks mirror CI so the existing CMake presets
    resolve. No extra privileges or broad security exceptions (runs as vscode,
    no --privileged/cap adds). Only the compiler versions are pinned to CI —
    the Linux CI jobs still run on Ubuntu 24.04, so the container OS intentionally
    differs from CI (stated in the Dockerfile and the docs).
  • .devcontainer/cpp/devcontainer.json — selectable as
    power-grid-model (C++) in VS Code; same /power-grid-model workspace
    mount as the Python container; C++ extensions only (cpptools,
    cmake-tools, catch2-test-adapter, better-cpp-syntax). No
    cmake.configurePreset entry: that setting does not exist in CMake Tools, so
    first-time users run CMake: Select Configure Preset and choose gcc-debug
    (clang-debug remains an alternative).
  • docs/advanced_documentation/devcontainer-setup.md — new
    "C++ Development Container" section: select, run CMake: Select Configure Preset and choose gcc-debug, configure/build via preset, run tests, IDE
    debug, return to Python. build-guide.md points at it.
  • .gitattributes — Dockerfile text eol=lf so the Dockerfile keeps LF
    endings on Windows checkouts.

Out of scope (per thread agreement): combined Python/C++ and docs-building
environments.

Validation (all run for real, nothing invented)

Environment limitation, stated honestly: no Docker daemon on the Windows
host (docker info fails; Docker Desktop not installed, no devcontainer
CLI). Validation used the Docker Engine 29.7.2 inside WSL2 Ubuntu 26.04 plus a
native toolchain install there. VS Code interactive debugging was not
available, so IDE debugging is verified via the identical gdb path the
cppdbg launch config uses (same binary layout, same gdb backend).

Ubuntu 26.04 (this update, commit d5566aba4):

  1. docker manifest inspect mcr.microsoft.com/devcontainers/base:resolute —
    exists (amd64). The :ubuntu-26.04 tag does not exist, so the
    Dockerfile uses :resolute.
  2. docker build -t pgm-cpp-dev-26 .devcontainer/cpp — success (resolute
    base). Toolchain/dependency versions inside the image:
    • g++ 14.3.0, clang++ 18.1.8, cmake 4.2.3, ninja 1.13.2,
      gdb 17.1
    • boost 1.90.0, eigen3 3.4.0, nlohmann-json 3.12,
      msgpack-cxx 7.0.0, doctest 2.4.12
  3. cmake --preset gcc-debug inside the 26.04 container — configures
    cleanly, all find_package calls resolve (Boost 1.90, nlohmann_json,
    Threads). CMake 4.2.3 accepts the project's cmake_minimum_required(3.23).
  4. Compilation on Ubuntu 26.04 with g++-14 under the preset's own flags
    (-Werror, ASan+UBSan, C++23): every translation unit attempted compiled
    with zero errors — the core C/C++ libraries, all 9
    power_grid_model_api_tests TUs and the attempted unit-test TUs (~277 MB
    of objects). This retires the header/API-compatibility risk for the newer
    dependency versions (Boost 1.90, msgpack-cxx 7.0, nlohmann-json 3.12,
    doctest 2.4.12).
  5. ASan+UBSan link+run probe inside the 26.04 container — passes.
  6. Not completed locally: the final giant test-binary links and the ctest
    runs on 26.04. The local box (WSL2, ~6 GB RAM, slow cores) cannot finish an
    ASan-instrumented link of these binaries in one uninterrupted run, and
    backgrounded builds do not survive between sessions here. No 26.04
    incompatibility was found at any stage — every failure observed was the
    environment (OOM pressure, WSL service restarts under load), never a
    compiler, header, or package error. If reviewers prefer full local
    build+test proof before merging, I can revert the base to 24.04 on request.

Ubuntu 24.04 (original validation, commit 50a55450c, superseded by the above
for the container itself):

  1. docker build -t pgm-cpp-dev .devcontainer/cpp — success (noble base).
    Toolchain/dependency versions inside the image:
    • g++ 14.2.0, clang++ 18.1.3, cmake 3.28.3, ninja 1.11.1,
      gdb 15.1
    • boost 1.83.0, eigen3 3.4.0, nlohmann-json 3.11.3,
      msgpack-cxx 6.1.0, doctest 2.4.11
  2. cmake --preset gcc-debug inside the container as vscode with
    /power-grid-model mounted — configures cleanly, all find_package
    calls resolve. (This caught a real bug during development:
    libmsgpack-dev does not ship the msgpack-cxx CMake config;
    fixed to libmsgpack-cxx-dev before committing.)
  3. Full gcc-debug build + tests on equivalent host toolchain
    (gcc 14.3, same package set), ctest --preset gcc-debug:
    56/66 pass, 0 real failures — the 10 non-passing entries are
    NOT_BUILT placeholders for suites not yet compiled at that point.
    • power_grid_model_api_tests: 49/49 cases, 56608/56608 assertions pass
    • power_grid_model_validation_tests
      --test-case="Validation test single - power flow":
      1/1 case, 1282/1282 assertions pass
  4. gdb breakpoint debugging on both binaries (.vscode/launch.json
    uses the cppdbg/gdb backend against the same
    ${command:cmake.buildDirectory}/bin/... layout):
    • break test_api_model.cpp:195 → hit, bt shows
      doctest::Context::run → main
    • break test_validation.cpp:672 → hit, same clean backtrace
    • Binaries confirmed with debug_info, not stripped
  5. Python workflow untouched: root .devcontainer/devcontainer.json
    byte-identical (git diff shows only the new cpp/ dir, docs and the
    one .gitattributes line); both devcontainer JSON files parse;
    referenced presets (gcc-debug, clang-debug) exist.

Not yet completed locally: power_grid_model_unit_tests binary (building
at PR time on a slow machine) and interactive VS Code debugging — covered
by CI. reuse compliance: new JSON config carries a .license sidecar
like the existing one; Dockerfile carries an inline SPDX header.

Files

.devcontainer/cpp/Dockerfile, .devcontainer/cpp/devcontainer.json,
.devcontainer/cpp/devcontainer.json.license, .gitattributes,
docs/advanced_documentation/build-guide.md,
docs/advanced_documentation/devcontainer-setup.md — commits 50a55450c,
d5566aba4.

Comment thread .devcontainer/cpp/Dockerfile Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The unsupported CMake Tools preset setting makes the documented default preset behavior incorrect.

Review effort: Balanced
Findings: 1 Medium severity · 1 Low severity

Open (2)
What changed in this PR

Adds a dedicated C++ devcontainer while preserving the existing Python environment.

Changes:

  • Adds Ubuntu-based C++ tooling and VS Code integration.
  • Documents building, testing, and debugging.
  • Enforces LF endings for Dockerfiles.
File Description
.devcontainer/​cpp/​Dockerfile Installs C++ compilers, tools, and dependencies.
.devcontainer/​cpp/​devcontainer.json Configures the C++ development environment.
.devcontainer/​cpp/​devcontainer.json.license Adds SPDX licensing metadata.
.gitattributes Enforces Dockerfile LF endings.
docs/​advanced_documentation/​build-guide.md Links to the C++ container guide.
docs/​advanced_documentation/​devcontainer-setup.md Documents C++ container workflows.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .devcontainer/cpp/devcontainer.json Outdated
Comment thread docs/advanced_documentation/devcontainer-setup.md Outdated

@mgovers mgovers left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @bferanmi806-sketch,

Thank you very much for the contribution and my apologies for the delay on the review. We have been very occupied recently.

I have a couple open questions - see my comments below.

In addition to that, please also make sure all your commits are marked Verified (see also https://power-grid-model.readthedocs.io/en/stable/contribution/CONTRIBUTING.html#commit-signature-verification ).

Comment thread .devcontainer/cpp/Dockerfile Outdated
Comment on lines +17 to +31
gcc-14 g++-14 \
clang-18 lld-18 clang-format-18 clang-tidy-18 \
cmake ninja-build gdb \
libboost-dev libeigen3-dev nlohmann-json3-dev libmsgpack-cxx-dev doctest-dev \
gcovr lcov pkg-config git curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*

# The CMake presets resolve `gcc`/`g++`/`clang`/`clang++` via PATH
# (same approach as CI, which symlinks the versioned binaries).
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 \
&& update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100 \
&& update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100 \
&& update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100 \
&& update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-18 100 \
&& update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-18 100

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please bump all compilers etc. in accordance with #1631

It is also a good idea to merge with main before doing so

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I merged the current main and aligned the image with #1631: GCC/G++ 16, Clang/Clang++ 22, clang-tidy 18, and libclang-rt-22-dev, on the Ubuntu 26.04 (resolute) base. I checked each package/version against the 26.04 archive; the compiler versions are also asserted by the postCreateCommand output.

&& update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-18 100 \
&& update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-18 100

ENV CC=gcc CXX=g++

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this work combined with the preset? e.g. if i select clang-debug, will it automatically use Clang?

I am getting this CMake Error when I run clang-debug on my machine

[main] Building folder: /power-grid-model/cpp_build/clang-debug 
[main] Configuring project: power-grid-model 
[proc] Executing command: /usr/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DPGM_ENABLE_DEV_BUILD=ON -DPGM_MSVC_REPRODUCIBLE_BUILD=OFF -DCMAKE_INSTALL_PREFIX=/power-grid-model/install/clang-debug -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -S /power-grid-model -B /power-grid-model/cpp_build/clang-debug -G Ninja
[cmake] CMake Error: The current CMakeCache.txt directory /power-grid-model/cpp_build/clang-debug/CMakeCache.txt is different than the directory <local_path_to_repo>/power-grid-model/cpp_build/clang-debug where CMakeCache.txt was created. This may result in binaries being created in the wrong place. If you are not sure, reedit the CMakeCache.txt
[cmake] CMake Error: The source "/power-grid-model/CMakeLists.txt" does not match the source "<local_path_to_repo>/power-grid-model/CMakeLists.txt" used to generate cache.  Re-run cmake with a different source directory.
[proc] The command: /usr/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DPGM_ENABLE_DEV_BUILD=ON -DPGM_MSVC_REPRODUCIBLE_BUILD=OFF -DCMAKE_INSTALL_PREFIX=/power-grid-model/install/clang-debug -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -S /power-grid-model -B /power-grid-model/cpp_build/clang-debug -G Ninja exited with code: 1

gcc-debug, on the other hand, works just fine.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes: both presets set the compiler explicitly, so selecting clang-debug uses clang/clang++ (the CC/CXX environment variables only affect ad-hoc CMake invocations and do not override a preset).

The error is a stale cpp_build cache, not the preset. It appears when the same cpp_build/<preset> was configured on the host and then reused at the container path. I changed cpp_build to a per-checkout named volume (power-grid-model-cpp-build-${devcontainerId}), so the container never reuses a host-generated CMakeCache.txt, and parallel worktrees do not share one either.

If you tested the earlier revision, delete the stale cpp_build directory (or its old volume) once and reconfigure; cmake --list-presets is part of postCreateCommand and will confirm both presets are visible.

Comment thread .devcontainer/cpp/devcontainer.json Outdated
Comment on lines +26 to +30
"ms-vscode.cpptools",
"ms-vscode.cmake-tools",
"matepek.vscode-catch2-test-adapter",
"jeff-hykin.better-cpp-syntax",
"tamasfe.even-better-toml"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no extension for clang-format installed in the devcontainer. please make sure to add + configure it

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added xaver.clang-format to the container extensions and configured it to use /power-grid-model/.venv/bin/clang-format with -style=file. That is the clang-format 23.1.3 version pinned in uv.lock and used by CI, so editor formatting matches pre-commit/CI rather than a distro clang-format. C and C++ files use it as the default formatter on save.

Comment on lines +175 to +181
### Debug a C++ test in the IDE

* Build with a Debug preset as above so binaries carry symbols.
* Set a breakpoint, then start the preconfigured `Debug validation test [Unix]` launch configuration
(`.vscode/launch.json`, `gdb`-based), or right-click an individual test in the Test Explorer and debug it.
* The launch configuration resolves the test binary via `${command:cmake.buildDirectory}`
(e.g. `cpp_build/gcc-debug/bin/power_grid_model_validation_tests`).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how to format, run REUSE, etc. (the stuff usually also provided using pre-commit, which are not available in this container at the moment)?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a "Format, check licences and run pre-commit" section to devcontainer-setup.md. postCreateCommand now creates the uv environment and installs the Git hook, and the docs cover:

uv run --frozen pre-commit run --all-files
uv run --frozen pre-commit run clang-format --files path/to/file.cpp
uv run --frozen pre-commit run reuse --all-files
uv run --frozen clang-format -style=file -i path/to/file.cpp

It also lists the hook IDs and how to recreate the environment after a rebuild.

@bferanmi806-sketch
bferanmi806-sketch force-pushed the feature/1272-cpp-devcontainer branch from d5566ab to fbfad01 Compare October 21, 2026 22:27
Provide a separately selectable C++ development container alongside the
default Python container (issue PowerGridModel#1272).

The container is based on Ubuntu 26.04 and mirrors the Linux CI toolchain
after PowerGridModel#1631: gcc-16/g++-16, clang-22, clang-tidy-18, CMake, Ninja, gdb and
the C++ dependencies from the build guide (boost, eigen3, nlohmann-json,
msgpack-cxx, doctest). It reuses the gcc-debug/clang-debug CMake presets and
the existing VS Code debug configurations.

cpp_build is kept in a per-checkout Docker volume. CMake caches contain
absolute paths, so sharing that directory with the host made presets fail
with a CMakeCache.txt directory mismatch (reported for clang-debug).

The clang-format extension uses the version pinned in uv.lock, which is the
same version CI runs through pre-commit, and the documentation now covers
formatting, REUSE, pre-commit and compiler verification.

Signed-off-by: Balogun Feranmi <bferanmi806@gmail.com>
@bferanmi806-sketch
bferanmi806-sketch force-pushed the feature/1272-cpp-devcontainer branch from fbfad01 to 2ea60f4 Compare October 21, 2026 22:29

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants