- Introduction
- What is Docker?
- How Docker Works for C++
- Where Docker Gets C++ Libraries
- Why Docker Alone is Not Enough
- What is Conan and Why Use It?
- Conan Internal Process
- Docker + Conan Together
- What is Bazel and Why Use It?
- Using Bazel Instead of CMake
- Alternatives Without Conan
- Best Practices
- What is Jenkins?
- Workflow Diagram – Docker + Conan + Bazel + Jenkins
- Conclusion
- Project
If you want, I can also add links for the remaining sub-subsections like “Summary Table”, “Analogy”, “Step 1 / Step 2 / Step 3” so your TOC becomes fully navigable in GitHub.
Do you want me to do that next?
This README explains the purpose and functionality of Docker, Conan, and Bazel, and how they relate to building modern C++ projects.
It answers questions like:
- Why Docker alone is insufficient for professional builds
- How Conan automates dependency management and ensures reproducibility
- How Bazel provides a fast, deterministic, and cache-friendly build system
- How these tools integrate in CI/CD pipelines like Jenkins
By the end, you’ll understand how to create fully reproducible C++ builds in a Dockerized environment using CMake or Bazel.
Docker is a platform for creating, running, and managing containers—lightweight, isolated Linux environments.
- Isolation: Containers run independently of the host system
- Portability: Runs the same on any machine
- Reproducibility: Guarantees consistent OS, compiler, and environment across developers and CI/CD
Docker = Your kitchen (oven, utensils, temperature) Ensures every chef works in the same kitchen
1. Choose a base image (e.g., ubuntu:22.04)
2. Install build tools inside the container:
FROM ubuntu:22.04
RUN apt update && apt install -y \
g++ cmake make ninja-build pkg-config python3 python3-pip3. Copy your project into the container:
COPY . /app
WORKDIR /appcmake -B build -S .
cmake --build buildDocker provides:
- Compiler (
g++,gcc) - Standard libraries (
libstdc++) - System libraries (
glibc,libm,libpthread)
Simple programs compile successfully without third-party package managers.
Docker does NOT copy your whole project into a global folder on your system. Where Docker “saves” files depends on how you build or run the container.
Below is the full explanation:
When you run:
docker build -t myimage .Docker creates:
- It sends the current directory (
.) to the Docker daemon. - The build context is stored temporarily, but Docker does NOT save your project files permanently.
- Only the filesystem layers produced by RUN / COPY / ADD are saved into the image layers.
### Where are image layers stored?
On Linux (including Ubuntu / WSL2):
/var/lib/docker/
Inside it:
/var/lib/docker/overlay2/
Your project files only appear inside the image layers if you COPY or ADD them in the Dockerfile.
If you run a container normally:
docker run -it myimageThe container filesystem is stored in:
/var/lib/docker/overlay2/<container-layer-id>/
This contains the merged root filesystem for that container.
This is Docker internal storage, not your project folder.
If you do:
docker run -v $(pwd):/app myimageYour project is NOT copied. Docker just mounts your host folder into the container.
That folder remains wherever it originally is.
If you run:
docker volume create mydata
docker run -v mydata:/app myimageDocker stores volume data inside:
/var/lib/docker/volumes/mydata/_data/
| Type of data | Where it is stored |
|---|---|
| Image layers | /var/lib/docker/overlay2/ |
| Container data | /var/lib/docker/overlay2/<container-id>/ |
| Named volumes | /var/lib/docker/volumes/<name>/_data/ |
| Bind mounts | On your host filesystem (your project folder) |
Run:
docker inspect <container-id> | grep UpperDirIt returns something like:
"UpperDir": "/var/lib/docker/overlay2/abc123/diff"
Docker base images only include system libraries. Third-party libraries like fmt, spdlog, Boost, or OpenCV must be installed manually:
RUN apt install -y libfmt-dev libspdlog-dev libboost-devLimitations:
- Versions are fixed by OS repositories
- Manual installation is error-prone
- Transitive dependencies aren’t automatically resolved
Docker does NOT provide any C++ libraries by itself.
The libraries used by g++ inside Docker come entirely from the base Linux distribution of the image you choose.
For example:
FROM ubuntu:22.04This means your container is running Ubuntu 22.04, with Ubuntu’s package manager (APT) and repositories.
RUN apt update && apt install -y g++ libstdc++-devDocker uses APT, and APT downloads packages from the repositories inside the container:
/etc/apt/sources.list
For Ubuntu images, these are:
http://archive.ubuntu.com/ubuntu
http://security.ubuntu.com/ubuntu
So all g++ packages and C++ standard libraries come from Ubuntu’s official servers.
APT installs:
/usr/bin/g++
/usr/lib/x86_64-linux-gnu/libstdc++.so
/usr/include/c++/<version>/
These are the same packages you get if you install g++ on your normal Ubuntu machine.
Docker gets its g++, GCC, and C++ standard libraries from the OS repositories of the base image (Ubuntu, Debian, Alpine, etc.) — not from Docker.
FROM debian:bookworm
APT pulls g++ and its libs from:
http://deb.debian.org/debian
FROM alpine:latest
Packages come from Alpine repositories via apk:
apk add g++ libstdc++
Docker does not provide g++ libraries — the C++ compiler and libstdc++ come from the package repositories of the base Linux image (Ubuntu, Debian, Alpine, etc.).
Docker ensures environment consistency, but cannot automatically manage third-party libraries.
Example:
#include <fmt/core.h>Error without installation:
fatal error: fmt/core.h: No such file or directory
Docker alone cannot:
- Fetch library versions automatically
- Handle transitive dependencies
- Ensure binaries match compiler flags or ABI
CConan is a C/C++ package manager (like APT for Linux or pip for Python) but designed specifically for C++ libraries.
It downloads prebuilt or source packages (FMT, Boost, OpenCV, etc.) and integrates them into your CMake or C++ build.
that automates:
- Fetching and building libraries (
fmt,spdlog) - Handling transitive dependencies
- Version and ABI management
- Integration with CMake, Bazel, or other build systems
Conan ensures reproducible builds and eliminates manual library management.
Here is a clean, complete, and simple explanation of how Conan works and where it gets C++ libraries from.
Conan does NOT use OS repositories (APT, yum, apk). Instead, Conan gets libraries from Conan remotes, the biggest one being:
https://center.conan.io/
This is the main global repository for C++ packages, containing:
- fmt
- boost
- spdlog
- openssl
- zlib
- opencv
- gtest
- etc.
Everything downloaded via Conan is hosted outside your OS and completely independent from apt/yum.
If you run:
conan install . --build=missingConan will:
It checks the remotes you have configured:
conan remote listYou will usually see:
conancenter: https://center.conan.io
This is where it downloads packages.
## Step 2 — Download a binary package
If a prebuilt binary (matching your compiler + OS + version) exists, Conan downloads it into your cache:
~/.conan2/p
## Step 3 — If no binary exists → Conan builds from source
If no prebuilt package matches your system, Conan automatically:
- downloads the source code (from GitHub usually)
- builds it using your compiler (g++, clang++)
- stores the compiled package in the Conan cache
- reuses it for future builds
Conan libraries do NOT come from your Linux system (APT). They come from ConanCenter or other Conan remotes.
This means Conan versions are usually more modern than apt packages.
Conan generates a conan_toolchain.cmake.
Then you write:
find_package(fmt REQUIRED)And Conan makes sure the correct include paths and library paths are provided.
If you want fmt with Conan:
conan new fmt/11.0.2 --template=cmake_lib
conan install . --build=missingConan gets the fmt recipe from ConanCenter → downloads/builts the library → puts it in:
~/.conan2/p/<package_hash>/
| Tool | Where it gets C++ libraries |
|---|---|
| APT | From the OS repos (Ubuntu mirrors) |
| Conan | From ConanCenter or other Conan remotes |
| vcpkg | From GitHub (ports) |
| Docker (apt inside) | Again from OS repos inside container |
So Conan is independent of APT, Docker, distro, etc.
[requires]
fmt/10.1.1
spdlog/1.12.0
[generators]
CMakeDeps
CMakeToolchain-
[requires]→ declares dependencies -
[generators]→ integrates libraries with CMake/BazelCMakeDeps→ generates<pkg>-config.cmakefilesCMakeToolchain→ generatesconan_toolchain.cmake
- Reads recipe and profile (compiler, OS, architecture)
- Resolves the dependency graph
- Checks local cache for binaries
- Downloads missing recipes/binaries from remotes
- Builds binaries if not found, respecting compiler flags and ABI
- Generates integration files (
conan_toolchain.cmake,<pkg>-config.cmake) - Builds project with correct dependencies
- Caches binaries for future builds
Conan downloads C++ libraries from online Conan remotes (mainly ConanCenter), not from your OS or Docker image. If no binary matches your system, Conan builds the library from source and caches it locally.
Using Docker and Conan together ensures full reproducibility:
Docker container (Ubuntu 22.04)
├─ g++, cmake, python3, conan installed
└─ conan install → pulls fmt, spdlog, etc.
└─ cmake build → compiles project with correct flags and dependencies
Docker = Kitchen Conan = Ingredients (exact sugar, flour, butter) Together → Perfect, reproducible cake 🍰
Bazel is a fast, reliable, and reproducible build system created by Google.
Unlike Make or CMake, Bazel emphasizes:
- Deterministic outputs – same inputs produce same outputs
- Incremental builds – rebuilds only changed parts
- Scalability – handles large, multi-language projects
- Remote caching & execution – shares artifacts across machines
| Feature | Bazel | CMake |
|---|---|---|
| Incremental builds | ✅ Fast, minimal rebuilds | |
| Deterministic builds | ✅ Fully reproducible outputs | |
| Remote caching | ✅ Built-in support | |
| Dependency tracking | ✅ File-level, precise | |
| Scalability | ✅ Large projects | |
| Multi-language support | ✅ C++, Java, Python, Go | |
| CI/CD integration | ✅ Optimized for caching & distributed builds |
Analogy:
CMake = Recipe book Bazel = Master chef + automated kitchen
When to Prefer Bazel:
- Large-scale projects
- Fast, reproducible CI/CD builds
- Multiple languages or embedded platforms
Bazel can build C++ projects with or without Conan.
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_binary")
cc_library(
name = "log_lib",
srcs = ["ConsoleSinkImpl.cpp", "FileSinkImpl.cpp", "LogManager.cpp", "LogMessage.cpp"],
hdrs = glob(["../inc/*.hpp"]),
includes = ["../inc"],
deps = [],
visibility = ["//visibility:public"],
)
cc_binary(
name = "main",
srcs = ["main.cpp"],
deps = [":log_lib"],
)bazel build //src:main
./bazel-bin/src/mainBazel can optionally integrate with Conan for dependency resolution using custom conan_bzl.rc or toolchain files.
- OS packages (
apt,brew) – limited versions - Manual build – slow, error-prone
- CMake FetchContent / ExternalProject_Add – suitable for small projects
Conan simplifies all steps, ensuring reproducibility and automation.
- Use Docker for OS + compiler + tools
- Use Conan for libraries
- Use Bazel or CMake as the build system
- Cache dependencies locally or in CI/CD pipelines
- Combine Docker + Conan + Bazel/CMake for professional, reproducible builds
Jenkins is an open-source automation server for CI/CD.
- Automates builds, tests, deployments
- Supports pipelines for complex workflows
- Integrates seamlessly with Docker, Conan, and Bazel/CMake
Workflow:
Git Push → Jenkins Pipeline Triggered
├─ Checkout Code
├─ Build Docker Image with Tools
├─ Run Conan Install
├─ Build Project (CMake or Bazel)
├─ Run Tests
└─ Deploy or Archive Artifacts
Jenkins = Project Manager Docker = Kitchen Conan = Ingredients Bazel/CMake = Cooking process
flowchart TD
A["Git Push"] --> B["Jenkins Pipeline Triggered"]
B --> C["Build Docker Image with Tools"]
B --> D["Run Tests / Static Analysis"]
C --> E["Run Conan Install (Dependencies)"]
E --> F["Build Project (CMake or Bazel)"]
F --> G["Build Artifacts / Deploy / Archive"]
style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#bbf,stroke:#333,stroke-width:2px
style C fill:#bfb,stroke:#333,stroke-width:2px
style D fill:#ffb,stroke:#333,stroke-width:2px
style E fill:#bff,stroke:#333,stroke-width:2px
style F fill:#fbf,stroke:#333,stroke-width:2px
style G fill:#ffd,stroke:#333,stroke-width:2px
- Docker = OS + compiler + tools
- Conan = library dependencies + reproducibility
- Bazel = fast, deterministic builds with caching
- Jenkins = CI/CD orchestrator
TL;DR:
Together → reproducible, reliable, professional C++ builds
The QuantumLog project demonstrates:
- Real-world C++ project structure
- Integration with CMake or Bazel
- Conan for dependencies (
fmt,spdlog) - Dockerized build environment
- CI/CD readiness with Jenkins
Getting Started:
git clone https://github.com/YoussefMostafaMohammed/QuantumLog.git
cd QuantumLog
# Build with Bazel (optional Conan)
docker build --build-arg BUILD_SYSTEM=bazel --build-arg USE_CONAN=false -t quantumlog-bazel .
docker run --rm quantumlog-bazel