Einleitung: Wenn "bei mir läuft es" eine Katastrophe ist
Jeder C++-Entwickler hat mindestens einmal den Satz gehört: "Bei mir funktioniert alles, komisch, dass es bei dir abstürzt." Oder ihn selbst gesagt. Template-Instanziierung, Linken, Besonderheiten verschiedener Standards (C++17, C++20), plattformabhängige Makros – C++ ist voller Überraschungen, die bei einem Umgebungswechsel auftauchen.
Eine CI/CD-Pipeline (Continuous Integration / Continuous Deployment) für C++ ist kein Luxus, sondern eine Notwendigkeit. Sie baut das Projekt automatisch, führt Tests durch, überprüft die Codequalität und stellt bei Erfolg die Anwendung auf einem Server bereit (oder veröffentlicht eine Bibliothek). In diesem Artikel richten wir eine vollständige Pipeline von Grund auf ein, unter Verwendung von GitHub Actions, CMake und C++. Sie erhalten eine fertige Konfiguration, die Sie an Ihr Projekt anpassen können.
1. Projektvorbereitung: Struktur und Build-System
Bevor wir die Pipeline schreiben, müssen wir das Projekt in Ordnung bringen. Wir verwenden CMake – den De-facto-Standard für moderne C++-Projekte. Unser Beispiel wird ein einfaches Dienstprogramm zur Zeichenkettenverarbeitung mit Modultests auf Basis von Google Test sein.
Repository-Struktur
my_cpp_project/├── .github/│ └── workflows/│ └── ci.yml # Pipeline-Datei├── src/│ ├── main.cpp│ └── string_utils.cpp├── include/│ └── string_utils.hpp├── tests/│ ├── CMakeLists.txt│ └── test_string_utils.cpp├── CMakeLists.txt # Root-CMake├── Dockerfile # Für das finale Deployment└── README.mdRoot CMakeLists.txt
Wir bauen die Bibliothek und die ausführbare Datei. Beachten Sie den Export der Tests:
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)
# Hauptbibliothekadd_library(string_utils STATIC src/string_utils.cpp include/string_utils.hpp)target_include_directories(string_utils PUBLIC include)
# Ausführbare Dateiadd_executable(my_app src/main.cpp)target_link_libraries(my_app PRIVATE string_utils)
# Tests (optional, über Option aktiviert)option(BUILD_TESTS "Build unit tests" ON)if(BUILD_TESTS) enable_testing() add_subdirectory(tests)endif()Beispieltest (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\\r"), "");}Nachdem das Projekt fertig ist, kommen wir zum Hauptteil – der Einrichtung der CI/CD-Pipeline für C++.
2. GitHub Actions: Unsere erste Pipeline schreiben
GitHub Actions ist das beliebteste Tool für CI/CD im Open-Source-Bereich. Seine Konfiguration wird in YAML geschrieben und liegt im Ordner .github/workflows. Erstellen wir die Datei ci.yml.
Basisstruktur: Auslösung bei Push und 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-failureDies ist eine minimale, aber bereits funktionierende CI/CD-Pipeline für C++. Wenn Tests fehlschlagen, bricht die Pipeline mit einem Fehler ab und Sie erhalten eine Benachrichtigung. Aber wir gehen noch weiter