C++Architecture

C++ Enterprise Deployment: CI/CD, Testing, Sanitizers, Docker & Module 30 Final Wrap-up

TT
TopicTrick Team
C++ Enterprise Deployment: CI/CD, Testing, Sanitizers, Docker & Module 30 Final Wrap-up

C++ Enterprise Deployment: CI/CD, Testing, Sanitizers, Docker & Module 30 Final Wrap-up


Table of Contents


The Professional C++ Pipeline


GitHub Actions: Multi-Platform CI

yaml
# .github/workflows/ci.yml
name: C++ CI

on: [push, pull_request]

jobs:
  build-and-test:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-24.04, macos-14, windows-2022]
        compiler: [gcc-14, clang-18]
        build_type: [Debug, Release]
        exclude:
          - os: windows-2022
            compiler: gcc-14  # MSVC on Windows, not MinGW
    
    runs-on: ${{ matrix.os }}
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Install dependencies (Ubuntu)
      if: startsWith(matrix.os, 'ubuntu')
      run: |
        sudo apt-get update
        sudo apt-get install -y ${{ matrix.compiler }} cmake ninja-build
        sudo apt-get install -y libgtest-dev libgmock-dev
    
    - name: Configure (vcpkg)
      run: |
        cmake -S . -B build \
          --preset ${{ matrix.build_type }} \
          -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
          -DCMAKE_C_COMPILER=${{ matrix.compiler == 'clang-18' && 'clang' || 'gcc' }} \
          -DCMAKE_CXX_COMPILER=${{ matrix.compiler == 'clang-18' && 'clang++' || 'g++' }}
    
    - name: Build
      run: cmake --build build --parallel $(nproc)
    
    - name: Test
      run: ctest --test-dir build --output-on-failure --parallel $(nproc)
    
    - name: Upload test results
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: test-results-${{ matrix.os }}-${{ matrix.compiler }}
        path: build/Testing/

Testing Strategy: GTest + Catch2

cpp
// tests/test_processor.cpp — Google Test
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "processor.hpp"

class TextProcessorTest : public ::testing::Test {
protected:
    void SetUp() override {
        sample = "Hello world\nThis is a test\nThree lines here";
    }
    std::string sample;
};

TEST_F(TextProcessorTest, CountsLinesCorrectly) {
    auto stats = analyze_text(sample);
    EXPECT_EQ(stats.lines, 3);
}

TEST_F(TextProcessorTest, CountsWordsCorrectly) {
    auto stats = analyze_text(sample);
    EXPECT_EQ(stats.words, 9);
}

TEST_F(TextProcessorTest, EmptyStringReturnsZeroStats) {
    auto stats = analyze_text("");
    EXPECT_EQ(stats.lines, 0);
    EXPECT_EQ(stats.words, 0);
    EXPECT_EQ(stats.characters, 0);
}

// Parameterized test — test multiple inputs without code duplication:
class WordCountTest : public ::testing::TestWithParam<std::pair<std::string, size_t>> {};

INSTANTIATE_TEST_SUITE_P(WordCounts, WordCountTest, ::testing::Values(
    std::make_pair("one",         1),
    std::make_pair("one two",     2),
    std::make_pair("  spaces  ",  1), // Leading/trailing stripped
    std::make_pair("",            0)
));

TEST_P(WordCountTest, CountsWordsCorrectly) {
    auto [text, expected] = GetParam();
    EXPECT_EQ(analyze_text(text).words, expected);
}

// Mock example — test interactions:
class MockFileReader : public IFileReader {
public:
    MOCK_METHOD(std::string, read, (const std::string& path), (override));
    MOCK_METHOD(bool, exists, (const std::string& path), (const, override));
};

TEST(ProcessorTest, UsesFileReaderCorrectly) {
    MockFileReader mock;
    EXPECT_CALL(mock, exists("test.txt")).WillOnce(::testing::Return(true));
    EXPECT_CALL(mock, read("test.txt")).WillOnce(::testing::Return("hello world"));
    
    auto stats = analyze_file("test.txt", mock);
    EXPECT_EQ(stats.words, 2);
}

Memory Safety: AddressSanitizer & ThreadSanitizer

cmake
# CMakeLists.txt — Sanitizer build types
option(ENABLE_ASAN  "Enable AddressSanitizer" OFF)
option(ENABLE_TSAN  "Enable ThreadSanitizer"  OFF)
option(ENABLE_UBSAN "Enable UBSan"            OFF)
option(ENABLE_MSAN  "Enable MemorySanitizer"  OFF)

if(ENABLE_ASAN)
    add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
    add_link_options(-fsanitize=address)
endif()

if(ENABLE_TSAN)
    add_compile_options(-fsanitize=thread)
    add_link_options(-fsanitize=thread)
endif()

if(ENABLE_UBSAN)
    add_compile_options(-fsanitize=undefined -fno-sanitize-recover=all)
    add_link_options(-fsanitize=undefined)
endif()
yaml
# CI: dedicated sanitizer job
sanitizers:
  runs-on: ubuntu-24.04
  steps:
  - name: ASan build
    run: |
      cmake -DENABLE_ASAN=ON -DCMAKE_BUILD_TYPE=Debug -S . -B build-asan
      cmake --build build-asan --parallel
      ctest --test-dir build-asan --output-on-failure
  
  - name: TSan build
    run: |
      cmake -DENABLE_TSAN=ON -DCMAKE_BUILD_TYPE=Debug -S . -B build-tsan
      cmake --build build-tsan --parallel
      ctest --test-dir build-tsan --output-on-failure

Static Analysis: clang-tidy and cppcheck

bash
# .clang-tidy — project-wide clang-tidy configuration
Checks: >
  -*,
  bugprone-*,
  cert-*,
  clang-analyzer-*,
  concurrency-*,
  cppcoreguidelines-*,
  modernize-*,
  performance-*,
  readability-*,
  -modernize-use-trailing-return-type,
  -readability-magic-numbers

WarningsAsErrors: '*'
HeaderFilterRegex: '.*include/.*'

CheckOptions:
  - key:    modernize-use-default-member-init.UseAssignment
    value:  true
  - key:    readability-identifier-length.MinimumVariableNameLength
    value:  2
cmake
# CMake integration — run clang-tidy during build:
set(CMAKE_CXX_CLANG_TIDY
    clang-tidy;
    --config-file=${CMAKE_SOURCE_DIR}/.clang-tidy;
    --header-filter=${CMAKE_SOURCE_DIR}/include/.*
)

Dependency Management: vcpkg and Conan

json
// vcpkg.json — manifest mode (CMake integration):
{
  "name": "my-cpp-project",
  "version": "1.0.0",
  "dependencies": [
    "asio",
    { "name": "gtest", "version>=": "1.14.0" },
    "fmt",
    "spdlog",
    { "name": "openssl", "platform": "!windows" }
  ]
}
cmake
# CMakeLists.txt with vcpkg toolchain:
# Pass at configure: -DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
find_package(asio   REQUIRED)
find_package(GTest  REQUIRED)
find_package(fmt    REQUIRED)
find_package(spdlog REQUIRED)

target_link_libraries(MyProject PRIVATE
    asio::asio
    GTest::gtest_main
    fmt::fmt
    spdlog::spdlog
)

Docker: Multi-Stage Build for C++ Apps

dockerfile
# Multi-stage: builder stage has full dev tools, deploy stage is minimal
FROM ubuntu:24.04 AS builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
    cmake ninja-build g++-14 git curl \
    libgtest-dev && rm -rf /var/lib/apt/lists/*

# Copy vcpkg and restore dependencies:
COPY vcpkg.json CMakeLists.txt ./
RUN cmake --preset release-linux . && cmake --build build/release --parallel

# Copy source and build:
COPY . .
RUN cmake --build build/release --target install

# ── Deploy stage — minimal runtime image:
FROM ubuntu:24.04 AS deploy
RUN apt-get update && apt-get install -y libstdc++6 ca-certificates \
    && rm -rf /var/lib/apt/lists/*

COPY --from=builder /usr/local/bin/myapp /usr/local/bin/myapp

# Non-root user for security:
RUN useradd -r -s /bin/false appuser
USER appuser

HEALTHCHECK --interval=30s CMD curl -f http://localhost:8080/health || exit 1
EXPOSE 8080
ENTRYPOINT ["/usr/local/bin/myapp"]

Your C++ Mastery Roadmap

You have completed 30 modules covering the complete arc from beginner to expert. Here is where to go next:

Domain Specialization

DomainKey ProjectsResources
Game EnginesContribute to Godot/SFML, write an ECSGame Programming Patterns, Real-Time Rendering
High-Frequency TradingLock-free queues, DPDK networkingC++ in HFT (Jane Street, Jump Trading blogs)
RoboticsROS2 C++ nodes, embedded controllersROS2 Documentation, Embedded C++ books
DatabasesBuild a log-structured storage engineCMU 15-445, rediscovering design via LevelDB
Compilers/InterpretersWrite a tree-walk interpreter in C++Crafting Interpreters (Nystrom), LLVM Tutorial

Community and Open Source

  • Contribute to: LLVM, Boost, abseil-cpp, folly, seastar, cppcoro
  • Follow: iso-cpp.org, reddit.com/r/cpp, CppCon YouTube channel
  • Read: "Effective Modern C++" (Meyers), "C++ Templates" (Vandevoorde/Dawes)

Final Takeaway

C++ in 2026 is more powerful, safer, and more expressive than ever. You now understand:

  • Zero-cost abstractions: Templates, constexpr, CRTP — performance without sacrificing expressiveness
  • Memory safety: Smart pointers, RAII, span, optional — safety without a garbage collector
  • Modern concurrency: jthread, atomics, coroutines — scalable I/O without threading complexity
  • Compile-time programming: Concepts, fold expressions, static reflection — moving work to build time

Thank you for completing the C++ Mastery course. The C++ you write now is not just correct — it's production-grade, performance-oriented, and future-proof.

"C++ is not just a language; it's a discipline."

Frequently Asked Questions

Q: What does a typical CI/CD pipeline look like for a C++ enterprise project? A typical pipeline: (1) checkout code, (2) configure with CMake (cmake -B build -DCMAKE_BUILD_TYPE=Release), (3) compile (cmake --build build --parallel), (4) run unit tests (ctest --test-dir build), (5) run static analysis (clang-tidy, cppcheck), (6) package the binary (CPack or a Docker image), and (7) deploy to staging then production. GitHub Actions, GitLab CI, and Jenkins are common orchestrators. Caching the build directory between runs dramatically speeds up incremental builds.

Q: How do you manage C++ dependencies in a CI/CD environment? Use a package manager: vcpkg (integrates with CMake via toolchain file, supports binary caching) or Conan (more flexible for enterprise use with private package servers). In CI, restore the package cache before building and save it after. Alternatively, vendor dependencies as git submodules for fully reproducible builds at the cost of repository size. Avoid system-installed libraries in CI — they vary between runners and break reproducibility.

Q: What sanitisers should you run in a C++ CI pipeline and how do you enable them? Run AddressSanitizer (ASan) to detect memory errors, UndefinedBehaviorSanitizer (UBSan) for undefined behaviour, and ThreadSanitizer (TSan) for data races. Enable them via CMake: set(CMAKE_CXX_FLAGS "-fsanitize=address,undefined") for a sanitiser build configuration. Run your full test suite under each sanitiser in separate CI jobs — sanitisers have significant runtime overhead so they run alongside, not instead of, the main Release build.


*Part of the C++ Mastery Course — 30 modules from modern C++ basics to expert systems eng