Introduction to CI/CD for C++ with GitHub Actions
\nModern C++ development is unthinkable without automating build and testing processes. CI/CD (Continuous Integration / Continuous Deployment) allows teams to quickly identify errors, automatically build binary files, and deploy applications. GitHub Actions is a powerful tool built into GitHub that is ideal for C++ projects. In this article, we will break down how to set up a complete CI/CD pipeline for C++: from compilation with CMake to deploying finished artifacts.
\nWe will look at real code examples, common errors, and best practices. After reading, you will be able to independently implement CI/CD in your C++ project.
\n\nGitHub Actions Basics for C++
\nWorkflow File Structure
\nA workflow in GitHub Actions is defined by a YAML file in the .github/workflows/ directory. Let's look at a basic example for a C++ project:
name: C++ CI/CD Pipeline\n\non:\n push:\n branches: [ main, develop ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n runs-on: ubuntu-latest\n\n steps:\n - name: Checkout repository\n uses: actions/checkout@v4\n\n - name: Install dependencies\n run: |\n sudo apt-get update\n sudo apt-get install -y cmake g++ libboost-all-dev\n\n - name: Configure with CMake\n run: mkdir build && cd build && cmake ..\n\n - name: Build project\n run: cd build && make -j$(nproc)\n\n - name: Run tests\n run: cd build && ctest --output-on-failure\nThis workflow runs on pushes to main and develop, as well as when a pull request is created. It installs dependencies, configures the build via CMake, compiles the project, and runs tests.
Choosing an Operating System and Compiler
\nGitHub Actions supports Linux (ubuntu), macOS, and Windows. For cross-platform projects, you can use a build matrix:
\njobs:\n build:\n strategy:\n matrix:\n os: [ubuntu-latest, macos-latest, windows-latest]\n compiler: [g++, clang++]\n runs-on: ${{ matrix.os }}\n\n steps:\n - name: Set compiler\n run: |\n if [ "${{ matrix.os }}" == "windows-latest" ]; then\n echo "CXX=cl.exe" >> $GITHUB_ENV\n else\n echo "CXX=${{ matrix.compiler }}" >> $GITHUB_ENV\n fi\n shell: bash\nThis allows you to check code compatibility with different compilers and OS.
\n\nAdvanced Configuration: Testing, Caching, and Artifacts
\nDependency Caching
\nEach build in GitHub Actions starts with a clean environment. To speed up the process, cache downloaded packages and libraries:
\n- name: Cache CMake build directory\n uses: actions/cache@v3\n with:\n path: build\n key: ${{ runner.os }}-cmake-${{ hashFiles('**/CMakeLists.txt') }}\n restore-keys: |\n ${{ runner.os }}-cmake-\n\n- name: Configure CMake\n run: cmake -B build -S . -DCMAKE_BUILD_TYPE=Release\nThe cache is restored if the CMakeLists.txt files have not changed, saving time on subsequent builds.
\n\nRunning Unit Tests with Google Test
\nGoogle Test is often used for C++. Let's add a testing stage with report generation in JUnit format:
\n- name: Build and run tests\n run: |\n cmake --build build --target all_tests\n cd build && ctest --output-junit test-results.xml\n\n- name: Upload test results\n if: always()\n uses: actions/upload-artifact@v4\n with:\n name: test-results-${{ runner.os }}\n path: build/test-results.xml\nThe if: always() flag ensures the report is uploaded even if tests fail.
Creating and Publishing Artifacts
\nAfter a successful build, you can save the binary files:
\n- name: Build release binary\n run: cmake --build build --config Release\n\n- name: Upload build artifacts\n uses: ac