CI/CD for a C++ Project with CMake and GitHub Actions
Configure, build, test -- and cache the compiler so rebuilds are not glacial.
C++ CI with CMake follows a configure-build-test rhythm: generate a build directory, compile, then run the test suite through CTest. C++ compiles are slow, so a compiler cache like ccache is what keeps CI fast on incremental changes. This recipe sets up a Ninja-driven build with caching.
What the pipeline does
- Installs CMake, Ninja, and ccache.
- Configures the project into an out-of-source build directory.
- Compiles with Ninja using ccache.
- Runs the test suite through CTest.
The workflow
Point CMake at ccache via the compiler-launcher variables and persist the ccache directory between runs.
name: C++ CI
on: [push, pull_request]
jobs:
build-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install build tools
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build ccache
- name: Restore ccache
uses: actions/cache@v4
with:
path: ~/.ccache
key: ccache-\${{ github.sha }}
restore-keys: ccache-
- name: Configure
run: |
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build build
- name: Test
run: ctest --test-dir build --output-on-failureNotes for this platform
Compilation dominates C++ CI time, so ccache (wired in via the COMPILER_LAUNCHER variables) is the key to fast feedback -- it turns most incremental rebuilds into cache hits. Use Ninja over Make for better parallelism. The build is Linux-native and belongs on your cheapest, fastest runner class; managed runners auto-retry transient apt-get and dependency-fetch failures so a mirror hiccup does not fail a clean build.
Key takeaways
- Follow configure, build, then CTest for a complete C++ pipeline.
- Wire ccache via CMAKE_*_COMPILER_LAUNCHER and cache ~/.ccache between runs.
- Prefer Ninja over Make for better build parallelism in CI.