Einleitung: Warum ein Monorepository in C++?
\n\nIn der Welt der C++-Entwicklung stellt sich früher oder später die Frage: Wie organisiert man Code, wenn es viele Projekte gibt? Bibliotheken, Hilfsprogramme, ausführbare Dateien – all das muss irgendwie verknüpft, versioniert und gebaut werden. Der traditionelle Ansatz mit vielen einzelnen Repositories (Multirepository) führt oft zu Problemen: Änderungen sind schwer zu synchronisieren, die Integration ist schwer zu testen, und Abhängigkeiten zwischen Projekten werden zur Hölle.
\n\nEine Alternative ist das Monorepository. Es ist ein einziges Repository, in dem alle Komponenten Ihres Projekts gespeichert sind: Bibliotheken, Anwendungen, Tests, Dokumentation. Dieser Ansatz wird aktiv bei Google, Facebook, Microsoft und vielen anderen Unternehmen eingesetzt. Für C++ bietet ein Monorepository eine Reihe von Vorteilen:
\n\n- \n
- Einheitliche Version der Abhängigkeiten – Sie wissen immer, welche Version einer Bibliothek in allen Projekten verwendet wird. \n
- Atomare Commits – Eine Änderung der API einer Bibliothek und die Aktualisierung aller ihrer Nutzer erfolgt in einem einzigen Commit. \n
- Vereinfachtes CI/CD – Eine Pipeline für alle Komponenten. \n
- Transparenz – Es ist leicht zu sehen, wie das gesamte Projekt aufgebaut ist. \n
In diesem Artikel werden wir die praktische Organisation eines Monorepositorys für C++ mit CMake durchgehen, die Ordnerstruktur zeigen und Codebeispiele geben.
\n\n1. Ordnerstruktur: Die Grundlage der Ordnung
\n\nDer erste Schritt zu einem erfolgreichen Monorepository ist eine durchdachte Verzeichnisstruktur. Hier ist eine empfohlene Vorlage für ein C++-Projekt:
\n\nmy_project/\n├── CMakeLists.txt # Root CMake-Datei\n├── README.md\n├── .gitignore\n├── .clang-format\n├── cmake/ # Hilfs-CMake-Module\n│ └── FindMyLib.cmake\n├── libs/ # Bibliotheken\n│ ├── core/ # Bibliothek core\n│ │ ├── CMakeLists.txt\n│ │ ├── include/\n│ │ │ └── core/\n│ │ │ ├── math.h\n│ │ │ └── string_utils.h\n│ │ └── src/\n│ │ ├── math.cpp\n│ │ └── string_utils.cpp\n│ └── network/ # Bibliothek network\n│ ├── CMakeLists.txt\n│ ├── include/\n│ │ └── network/\n│ │ └── http_client.h\n│ └── src/\n│ └── http_client.cpp\n├── apps/ # Ausführbare Anwendungen\n│ ├── server/\n│ │ ├── CMakeLists.txt\n│ │ └── src/\n│ │ └── main.cpp\n│ └── cli_tool/\n│ ├── CMakeLists.txt\n│ └── src/\n│ └── main.cpp\n├── tests/ # Tests\n│ ├── CMakeLists.txt\n│ ├── test_core/\n│ │ ├── CMakeLists.txt\n│ │ └── test_math.cpp\n│ └── test_network/\n│ ├── CMakeLists.txt\n│ └── test_http_client.cpp\n└── third_party/ # Externe Abhängigkeiten (git submodules oder FetchContent)\n └── googletest/\n\n\nWichtige Prinzipien:
\n- \n
- libs/ – alle Bibliotheken. Jede Bibliothek ist ein eigener Ordner mit einer eigenen CMakeLists.txt. \n
- apps/ – alle ausführbaren Dateien. Sie hängen von den Bibliotheken in libs/ ab. \n
- tests/ – Tests, organisiert nach Bibliotheken. \n
- third_party/ – externe Abhängigkeiten. Verwenden Sie
git submodulesoderFetchContent, um sie einzubinden. \n
2. CMake: Build-Konfiguration des Monorepositorys
\n\nCMake ist das ideale Werkzeug für ein Monorepository. Schauen wir uns an, wie die root CMakeLists.txt und die Dateien für die Bibliotheken konfiguriert werden.
Root CMakeLists.txt
\n\ncmake_minimum_required(VERSION 3.20)\nproject(MyProject VERSION 1.0.0 LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 20)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_EXTENSIONS OFF)\n\n# Optionen zum Aktivieren/Deaktivieren von Komponenten\noption(BUILD_TESTS "Build tests" ON)\noption(BUILD_APPS "Build applications" ON)\n\n# Externe Abhängigkeiten einbinden\ninclude(FetchConte