Монорепозиторий с C++: организация кода и лучшие практики

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

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

Начать курс

Монорепозиторий с C++: организация кода и лучшие практики

Разработка крупных проектов на C++ часто сталкивается с проблемой фрагментации кода: библиотеки разбросаны по разным репозиториям, версии не синхронизированы, а интеграция превращается в головную боль. Решение — монорепозиторий (monorepo). Это подход, при котором весь код, включая библиотеки, утилиты и тесты, хранится в одном репозитории. В этой статье мы разберем, как правильно организовать монорепозиторий для C++ проектов, используя современные инструменты (CMake, Conan, Git) и избегая типичных ошибок.

1. Структура каталогов: основа порядка

Первый шаг — создать единую, понятную структуру папок. Вот рекомендуемая схема для C++ монорепозитория:

my-monorepo/
├── cmake/                  # Общие CMake-модули
├── libs/                   # Библиотеки
│   ├── core/               # Ядро (логирование, аллокаторы)
│   ├── math/               # Математическая библиотека
│   └── network/            # Сетевая библиотека
├── apps/                   # Исполняемые приложения
│   ├── server/             # Серверное приложение
│   └── client/             # Клиентское приложение
├── tests/                  # Интеграционные тесты
├── scripts/                # Скрипты сборки и деплоя
├── third_party/            # Внешние зависимости (submodules)
├── CMakeLists.txt          # Корневой CMake-файл
├── conanfile.txt           # Менеджер зависимостей (опционально)
└── .github/                # CI/CD (GitHub Actions)

Почему это работает?

  • libs/ — все библиотеки в одном месте, легко переиспользовать.
  • apps/ — приложения, которые зависят от libs.
  • third_party/ — внешние зависимости (через git submodules или CMake FetchContent).
  • cmake/ — кастомные функции (например, add_library_with_tests).

2. CMake: настройка корневого проекта

CMake — стандарт для C++ сборки в монорепозиториях. Настройте корневой CMakeLists.txt так, чтобы он подключал все подпроекты:

cmake_minimum_required(VERSION 3.20)
project(MyMonorepo LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Общие опции
option(BUILD_TESTS "Build tests" ON)

# Подключаем библиотеки
add_subdirectory(libs/core)
add_subdirectory(libs/math)
add_subdirectory(libs/network)

# Подключаем приложения
add_subdirectory(apps/server)
add_subdirectory(apps/client)

# Подключаем тесты
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

Важные моменты:

  • Используйте target_link_libraries для явного указания зависимостей между библиотеками.
  • Для внешних зависимостей (например, Boost, fmt) используйте FetchContent или Conan.
  • Избегайте глобальных include_directories — используйте target_include_directories с PUBLIC или PRIVATE.

3. Управление зависимостями внутри монорепозитория

Одна из главных проблем монорепозитория — циклические зависимости. Решение: строгая иерархия. Например:

  • core (не зависит ни от чего, кроме стандартной библиотеки)
  • math (зависит от core)
  • network (зависит от core и math)
  • server (зависит от core, math, network)

Пример CMakeLists.txt для библиотеки math:

add_library(math
    src/vector.cpp
    src/matrix.cpp
    include/math/vector.h
    include/math/matrix.h
)

target_include_directories(math
    PUBLIC include
    PRIVATE src
)

target_link_libraries(math
    PUBLIC core  # Явно указываем зависимость
)

Совет: Используйте INTERFACE для библиотек, которые содержат только заголовки (header-only). Это ускоряет сборку.

4. CI/CD и автоматизация сборки

Монорепозиторий требует продуманного CI/CD. Основные принципы:

  • Инкрементальная сборка: собирайте только те компоненты, которые изменились. Используйте ccache для ускорения.
  • Матрица сборок: тестируйте на разных компиляторах (GCC, Clang, MSVC) и платформах (Linux, Windows, macOS).
  • Линтинг и форматирование: запускайте clang-tidy и clang-format на каждом PR.

Пример workflow для GitHub Actions (файл .github/workflows/build.yml):

name: Build and Test
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Configure CMake
        run: cmake -B build -DCMAKE_CXX_COMPILER=clang++ -DBUILD_TESTS=ON
      - name: Build
        run: cmake --build build --parallel
      - name: Test
        run: ctest --test-dir build --output-on-failure

Важно: В больших монорепозиториях (100+ библиотек) используйте инструменты вроде Bazel или Buck2, которые умеют кэшировать результаты сборки на уровне файлов. Но для средних проектов CMake + ccache — оптимальный выбор.

Заключение

Монорепозиторий для C++ — это не просто модный тренд, а реальный способ ускорить разработку и уменьшить хаос. Главное — придерживаться четкой структуры (libs/apps/tests), использовать современные CMake-практики (target-based, FetchContent) и автоматизировать CI/CD. Начните с малого: перенесите

Блоги

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