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