<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Tools on kenji.blog</title><link>http://kenji.blog/de/categories/tools/</link><description>Recent content in Tools on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 09:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/categories/tools/index.xml" rel="self" type="application/rss+xml"/><item><title>Anleitung zur Einrichtung einer plattformübergreifenden C++-Build-Umgebung mit CMake</title><link>http://kenji.blog/de/p/cmake-cross-platform-build-environment-guide/</link><pubDate>Sat, 12 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/cmake-cross-platform-build-environment-guide/</guid><description>&lt;img src="http://kenji.blog/p/cmake-cross-platform-build-environment-guide/img/eyecatch.jpg" alt="Featured image of post Anleitung zur Einrichtung einer plattformübergreifenden C++-Build-Umgebung mit CMake" />&lt;p>Bei der Softwareentwicklung mit C++ ist die Auswahl und Einrichtung eines „Build-Systems“ ein Thema, das vielen Entwicklern seit Jahren Kopfzerbrechen bereitet. Da es in C++ keinen offiziellen Standard-Paketmanager oder ein einheitliches Build-System gibt, war es bisher notwendig, je nach Plattform (Windows, Linux, macOS) unterschiedliche Compiler und Build-Tools (MSVC, GCC, Clang, Make, Ninja usw.) zu verwenden.&lt;/p>
&lt;p>Heutzutage hat sich jedoch &lt;strong>CMake&lt;/strong> als De-facto-Branchenstandard etabliert. Wenn CMake richtig eingesetzt wird, lässt sich aus einer einzigen &lt;code>CMakeLists.txt&lt;/code>-Datei elegant eine plattformübergreifende Build-Umgebung aufbauen.&lt;/p>
&lt;p>In diesem Artikel werden die Schritte zur Einrichtung einer modernen, plattformübergreifenden C++-Build-Umgebung (Modern CMake) von den Grundlagen bis hin zu fortgeschrittenen Techniken ausführlich und detailliert erläutert.&lt;/p>
&lt;h2 id="1-was-ist-cmake-das-konzept-des-meta-build-systems">1. Was ist CMake? (Das Konzept des Meta-Build-Systems)
&lt;/h2>&lt;p>CMake ist kein Werkzeug, das den Quellcode selbst direkt kompiliert. CMake ist ein „System, das Build-Systeme generiert“, also ein &lt;strong>Meta-Build-System&lt;/strong>.&lt;/p>
&lt;p>Die Hauptaufgabe von CMake besteht darin, eine abstrakte Konfigurationsdatei (&lt;code>CMakeLists.txt&lt;/code>), die unabhängig von Plattform oder Compiler ist, einzulesen und die jeweils optimalen nativen Build-Skripte für die jeweilige Umgebung (z. B. &lt;code>Makefile&lt;/code> für Linux, Visual Studio &lt;code>.sln&lt;/code>-Projektdateien für Windows oder das schnelle &lt;code>build.ninja&lt;/code>) automatisch zu generieren.&lt;/p>
&lt;p>Das folgende Diagramm veranschaulicht den Generierungsprozess von CMake.&lt;/p>
&lt;div class="mermaid">graph TD
A["CMakeLists.txt (Abstrakte Build-Definition)"] --> B["CMake (Konfigurieren &amp; Generieren)"]
B --> C["Unix Makefiles"]
B --> D["Ninja Build-Dateien"]
B --> E["Visual Studio-Lösungen"]
B --> F["Xcode-Projekte"]
C --> G["Natives Build-Tool (make, ninja, MSBuild, xcodebuild)"]
D --> G
E --> G
F --> G
G --> H["Ausführbare Datei / Freigegebene Bibliothek / Statische Bibliothek"]&lt;/div>
&lt;p>Durch das Dazwischenschalten von CMake können Entwickler C++-Projekte verwalten, ohne sich um die feinen Befehlsunterschiede der einzelnen Betriebssysteme kümmern zu müssen.&lt;/p>
&lt;h2 id="2-grundlagen-von-modern-cmake-von-variablen-zu-targets">2. Grundlagen von Modern CMake: Von Variablen zu Targets
&lt;/h2>&lt;p>Die Schreibweise ab CMake 3.0 wird als „Modern CMake“ bezeichnet und unterscheidet sich in ihrer Designphilosophie grundlegend von früheren Versionen (Legacy CMake). In Legacy CMake war der Ansatz vorherrschend, globale Variablen verzeichnisweise zu überschreiben (z. B. durch die Verwendung von &lt;code>include_directories()&lt;/code> oder &lt;code>link_libraries()&lt;/code>). Dies führte jedoch oft zu schwerwiegenden Nebenwirkungen, bei denen Konfigurationen unbeabsichtigt auf andere Module übergriffen.&lt;/p>
&lt;p>In Modern CMake wird alles als &lt;strong>Target (Ziel)&lt;/strong> und &lt;strong>Property (Eigenschaft)&lt;/strong> behandelt. Dies ähnelt der Beziehung zwischen Klassen und Membervariablen in der objektorientierten Programmierung.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Target&lt;/strong>: Eine ausführbare Datei (Executable) oder eine Bibliothek (Library).&lt;/li>
&lt;li>&lt;strong>Property&lt;/strong>: Quelldateien, Include-Verzeichnisse, Kompilierungsoptionen, andere zu verlinkende Bibliotheken usw., die zum Erstellen dieses Targets erforderlich sind.&lt;/li>
&lt;/ul>
&lt;p>Indem die Einstellungen ausschließlich in bestimmten Targets gekapselt (eingeschlossen) werden, ist eine sichere Build-Definition möglich, die auch bei Großprojekten nicht zusammenbricht.&lt;/p>
&lt;h3 id="ein-minimales-cmakeliststxt">Ein minimales &lt;code>CMakeLists.txt&lt;/code>
&lt;/h3>&lt;p>Sehen wir uns zunächst die grundlegendste &lt;code>CMakeLists.txt&lt;/code> an.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># CMake-Mindestversion festlegen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Projektname und zu verwendende Sprache festlegen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">VERSION&lt;/span> &lt;span class="s">1.0.0&lt;/span> &lt;span class="s">LANGUAGES&lt;/span> &lt;span class="s">CXX&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># C++-Standard (C++20) anfordern
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD_REQUIRED&lt;/span> &lt;span class="s">ON&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_EXTENSIONS&lt;/span> &lt;span class="s">OFF&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c"># Compiler-spezifische Erweiterungen deaktivieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Ausführbares Target definieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Mit nur diesen wenigen Zeilen ist die Build-Konfiguration für eine portable, ausführbare Datei, die C++20 erfordert und Compiler-Erweiterungen deaktiviert, abgeschlossen.&lt;/p>
&lt;h2 id="3-abhängigkeiten-und-gültigkeitsbereich-public--private--interface">3. Abhängigkeiten und Gültigkeitsbereich: PUBLIC / PRIVATE / INTERFACE
&lt;/h2>&lt;p>Das wichtigste und zugleich schwierigste Konzept, das es bei Modern CMake zu meistern gilt, sind die drei Zugriffsmodifikatoren (Sichtbarkeitsbereiche) &lt;strong>&lt;code>PUBLIC&lt;/code>, &lt;code>PRIVATE&lt;/code>, &lt;code>INTERFACE&lt;/code>&lt;/strong>, die beispielsweise in &lt;code>target_include_directories&lt;/code> oder &lt;code>target_link_libraries&lt;/code> verwendet werden.&lt;/p>
&lt;p>Diese dienen dazu, zu steuern, ob die Eigenschaften eines Targets (Include-Pfade oder abhängige Bibliotheken) „für den eigenen Build benötigt werden“ und ob sie „auch an andere Targets, die von diesem Target abhängen, weitergegeben werden“.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>&lt;code>PRIVATE&lt;/code>&lt;/strong>: Wird nur für den Build des Targets selbst benötigt. Es wird &lt;strong>nicht&lt;/strong> an abhängige Targets weitergegeben.&lt;/li>
&lt;li>&lt;strong>&lt;code>INTERFACE&lt;/code>&lt;/strong>: Wird für den eigenen Build des Targets nicht benötigt, wird aber an den Build abhängiger Targets &lt;strong>weitergegeben&lt;/strong> (z. B. bei Header-only-Bibliotheken verwendet).&lt;/li>
&lt;li>&lt;strong>&lt;code>PUBLIC&lt;/code>&lt;/strong>: Wird für den eigenen Build des Targets benötigt und wird auch an abhängige Targets &lt;strong>weitergegeben&lt;/strong> (&lt;code>PRIVATE&lt;/code> + &lt;code>INTERFACE&lt;/code>).&lt;/li>
&lt;/ol>
&lt;p>Lassen Sie uns die Weitergabe von Abhängigkeiten (Weitergabe von Usage Requirements) im folgenden Diagramm visualisieren.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Bibliotheken"
MathLib["MathLib (Statische Bibliothek)"]
NetworkLib["NetworkLib (Freigegebene Bibliothek)"]
HeaderLib["HeaderLib (Nur-Header)"]
end
subgraph "Anwendung"
App["Hauptanwendung"]
end
App -- "target_link_libraries(App PRIVATE MathLib)" --> MathLib
App -- "target_link_libraries(App PUBLIC NetworkLib)" --> NetworkLib
NetworkLib -- "target_link_libraries(NetworkLib INTERFACE HeaderLib)" --> HeaderLib
note1["App hängt von der Implementierung von MathLib ab, zeigt diese aber nicht nach außen"]
note2["NetworkLib macht die Schnittstelle von HeaderLib öffentlich zugänglich"]&lt;/div>
&lt;h3 id="konkretes-anwendungsbeispiel-für-sichtbarkeitsbereiche">Konkretes Anwendungsbeispiel für Sichtbarkeitsbereiche
&lt;/h3>&lt;p>Angenommen, eine Bibliothek &lt;code>MyLib&lt;/code> verwendet intern &lt;code>nlohmann/json&lt;/code> als Implementierung, ohne dass &lt;code>nlohmann/json&lt;/code> in der öffentlichen Header-Datei &lt;code>MyLib.hpp&lt;/code> inkludiert wird. In diesem Fall muss der Nutzer von &lt;code>MyLib&lt;/code> (die Anwendung) nichts von der Existenz der JSON-Bibliothek wissen.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Bibliotheksdefinition
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_library&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyLib&lt;/span> &lt;span class="s">src/MyLib.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Angabe der Include-Verzeichnisse des eigenen Projekts
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Das include-Verzeichnis wird PUBLIC gemacht, da es auch für die Nutzer von MyLib erforderlich ist
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Das src-Verzeichnis wird PRIVATE gemacht, da es nur in der Implementierung von MyLib verwendet wird
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_include_directories&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyLib&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">PUBLIC&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">INSTALL_INTERFACE:include&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">PRIVATE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">${&lt;/span>&lt;span class="nv">CMAKE_CURRENT_SOURCE_DIR&lt;/span>&lt;span class="o">}&lt;/span>&lt;span class="s">/src&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Die JSON-Bibliothek wird nur in der internen Implementierung verwendet, daher wird sie als PRIVATE verlinkt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyLib&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">nlohmann_json::nlohmann_json&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Wenn andererseits &lt;code>#include &amp;lt;nlohmann/json.hpp&amp;gt;&lt;/code> in &lt;code>MyLib.hpp&lt;/code> steht, erhält die Seite, die &lt;code>MyLib&lt;/code> verwendet, einen Kompilierungsfehler, wenn sie den JSON-Header-Pfad nicht kennt. Daher muss sie als &lt;code>PUBLIC&lt;/code> verlinkt werden. Durch die richtige Einstellung dieser Sichtbarkeitsbereiche können Build-Zeiten verkürzt und die Weitergabe unnötiger Abhängigkeiten (Re-Poisoning) verhindert werden.&lt;/p>
&lt;h2 id="4-out-of-source-build">4. Out-of-Source-Build
&lt;/h2>&lt;p>Eine Best Practice, die bei der Verwendung von CMake immer befolgt werden sollte, ist der &lt;strong>Out-of-Source-Build&lt;/strong>.
Dies ist eine Methode, bei der die Build-Ergebnisse (Objektdateien und ausführbare Dateien) überhaupt nicht in das Verzeichnis ausgegeben werden, in dem sich der Quellcode befindet (der Quellcode-Baum). Stattdessen findet der Build getrennt in einem speziellen Verzeichnis (normalerweise &lt;code>build/&lt;/code>) statt.&lt;/p>
&lt;div class="mermaid">graph TD
Root["Projekt-Stammverzeichnis (Git-Repository)"]
Root --> Src["src/"]
Root --> Inc["include/"]
Root --> CMake["CMakeLists.txt"]
Root -. "Build-Verzeichnis erstellen" .-> Build["build/ (Out-of-source)"]
Build --> Obj["CMakeFiles/ (Objektdateien, Caches)"]
Build --> Bin["Binärdateien (MyApp.exe)"]
Build --> Gen["Generiertes Makefile / build.ninja"]&lt;/div>
&lt;p>Mit dieser Struktur reicht es bei einem gewünschten Zurücksetzen der Build-Umgebung aus, einfach das gesamte &lt;code>build&lt;/code>-Verzeichnis zu löschen. Da der Quellcode-Baum nicht verunreinigt wird, ist auch die Verwaltung mit Git einfach (es reicht aus, &lt;code>build/&lt;/code> zur &lt;code>.gitignore&lt;/code> hinzuzufügen).&lt;/p>
&lt;h3 id="ausführungsschritte-des-builds">Ausführungsschritte des Builds
&lt;/h3>&lt;p>In Modern CMake kann der Build mit gängigen Befehlen ausgeführt werden, die nicht vom Betriebssystem oder Build-Tool abhängen.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Konfiguration und Generierung (Erstellen des Build-Verzeichnisses und Festlegen der Einstellungen)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake -S . -B build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Der eigentliche Build (Kompilieren und Linken)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build build --config Release
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (Optional) Für Multithreading-Builds die Option -j verwenden&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build build --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Hier bedeutet &lt;code>cmake -S . -B build&lt;/code>: „Setze das aktuelle Verzeichnis (&lt;code>.&lt;/code>) als Quellverzeichnis und &lt;code>build&lt;/code> als Build-Verzeichnis.“&lt;/p>
&lt;h2 id="5-methoden-zur-einbindung-von-drittanbieter-bibliotheken">5. Methoden zur Einbindung von Drittanbieter-Bibliotheken
&lt;/h2>&lt;p>In der C++-Entwicklung war die Einführung externer Bibliotheken (Drittanbieter-Bibliotheken) schon immer eine hohe Hürde. Heutzutage sind jedoch vor allem die folgenden drei Ansätze Standard.&lt;/p>
&lt;h3 id="51-find_package-suche-nach-im-system-installierten-bibliotheken">5.1. find_package (Suche nach im System installierten Bibliotheken)
&lt;/h3>&lt;p>Dies ist die traditionellste Methode, um Bibliotheken zu finden und zu verlinken, die bereits auf dem System installiert sind (z. B. OpenSSL oder Zlib).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">find_package&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ZLIB&lt;/span> &lt;span class="s">REQUIRED&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ZLIB_FOUND&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">ZLIB::ZLIB&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="52-fetchcontent-herunterladen-aus-quelltexten-und-integration">5.2. FetchContent (Herunterladen aus Quelltexten und Integration)
&lt;/h3>&lt;p>Ein Modul, das in CMake 3.11 eingeführt wurde und ab 3.14 sehr leistungsstark geworden ist. Während des Builds wird der Quellcode direkt aus einem externen Git-Repository oder über eine URL heruntergeladen und gemeinsam als Teil des Projekts kompiliert. Da Abhängigkeiten zentral verwaltet werden können, ist die Reproduzierbarkeit auf verschiedenen Plattformen extrem hoch.&lt;/p>
&lt;p>Das folgende Beispiel zeigt die Einführung von GoogleTest mittels FetchContent.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">include&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">FetchContent&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">FetchContent_Declare&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">googletest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">GIT_REPOSITORY&lt;/span> &lt;span class="s">https://github.com/google/googletest.git&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">GIT_TAG&lt;/span> &lt;span class="s">v1.14.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Die Bibliothek in das Projekt aufnehmen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">FetchContent_MakeAvailable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">googletest&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Erstellen und Linken der ausführbaren Datei für Tests
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyTests&lt;/span> &lt;span class="s">test/main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyTests&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">gtest_main&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-integration-mit-vcpkg">5.3. Integration mit vcpkg
&lt;/h3>&lt;p>Durch die Verwendung von &lt;strong>vcpkg&lt;/strong>, einem von Microsoft geleiteten Paketmanager für C++, können Tausende von Bibliotheken problemlos eingeführt werden. vcpkg ist für eine nahtlose Integration in CMake konzipiert.&lt;/p>
&lt;p>Wenn CMake ausgeführt wird und die Toolchain-Datei für vcpkg angegeben wird, beginnt &lt;code>find_package&lt;/code> automatisch nach Bibliotheken innerhalb von vcpkg zu suchen.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE&lt;span class="o">=&lt;/span>/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Indem &lt;code>vcpkg.json&lt;/code> (Manifest-Modus) im Projektstamm abgelegt wird, lässt sich außerdem die Versionsverwaltung der erforderlichen Bibliotheken vollständig automatisieren.&lt;/p>
&lt;h2 id="6-plattformübergreifende-compiler-flags">6. Plattformübergreifende Compiler-Flags
&lt;/h2>&lt;p>Damit der Build in jeder der Umgebungen Windows (MSVC), Linux (GCC/Clang) und macOS (Apple Clang) erfolgreich ist, müssen compiler-spezifische Flags entsprechend gesetzt werden.&lt;/p>
&lt;p>Durch die Verwendung der &lt;strong>Generator Expressions (Generatorausdrücke)&lt;/strong> von CMake können Sie deklarativ bedingte Verzweigungen beschreiben, wie z. B.: „Wenn der Compiler MSVC ist, verwende dieses Flag, andernfalls verwende jenes Flag.“ Generatorausdrücke verwenden die Syntax &lt;code>$&amp;lt;...&amp;gt;&lt;/code> und werden während der Generierungsphase (Generate) des Build-Systems ausgewertet.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Beispiel zur Aktivierung der höchsten Warnstufe auf allen Plattformen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">PRIVATE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Für MSVC
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">$&amp;lt;CXX_COMPILER_ID:MSVC&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">:/W4&lt;/span> &lt;span class="s">/WX&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># Für GCC oder Clang
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">$&amp;lt;OR:$&amp;lt;CXX_COMPILER_ID:GNU&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">,&lt;/span>&lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">CXX_COMPILER_ID:Clang&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">,&lt;/span>&lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">CXX_COMPILER_ID:AppleClang&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;gt;:-Wall&lt;/span> &lt;span class="s">-Wextra&lt;/span> &lt;span class="s">-Wpedantic&lt;/span> &lt;span class="s">-Werror&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Mit dieser Methode wird verhindert, dass &lt;code>CMakeLists.txt&lt;/code> durch übermäßige Verwendung von bedingten Verzweigungen wie &lt;code>if(MSVC)&lt;/code> unleserlich wird, und es ermöglicht eine flexible Konfiguration für jedes Target.&lt;/p>
&lt;h2 id="7-einrichtung-der-testumgebung-ctest">7. Einrichtung der Testumgebung (CTest)
&lt;/h2>&lt;p>Bei der Qualitätssicherung in einer plattformübergreifenden Umgebung ist die Einführung von automatisierten Tests unerlässlich. CMake wird standardmäßig mit einem Test-Runner namens &lt;strong>CTest&lt;/strong> geliefert.&lt;/p>
&lt;p>Das Verfahren zur Integration von GoogleTest, das zuvor mit &lt;code>FetchContent&lt;/code> eingeführt wurde, in CTest ist wie folgt.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Testfunktionen aktivieren (nur einmal in der Root-CMakeLists.txt geschrieben)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">enable_testing&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyMathTests&lt;/span> &lt;span class="s">test/math_test.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyMathTests&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">gtest_main&lt;/span> &lt;span class="s">MyLib&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Bei CTest als Test registrieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">include&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">GoogleTest&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">gtest_discover_tests&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyMathTests&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Führen Sie nach dem Build einfach den Befehl &lt;code>ctest&lt;/code> im Build-Verzeichnis aus. Daraufhin werden alle Tests ausgeführt und die Ergebnisse gemeldet.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ctest --output-on-failure -C Release
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="8-theorie-der-build-systeme-und-mathematische-modelle">8. Theorie der Build-Systeme und mathematische Modelle
&lt;/h2>&lt;p>Wechseln wir die Perspektive ein wenig und betrachten die Effizienz von Build-Systemen und der parallelen Kompilierung in Großprojekten anhand eines mathematischen Modells.&lt;/p>
&lt;p>Die Verkürzung der Build-Zeit (Kompilierzeit) ist eine ständige Herausforderung bei der C++-Entwicklung. Durch das Aufteilen des Quellcodes und paralleles Kompilieren kann die Build-Zeit verkürzt werden. Diese Beschleunigung (Speedup) durch Parallelisierung wird durch das &lt;strong>Amdahlsche Gesetz (Amdahl&amp;rsquo;s Law)&lt;/strong> modelliert.&lt;/p>
&lt;p>Wenn der parallelisierbare Anteil eines Programms $P$ ist, der seriell (nicht parallelisierbar) auszuführende Anteil $1-P$ beträgt und die Anzahl der verwendeten Prozessoren $N$ ist, dann wird die theoretisch maximale Gesamtbeschleunigung $S(N)$ durch die folgende Formel ausgedrückt:&lt;/p>
$$ S(N) = \frac{1}{(1 - P) + \frac{P}{N}} $$
&lt;p>Im C++-Build-Prozess ist „die Kompilierung von jeder &lt;code>.cpp&lt;/code>-Datei zu &lt;code>.o&lt;/code> oder &lt;code>.obj&lt;/code>“ unabhängig und parallelisierbar (der $P$-Teil), aber „der abschließende Verknüpfungsprozess durch den Linker“ wird grundsätzlich seriell ausgeführt (der $1-P$-Teil).&lt;/p>
&lt;p>Daher wird, egal wie viele CPU-Kerne ($N \to \infty$) bereitgestellt werden, die maximale Beschleunigungsrate asymtotisch gegen die folgende Formel streben, solange der Engpass der Linkzeit besteht:&lt;/p>
$$ \lim_{N \to \infty} S(N) = \frac{1}{1 - P} $$
&lt;p>Was diese Formel besagt, ist: „Die bloße Erhöhung der Anzahl der CPU-Kerne hat Grenzen bei der Verkürzung der Build-Zeit.“ In Modern CMake ist die richtige Unterscheidung von &lt;code>PRIVATE&lt;/code> und &lt;code>INTERFACE&lt;/code> und die Minimierung von Header-Datei-Abhängigkeiten (z. B. durch die Verwendung von Vorwärtsdeklarationen (Forward Declarations)), um den Anteil von $P$ zu erhöhen und die neu zu kompilierenden Ziele bei inkrementellen Builds zu reduzieren, praktisch die effektivste Strategie zur Beschleunigung des Builds.&lt;/p>
&lt;p>Darüber hinaus ist zur Verkürzung der Linkzeit der Wechsel von statischen Bibliotheken (Static Libraries) zu freigegebenen Bibliotheken / DLLs (Shared Libraries) oder die Verwendung von schnellen Linkern wie LLD / Mold wichtig.&lt;/p>
&lt;p>In CMake lässt sich der Linker leicht wie folgt spezifizieren:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Konfiguration zur Verwendung des lld-Linkers in einer Clang/GCC-Umgebung
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">UNIX&lt;/span> &lt;span class="s">AND&lt;/span> &lt;span class="s">NOT&lt;/span> &lt;span class="s">APPLE&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">target_link_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s2">&amp;#34;-fuse-ld=lld&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="9-praxisbeispiel-einer-komplexen-verzeichnisstruktur">9. Praxisbeispiel einer komplexen Verzeichnisstruktur
&lt;/h2>&lt;p>In der tatsächlichen Anwendungsentwicklung ergibt sich eine Verzeichnisstruktur, in der viele Module kombiniert sind. Zum Schluss zeigen wir die ideale Verzeichnisstruktur eines mittelgroßen Projekts und die Beziehung zwischen übergeordneten und untergeordneten &lt;code>CMakeLists.txt&lt;/code>-Dateien.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">ProjectRoot/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── CMakeLists.txt (Root: Definition des gesamten Projekts)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── vcpkg.json (Definition der abhängigen Bibliotheken)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── external/ (Externe Module)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── include/ (Öffentliche Header)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── myapp/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── src/ (Quellcode und interne Build-Definitionen)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── main.cpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── math/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── Vector3.hpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── Vector3.cpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── network/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── NetworkManager.cpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── tests/ (Testcode)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── math_test.cpp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Die Root-&lt;code>CMakeLists.txt&lt;/code> führt nur Umgebungseinstellungen und globale Optionsdefinitionen durch, und Unterverzeichnisse werden mit &lt;code>add_subdirectory()&lt;/code> hinzugefügt.&lt;/p>
&lt;p>&lt;strong>Root &lt;code>CMakeLists.txt&lt;/code>&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ComplexApp&lt;/span> &lt;span class="s">LANGUAGES&lt;/span> &lt;span class="s">CXX&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Globale Einstellungen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD_REQUIRED&lt;/span> &lt;span class="s">ON&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Tests aktivieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">enable_testing&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Unterverzeichnisse hinzufügen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">src&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">tests&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>&lt;code>src/CMakeLists.txt&lt;/code>&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Jedes Modul hinzufügen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">math&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">network&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Die endgültige ausführbare Datei
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ComplexApp&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Module verlinken
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ComplexApp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">PRIVATE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">MathLib&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">NetworkLib&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Durch das Aufteilen der &lt;code>CMakeLists.txt&lt;/code> für jedes Verzeichnis auf diese Weise und deren Definition als Abhängigkeiten zwischen den Targets wird die Wiederverwendbarkeit von Modulen erhöht und die Parallelität des Builds ebenfalls verbessert. Dies ist der wahre Wert der „modularisierten Build-Umgebung“, die Modern CMake propagiert.&lt;/p>
&lt;h2 id="10-zusammenfassung">10. Zusammenfassung
&lt;/h2>&lt;p>Wir haben die Schritte zum Aufbau einer plattformübergreifenden C++-Build-Umgebung mit CMake erläutert.
Fassen wir die wichtigsten Punkte noch einmal zusammen:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Verständnis des Meta-Build-Systems&lt;/strong>: CMake ist ein Werkzeug zur Generierung von Build-Skripten.&lt;/li>
&lt;li>&lt;strong>Konsequente Anwendung von Modern CMake&lt;/strong>: Kapseln Sie Einstellungen &lt;strong>zielorientiert (Target-orientiert)&lt;/strong> mit &lt;code>add_executable&lt;/code>, &lt;code>target_link_libraries&lt;/code>, &lt;code>target_include_directories&lt;/code> usw., ohne globale Variablen zu verwenden.&lt;/li>
&lt;li>&lt;strong>Angemessene Festlegung des Gültigkeitsbereichs&lt;/strong>: Setzen Sie &lt;code>PUBLIC&lt;/code>, &lt;code>PRIVATE&lt;/code> und &lt;code>INTERFACE&lt;/code> korrekt ein, um die Ausbreitung von Abhängigkeiten zu kontrollieren.&lt;/li>
&lt;li>&lt;strong>Konsequente Out-of-Source-Builds&lt;/strong>: Führen Sie Builds im &lt;code>build/&lt;/code>-Verzeichnis aus, um den Quellcode-Baum nicht zu verschmutzen.&lt;/li>
&lt;li>&lt;strong>Integration von Drittanbietern&lt;/strong>: Nutzen Sie &lt;code>FetchContent&lt;/code> oder &lt;code>vcpkg&lt;/code>, um die Auflösung von abhängigen Bibliotheken zu automatisieren.&lt;/li>
&lt;li>&lt;strong>Nutzung von Generatorausdrücken (Generator Expressions)&lt;/strong>: Gleichen Sie Unterschiede in den Flags verschiedener Compiler elegant aus.&lt;/li>
&lt;li>&lt;strong>Mathematischer Ansatz&lt;/strong>: Berücksichtigen Sie das Amdahlsche Gesetz, um Abhängigkeiten zu reduzieren und die Effizienz des parallelen Kompilierens zu steigern.&lt;/li>
&lt;/ol>
&lt;p>Anfangs mag CMake schwer verständlich erscheinen, aber sobald Sie die Konzepte von Targets und Properties verstanden haben, können Sie eine geordnete Build-Umgebung aufrechterhalten, egal wie komplex oder riesig ein C++-Projekt ist. Bitte nutzen Sie diesen Artikel als Referenz und versuchen Sie, eine C++-Entwicklungsumgebung mit der neuesten Modern CMake-Schreibweise aufzubauen.&lt;/p></description></item></channel></rss>