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

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

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

Начать курс

Введение: Когда "собралось на моей машине" — это катастрофа

Каждый C++ разработчик хотя бы раз слышал фразу: "У меня всё работает, странно, что у тебя падает". Или сам её произносил. Компиляция шаблонов, линковка, особенности разных стандартов (C++17, C++20), платформозависимые макросы — C++ полон сюрпризов, которые всплывают при смене окружения.

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

1. Подготовка проекта: структура и система сборки

Прежде чем писать пайплайн, нужно привести проект в порядок. Мы будем использовать CMake — стандарт де-факто для современных C++ проектов. Наш пример будет представлять собой простую утилиту для обработки строк с модульными тестами на Google Test.

Структура репозитория

my_cpp_project/
├── .github/
│   └── workflows/
│       └── ci.yml          # Файл пайплайна
├── src/
│   ├── main.cpp
│   └── string_utils.cpp
├── include/
│   └── string_utils.hpp
├── tests/
│   ├── CMakeLists.txt
│   └── test_string_utils.cpp
├── CMakeLists.txt           # Корневой CMake
├── Dockerfile               # Для финального деплоя
└── README.md

Корневой CMakeLists.txt

Собираем библиотеку и исполняемый файл. Обратите внимание на экспорт тестов:

cmake_minimum_required(VERSION 3.20)
project(MyStringUtils VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Основная библиотека
add_library(string_utils STATIC
    src/string_utils.cpp
    include/string_utils.hpp
)
target_include_directories(string_utils PUBLIC include)

# Исполняемый файл
add_executable(my_app src/main.cpp)
target_link_libraries(my_app PRIVATE string_utils)

# Тесты (опционально, подключаются опцией)
option(BUILD_TESTS "Build unit tests" ON)
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

Пример теста (tests/test_string_utils.cpp)

#include <gtest/gtest.h>
#include "string_utils.hpp"

TEST(StringUtilsTest, ToUpper) {
    EXPECT_EQ(to_upper("hello"), "HELLO");
    EXPECT_EQ(to_upper("C++20"), "C++20");
}

TEST(StringUtilsTest, Trim) {
    EXPECT_EQ(trim("  spaced  "), "spaced");
    EXPECT_EQ(trim("\t\n\r"), "");
}

Теперь, когда проект готов, переходим к главному — настройке CI/CD pipeline для C++.

2. GitHub Actions: пишем первый пайплайн

GitHub Actions — самый популярный инструмент для CI/CD в Open Source. Его конфигурация пишется на YAML и лежит в папке .github/workflows. Создадим файл ci.yml.

Базовая структура: запуск при пуше и PR

name: C++ CI/CD Pipeline

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

jobs:
  build-and-test:
    runs-on: ubuntu-latest

    steps:
    - name: Checkout code
      uses: actions/checkout@v4

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

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

    - name: Build
      run: cmake --build build --parallel $(nproc)

    - name: Run tests
      run: cd build && ctest --output-on-failure

Это минимальный, но уже рабочий CI/CD pipeline для C++. Если тесты падают, пайплайн завершается с ошибкой, и вы получаете уведомление. Но мы пойдём дальше — добавим линтеры, статический анализ и многоплатформенную сборку.

3. Улучшаем пайплайн: линтеры, статика и многоплатформенность

3.1. Линтер: clang-format и clang-tidy

Качество кода в C++ критично. Добавим проверку форматирования и статический анализ:

    - name: Check code formatting (clang-format)
      run: |
        find . -name '*.cpp' -o -name '*.hpp' | xargs clang-format -style=file --dry-run --Werror
      continue-on-error: true  # Не блокируем сборку, но показываем ошибки

    - name: Static analysis (clang-tidy)
      run: |
        cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
        run-clang-tidy -p build -header-filter='.*'

3.2. Многоплатформенная сборка (matrix)

C++ приложения часто требуют совместимости с разными ОС. Используем стратегию matrix:

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        compiler: [g++, clang++]
        exclude:
          - os: macos-latest
            compiler: g++  # На macOS чаще используют clang
    runs-on: ${{ matrix.os }}

    steps:
    - uses: actions/checkout@v4

    - name: Set compiler (Linux/macOS)
      if: runner.os != 'Windows'
      run: |
        echo "CXX=${{ matrix.compiler }}" >> $GITHUB_ENV
        echo "CC=${{ matrix.compiler }}" >> $GITHUB_ENV

    - name: Install dependencies (Ubuntu)
      if: runner.os == 'Linux'
      run: sudo apt-get install -y cmake g++ libgtest-dev

    - name: Install dependencies (macOS)
      if: runner.os == 'macOS'
      run: brew install cmake googletest

    - name: Configure and Build
      run: |
        cmake -B build -DCMAKE_BUILD_TYPE=Debug
        cmake --build build

Теперь ваш CI/CD pipeline для C++ прогоняет сборку на трёх ОС с двумя компиляторами. Это отличная страховка от платформозависимых багов.

4. CD: автоматический деплой C++ приложения

После успешной сборки и тестов логично развернуть приложение. Для C++ это часто означает сборку Docker-образа или публикацию бинарного артефакта. Рассмотрим оба варианта.

4.1. Сборка Docker-образа

Создадим простой Dockerfile для мультистадийной сборки:

# Stage 1: Build
FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y cmake g++ libgtest-dev
WORK                

Блоги

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