CI/CD для C++ проектов: настройка GitHub Actions

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

CI/CD для C++ проектов: настройка GitHub Actions

Современная разработка на C++ требует не только написания качественного кода, но и настройки процессов его сборки, тестирования и развертывания. CI/CD (Continuous Integration / Continuous Deployment) — это практика, которая позволяет автоматизировать эти процессы, сокращая время между написанием кода и его доставкой пользователям. В этой статье мы рассмотрим, как настроить CI/CD для C++ проектов с помощью GitHub Actions — мощного и бесплатного инструмента, встроенного в GitHub.

GitHub Actions позволяет создавать автоматические рабочие процессы (workflows), которые запускаются при определенных событиях: push в репозиторий, создание pull request, релиз и другие. Для C++ проектов это особенно полезно, так как позволяет гарантировать, что код собирается на разных платформах и не содержит регрессий.

Основы GitHub Actions для C++

GitHub Actions использует YAML-файлы для описания workflows. Каждый workflow состоит из одного или нескольких jobs, которые выполняются на виртуальных машинах (runners). Для C++ проектов обычно используются Ubuntu, Windows и macOS runners. Рассмотрим базовую структуру workflow-файла.

name: C++ CI

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Install dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y cmake g++ libboost-all-dev

    - name: Configure CMake
      run: cmake -B build -DCMAKE_BUILD_TYPE=Release

    - name: Build
      run: cmake --build build --config Release

    - name: Test
      run: cd build && ctest --output-on-failure

Этот workflow запускается при push в ветки main и develop, а также при создании pull request в main. Он устанавливает зависимости (CMake, g++, Boost), конфигурирует проект, собирает его и запускает тесты.

Многоплатформенная сборка C++ проектов

Одно из главных преимуществ CI/CD для C++ — возможность автоматически проверять сборку на нескольких платформах. Это критически важно, так как C++ код может вести себя по-разному на разных ОС и компиляторах. GitHub Actions позволяет легко организовать матрицу сборки.

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        compiler: [g++, clang++]
        include:
          - os: ubuntu-latest
            compiler: g++
            cmake_flags: -DCMAKE_CXX_COMPILER=g++-11
          - os: ubuntu-latest
            compiler: clang++
            cmake_flags: -DCMAKE_CXX_COMPILER=clang++-14
          - os: windows-latest
            compiler: msvc
            cmake_flags: -DCMAKE_CXX_COMPILER=cl
          - os: macos-latest
            compiler: clang++
            cmake_flags: -DCMAKE_CXX_COMPILER=clang++

    runs-on: ${{ matrix.os }}

    steps:
    - uses: actions/checkout@v4

    - name: Install dependencies (Ubuntu)
      if: matrix.os == 'ubuntu-latest'
      run: |
        sudo apt-get update
        sudo apt-get install -y cmake g++-11 clang-14 libboost-all-dev

    - name: Install dependencies (macOS)
      if: matrix.os == 'macos-latest'
      run: |
        brew update
        brew install cmake boost

    - name: Install dependencies (Windows)
      if: matrix.os == 'windows-latest'
      run: |
        choco install cmake boost-msvc-14.3

    - name: Configure CMake
      run: cmake -B build ${{ matrix.cmake_flags }} -DCMAKE_BUILD_TYPE=Release

    - name: Build
      run: cmake --build build --config Release

    - name: Test
      run: |
        if [ "${{ runner.os }}" == "Windows" ]; then
          cd build && ctest -C Release --output-on-failure
        else
          cd build && ctest --output-on-failure
        fi

В этом примере используется стратегия matrix, которая создает отдельные job для каждой комбинации ОС и компилятора. Это позволяет быстро выявить проблемы, связанные с платформо-зависимым кодом.

Оптимизация времени сборки: кэширование и параллелизм

Сборка C++ проектов может занимать много времени, особенно если проект большой. GitHub Actions предоставляет механизмы для ускорения: кэширование зависимостей и параллельное выполнение job. Рассмотрим, как настроить кэширование для CMake и пакетных менеджеров.

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4

    - name: Cache CMake build directory
      uses: actions/cache@v3
      with:
        path: build
        key: ${{ runner.os }}-cmake-${{ hashFiles('**/CMakeLists.txt') }}
        restore-keys: |
          ${{ runner.os }}-cmake-

    - name: Install dependencies
      run: |
        sudo apt-get update
        sudo apt-get install -y cmake g++ libboost-all-dev

    - name: Configure CMake
      run: cmake -B build -DCMAKE_BUILD_TYPE=Release

    - name: Build
      run: cmake --build build --config Release

    - name: Test
      run: cd build && ctest --output-on-failure

Кэширование директории build позволяет сохранять результаты предыдущей сборки. Если CMakeLists.txt не изменился, то при следующем запуске workflow будет использоваться кэш, что значительно ускоряет процесс. Также можно кэшировать зависимости, установленные через apt, brew или vcpkg.

Для параллельного выполнения job используйте стратегию matrix, как показано выше. GitHub Actions автоматически запускает их параллельно, что сокращает общее время прохождения workflow.

Автоматический деплой C++ приложений

После успешной сборки и тестирования можно настроить автоматический деплой. Для C++ проектов это может быть загрузка собранных артефактов (бинарных файлов, библиотек) в релизы GitHub, на сервер или в облачное хранилище. Рассмотрим пример деплоя в GitHub Releases.

jobs:
  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')

    steps:
    - uses: actions/checkout@v4

    - name: Build release binary
      run: |
        cmake -B build -DCMAKE_BUILD_TYPE=Release
        cmake --build build --config Release

    - name: Create release archive
      run: |
        mkdir -p release
        cp build/bin/myapp release/
        tar -czf myapp-${{ github.ref_name }}.tar.gz -C release .

    - name: Upload to Release
      uses: softprops/action-gh-release@v1
      with:
        files: myapp-${{ github.ref_name }}.tar.gz

Этот workflow срабатывает только при создании тега, начинающегося с "v

Блоги

Рекомендаций по книгам