Monorepository mit C++: Code-Organisation in der Praxis

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einführung: Warum ein Monorepo für C++?



In der modernen C++-Entwicklung, insbesondere bei mittleren und großen Projekten, wird die Code-Organisation zu einer kritischen Aufgabe. Ein Monorepository (Monorepo) ist ein Ansatz, bei dem der Code aller Komponenten, Bibliotheken und Dienste in einem einzigen Repository gespeichert wird. Im Gegensatz zu Multi-Repositories bietet ein Monorepo einen einzigen Einstiegspunkt, vereinfacht Refactoring und Abhängigkeitsverwaltung. In der Praxis bedeutet dies, dass Sie die API einer Bibliothek ändern und sofort sehen können, wie sich dies auf alle abhängigen Module auswirkt.



In diesem Artikel werden wir die praktischen Aspekte der Organisation von C++-Code in einem Monorepo behandeln: von der Ordnerstruktur bis zur CI/CD-Konfiguration. Sie erfahren, wie Sie typische Fehler vermeiden und den Build schnell und vorhersagbar gestalten.



1. Struktur eines Monorepos für C++



Die richtige Ordnerstruktur ist die Grundlage eines erfolgreichen Monorepos. Betrachten wir die empfohlene Hierarchie für C++-Projekte.



Basisverzeichnishierarchie



my_project/├── CMakeLists.txt          # Root-Build-Datei├── cmake/                  # Benutzerdefinierte CMake-Module│   └── FindMyLib.cmake├── libs/                   # Interne Bibliotheken│   ├── core/│   │   ├── CMakeLists.txt│   │   ├── include/│   │   │   └── core/│   │   │       ├── utils.h│   │   │       └── types.h│   │   └── src/│   │       ├── utils.cpp│   │       └── types.cpp│   └── network/│       ├── CMakeLists.txt│       ├── include/│       │   └── network/│       │       └── http_client.h│       └── src/│           └── http_client.cpp├── apps/                   # Ausführbare Anwendungen│   ├── server/│   │   ├── CMakeLists.txt│   │   └── src/│   │       └── main.cpp│   └── cli/│       ├── CMakeLists.txt│       └── src/│           └── main.cpp├── tests/                  # Integrationstests│   ├── CMakeLists.txt│   └── test_integration.cpp├── third_party/            # Externe Abhängigkeiten (Vendoring)│   ├── fmt/│   └── spdlog/├── .github/                # CI/CD-Konfiguration│   └── workflows/│       └── build.yml└── README.md


Wichtige Prinzipien:

  • libs/ — alle internen Bibliotheken. Jede Bibliothek hat ihren eigenen Ordner mit CMakeLists.txt.
  • apps/ — ausführbare Dateien. Sie hängen von den Bibliotheken in libs/ ab.
  • third_party/ — Vendor-Abhängigkeiten (git submodules oder kopierte Quellen).
  • tests/ — Integrationstests, die das Zusammenspiel mehrerer Bibliotheken prüfen.


Beispiel CMakeLists.txt für eine Bibliothek



# libs/core/CMakeLists.txtadd_library(core    src/utils.cpp    src/types.cpp)

target_include_directories(core PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)

target_link_libraries(core PUBLIC fmt::fmt spdlog::spdlog)


Wichtig: Verwenden Sie PUBLIC und PRIVATE für die korrekte Weitergabe von Abhängigkeiten. Dies ist ein entscheidender Punkt — wenn Bibliothek A Bibliothek B nur in ihren eigenen Quelldateien verwendet, machen Sie B zu PRIVATE.



2. Abhängigkeitsverwaltung im Monorepo



Eines der Hauptprobleme von Monorepos ist der „Abhängigkeits-Overhead“. In C++ wird dies durch CMake target-oriented design gelöst.



Regel: Ein Target — eine Bibliothek



Jede Bibliothek sollte genau ein CMake-Target exportieren. Dies vereinfacht das Linken und verhindert zyklische Abhängigkeiten.



# Root CMakeLists.txtcmake_minimum_required(VERSION 3.20)project(MyProject VERSION 1.0.0 LANGUAGES CXX)

# Alle Bibliotheken einbindenadd_subdirectory(libs/core)add_subdirectory(libs/network)

Blogs

Buchempfehlungen