A modern, production-ready template for C++ development.
| Capability | Tool / Setup | Status |
|---|---|---|
| Build | CMake ≥ 3.20 | ✔ |
| Unit tests | GoogleTest (optional) | ✔ |
| Formatting | clang-format (pre-commit) | ✔ |
| Linting | clang-tidy (pre-commit) | ✔ |
| Docs | Doxygen | ✔ |
| Dev environment | Docker image, VS Code DevContainer | ✔ |
| CI | GitHub Actions (Ubuntu 24.04) | ✔ |
git clone <your-fork> my_project && cd my_project
# Install pre-commit hooks (for code quality checks on push)
pre-commit install --hook-type pre-push
cmake -S . -B build # -DENABLE_UNIT_TESTS=OFF to skip tests
cmake --build build -j$(nproc)
./build/bin/main_exec
ctest --test-dir build --output-on-failure # if tests enabled.
├── CMakeLists.txt root build script
├── src/ production code
│ ├── example_public_private/ PUBLIC vs PRIVATE visibility (see README)
│ ├── example_interface/ INTERFACE library (header-only)
│ ├── example_static/ static library example (.a)
│ ├── example_shared/ shared library example (.so + RPATH)
│ ├── example_plugin_loader/ runtime plugin loader (dlopen)
│ ├── example_plugin_impl/ sample plugin implementation
│ └── main/ console application
├── tests/ unit tests (GoogleTest)
├── external/ third-party code (empty by default)
├── scripts/ helper scripts
├── docs/ documentation (Doxygen, guides)
└── .devcontainer/ VS Code container files
- PUBLIC/PRIVATE visibility: See docs/public-private-guide.md
- RPATH configuration: See docs/rpath-guide.md
- DevContainer setup: See docs/devcontainer-guide.md
# Development build (Debug, with debug symbols)
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
# Release build (optimized, for packaging)
cmake -S . -B build -DCMAKE_BUILD_TYPE=ReleaseKey flags:
| Flag | Effect |
|---|---|
-DENABLE_UNIT_TESTS=OFF |
Skip GoogleTest and test targets |
-DENABLE_COVERAGE=ON |
Enable code coverage with gcov |
-DBUILD_SHARED_LIBS=ON |
Build libraries as shared |
This project uses RPATH (Runtime Path) for portable library discovery:
your-package/
├── bin/
│ └── main_exec ← RPATH: $ORIGIN/../lib
└── lib/
├── libexample_shared.so ← Found automatically
└── libexample_plugin_impl.so ← Found by dlopen()
Key Benefits:
- Self-contained packages - work anywhere without installation
- No environment setup - no
LD_LIBRARY_PATHneeded - Plugin discovery -
dlopen()finds plugins via RPATH - Clean code - no hardcoded paths
For detailed RPATH explanation, examples, and troubleshooting, see docs/rpath-guide.md
| Script | Purpose |
|---|---|
build.sh |
Configure and compile (Debug mode) |
package.sh |
Build and create distributable packages (Release) |
coverage.sh |
Build with coverage, run tests, generate report |
format.sh |
Run clang-format on sources (use --check for CI) |
lint.sh |
Run clang-tidy using compile commands |
docs.sh |
Generate HTML docs |
Build vs Package:
./scripts/build.sh— Debug build for development (fast compilation, debug symbols)./scripts/package.sh— Release build + CPack packaging (optimized, distributable)
Docker-related scripts live under scripts/docker/:
| Script | Purpose |
|---|---|
build_image.sh |
Build the cpp-dev:latest image |
run.sh |
Run the dev container with UID/GID remap |
attach.sh |
Attach to running container as ubuntu |
Install hooks once (runs on git push, not commit):
pre-commit install --hook-type pre-pushBefore each push, pre-commit will:
- Run
clang-formatto check code formatting - Run
clang-tidyto analyze code quality
These checks ensure consistent code style across the team.
VS Code DevContainer users: Hooks are installed automatically via postCreateCommand.
Generate HTML documentation from code comments:
./scripts/docs.sh
xdg-open docs/html/index.htmlThis project uses a portable Docker image with runtime UID/GID remapping. The same image works for all users without rebuilding.
Build image
./scripts/docker/build_image.shRun interactive container
./scripts/docker/run.shAttach to the running container
./scripts/docker/attach.shThis attaches as user ubuntu (with remapped UID/GID). If the container isn't running, the script will fail—start it first with ./scripts/docker/run.sh.
Customize attach behavior:
To attach as root (for system administration):
docker exec -it -u root cpp-dev-${USER} bashTo attach with your host UID/GID directly:
docker exec -it -u "$(id -u):$(id -g)" cpp-dev-${USER} bashVS Code DevContainer:
VS Code users can reopen the workspace in the container. The Dev Container uses the prebuilt cpp-dev:latest image and relies on a runtime entrypoint to remap UID/GID (no extra vsc-…-uid image is created).
For detailed information about the DevContainer setup, see docs/devcontainer-guide.md
The CI pipeline runs on every push and pull request:
on: [push, pull_request]
runs-on: ubuntu-24.04
steps:
- Install dependencies (cmake, clang-format)
- Build project with CMake
- Run all unit tests with ctestSee .github/workflows/ci.yml for the complete configuration.
Unit tests are enabled by default using GoogleTest (fetched automatically via CMake FetchContent).
cmake -S . -B build
cmake --build build
ctest --test-dir build --output-on-failureTo disable tests:
cmake -S . -B build -DENABLE_UNIT_TESTS=OFF