Erste Schritte mit CMake

CMake ist eine Gruppe von Werkzeugen, mit denen sich Anwendungen erstellen, testen und paketieren lassen. Genau wie Qt ist es auf allen wichtigen Entwicklungsplattformen verfügbar. Es wird auch von verschiedenen IDEs unterstützt, darunter Qt Creator.

In diesem Abschnitt zeigen wir die grundlegendste Möglichkeit, Qt in einem CMake-Projekt zu verwenden. Zuerst erstellen wir eine einfache Konsolenanwendung. Dann erweitern wir das Projekt zu einer GUI-Anwendung, die Qt Widgets.

Wenn Sie wissen wollen, wie Sie ein bestehendes CMake-Projekt mit Qt erstellen, lesen Sie die Dokumentation über das Erstellen von Projekten mit CMake auf der Kommandozeile.

Um die Grundlagen für den Einstieg in CMake zu erlernen, besuchen Sie den Kurs Bauen mit Cmake: Erste Schritte mit CMake und Qt in der Qt Academy.

Erstellen einer C++-Konsolenanwendung

Ein CMake Projekt wird durch Dateien definiert, die in der CMake-Sprache geschrieben sind. Die Hauptdatei heißt CMakeLists.txt und befindet sich normalerweise im selben Verzeichnis wie die eigentlichen Programmquellen.

Hier ist eine typische CMakeLists.txt Datei für eine Konsolenanwendung, die in C++ mit Qt geschrieben wurde:

cmake_minimum_required(VERSION 3.16)

project(helloworld VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Core)
qt_standard_project_setup()

qt_add_executable(helloworld
    main.cpp
)

target_link_libraries(helloworld PRIVATE Qt6::Core)

Schauen wir uns den Inhalt an.

cmake_minimum_required(VERSION 3.16)

cmake_minimum_required() gibt die minimale CMake-Version an, die für die erfolgreiche Konfiguration des Projekts erforderlich ist. Siehe Unterstützte CMake-Versionen für die von Qt benötigte Mindestversion.

project(helloworld VERSION 1.0.0 LANGUAGES CXX)

project() legt einen Projektnamen und die Standard-Projektversion fest. Das Argument LANGUAGES teilt CMake mit, dass das Programm in C++ geschrieben ist.

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

Qt 6 erfordert einen Compiler, der C++ Version 17 oder neuer unterstützt. Wenn Sie dies durch Setzen der Variablen CMAKE_CXX_STANDARD, CMAKE_CXX_STANDARD_REQUIRED erzwingen, wird CMake einen Fehler ausgeben, wenn der Compiler zu alt ist.

find_package(Qt6 REQUIRED COMPONENTS Core)

Damit wird CMake angewiesen, nach Qt 6 zu suchen und das Modul Core zu importieren. Es macht keinen Sinn, weiterzumachen, wenn CMake das Modul nicht finden kann, also setzen wir das REQUIRED Flag, damit CMake in diesem Fall abbricht.

Wenn es erfolgreich ist, setzt das Modul einige CMake-Variablen, die in Modulvariablen dokumentiert sind. Außerdem importiert es das Ziel Qt6::Core, das wir weiter unten verwenden.

Damit find_package erfolgreich ist, muss CMake die Qt-Installation finden. Qt Creator und qt-cmake (qt-cmake.bat unter Windows) erledigen dies auf transparente Weise.

Wenn Sie CMake direkt verwenden, gibt es verschiedene Möglichkeiten, CMake über Qt zu informieren, aber der gängigste und empfohlene Ansatz ist, die CMake-Cache-Variable CMAKE_PREFIX_PATH so zu setzen, dass sie das Qt 6 Installationspräfix enthält. Dies ist ein Verzeichnis, in dem Qt-Binärdateien installiert sind. Unter Linux sieht es normalerweise so aus: "~/Qt/6.8.2/gcc_64" und Sie übergeben es auf der Kommandozeile als -DCMAKE_PREFIX_PATH=$HOME/Qt/6.8.2/gcc_64.

Hinweis: Beim Cross-Compiling (Kompilieren für eine andere Plattform als die, auf der Sie sich befinden, z. B. WebAssembly oder Android) und bei der Verwendung von vanilla cmake setzen Sie CMAKE_TOOLCHAIN_FILE anstelle von CMAKE_PREFIX_PATH. Unter Linux befindet sich die Toolchain-Datei (spezifisch für eine bestimmte Zielplattform) in der Regel unter einem ähnlichen Pfad wie diesem: "~/Qt/6.8.2/wasm_singlethread/lib/cmake/Qt6/qt.toolchain.cmake". Sie setzt die erforderlichen Variablen wie CMAKE_PREFIX_PATH, CMAKE_FIND_ROOT_PATH und QT_HOST_PATH.

qt_standard_project_setup()

Der Befehl qt_standard_project_setup setzt projektweite Standardwerte für eine typische Qt-Anwendung.

Unter anderem setzt dieser Befehl die Variable CMAKE_AUTOMOC auf ON, was CMake anweist, automatisch Regeln einzurichten, so dass Qt's Meta-Object Compiler (moc) bei Bedarf transparent aufgerufen wird.

Siehe qt_standard_project_setup's Referenz für Details.

qt_add_executable(helloworld
    main.cpp
)

qt_add_executable() teilt CMake mit, dass wir eine ausführbare Datei (also keine Bibliothek) namens helloworld als Ziel erstellen wollen. Es ist ein Wrapper um den eingebauten add_executable() Befehl und bietet zusätzliche Logik, um Dinge wie das Linken von Qt-Plugins in statischen Qt-Builds, plattformspezifische Anpassung von Bibliotheksnamen und so weiter automatisch zu behandeln.

Das Ziel sollte aus der C++-Quelldatei main.cpp erstellt werden.

Normalerweise werden hier keine Header-Dateien aufgelistet. Dies unterscheidet sich von qmake, wo Header-Dateien explizit aufgelistet werden müssen, damit sie von Meta-Object Compiler (moc) verarbeitet werden.

Für das Erstellen von Bibliotheken, siehe qt_add_library.

target_link_libraries(helloworld PRIVATE Qt6::Core)

Schließlich teilt target_link_libraries CMake mit, dass die ausführbare Datei helloworld von Qt Core verwendet, indem es das Qt6::Core Ziel referenziert, das durch den obigen find_package() Aufruf importiert wurde. Dies fügt nicht nur dem Linker die richtigen Argumente hinzu, sondern sorgt auch dafür, dass die richtigen Include-Verzeichnisse und Compiler-Definitionen an den C++-Compiler übergeben werden. Das Schlüsselwort PRIVATE ist für ein ausführbares Ziel nicht unbedingt erforderlich, aber es ist gute Praxis, es anzugeben. Wenn helloworld eine Bibliothek und keine ausführbare Datei ist, dann sollte entweder PRIVATE oder PUBLIC angegeben werden (PUBLIC, wenn die Bibliothek etwas aus Qt6::Core in ihren Headern erwähnt, ansonsten PRIVATE ).

Erstellen einer C++-GUI-Anwendung

Im letzten Abschnitt haben wir die CMakeLists.txt Datei für eine einfache Konsolenanwendung gezeigt. Wir werden nun eine GUI-Anwendung erstellen, die das Qt Widgets Modul verwendet.

Dies ist die vollständige Projektdatei:

cmake_minimum_required(VERSION 3.16)

project(helloworld VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_standard_project_setup()

qt_add_executable(helloworld
    mainwindow.ui
    mainwindow.cpp
    main.cpp
)

target_link_libraries(helloworld PRIVATE Qt6::Widgets)

set_target_properties(helloworld PROPERTIES
    WIN32_EXECUTABLE ON
    MACOSX_BUNDLE ON
)

Gehen wir die Änderungen durch, die wir vorgenommen haben.

find_package(Qt6 REQUIRED COMPONENTS Widgets)

Im Aufruf find_package ersetzen wir Core durch Widgets. Dadurch wird das Modul Qt6Widgets gefunden und die Ziele Qt6::Widgets bereitgestellt, mit denen wir später verlinken.

Beachten Sie, dass die Anwendung weiterhin gegen Qt6::Core linken wird, da Qt6::Widgets davon abhängt.

qt_standard_project_setup()

Zusätzlich zu CMAKE_AUTOMOC setzt qt_standard_project_setup die Variable CMAKE_AUTOUIC auf ON. Dadurch werden automatisch Regeln für den Aufruf von User Interface Compiler (uic) von Qt auf .ui Quelldateien erstellt.

qt_add_executable(helloworld
    mainwindow.ui
    mainwindow.cpp
    main.cpp
)

Wir fügen eine Qt Widgets Designer-Datei (mainwindow.ui) und die entsprechende C++-Quelldatei (mainwindow.cpp) zu den Quellen des Anwendungsziels hinzu.

In bestimmten Fällen, wie im folgenden Beispiel, wo die Include-Direktive einen relativen Pfad verwendet, kann qt_add_ui verwendet werden, um die ui_calculatorform.h Datei zu generieren, anstatt sich auf AUTOUIC zu verlassen.

Wann man qt_add_ui gegenüber AUTOUIC vorzieht

#include "src/files/ui_mainwindow.h"
qt_add_ui(calculatorform SOURCES mainwindow.ui INCLUDE_PREFIX src/files)

Wenn qt_add_ui verwendet wird, muss mainwindow.ui nicht an den Befehl qt_add_executable übergeben werden.

target_link_libraries(helloworld PRIVATE Qt6::Widgets)

Im Befehl target_link_libraries wird eine Verknüpfung mit Qt6::Widgets anstelle von Qt6::Core hergestellt.

set_target_properties(helloworld PROPERTIES
    WIN32_EXECUTABLE ON
    MACOSX_BUNDLE ON
)

Schließlich legen wir Eigenschaften für unser Anwendungsziel mit den folgenden Auswirkungen fest:

  • Verhindern Sie die Erstellung eines Konsolenfensters unter Windows.
  • Erstellen eines Anwendungsbündels unter macOS.

In der CMake-Dokumentation finden Sie weitere Informationen zu diesen Zieleigenschaften.

Projekte strukturieren

Projekte, die mehr als nur ein Ziel enthalten, profitieren von einer klaren Struktur der Projektdateien. Wir werden die Unterverzeichnis-Funktion von CMake verwenden.

Da wir planen, das Projekt um weitere Ziele zu erweitern, verschieben wir die Quelldateien der Anwendung in ein Unterverzeichnis und erstellen dort ein neues CMakeLists.txt.

<project root>
├── CMakeLists.txt
└── src
    └── app
        ├── CMakeLists.txt
        ├── main.cpp
        ├── mainwindow.cpp
        ├── mainwindow.h
        └── mainwindow.ui

Die oberste Ebene CMakeLists.txt enthält das allgemeine Projekt-Setup sowie die Aufrufe find_package und add_subdirectory:

cmake_minimum_required(VERSION 3.16)

project(helloworld VERSION 1.0.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Widgets)
qt_standard_project_setup()

add_subdirectory(src/app)

Variablen, die in dieser Datei gesetzt werden, sind in den Projektdateien der Unterverzeichnisse sichtbar.

Die Projektdatei der Anwendung src/app/CMakeLists.txt enthält das ausführbare Ziel:

qt_add_executable(helloworld
    mainwindow.ui
    mainwindow.cpp
    main.cpp
)

target_link_libraries(helloworld PRIVATE Qt6::Widgets)

set_target_properties(helloworld PROPERTIES
    WIN32_EXECUTABLE ON
    MACOSX_BUNDLE ON
)

Eine solche Struktur erleichtert es, dem Projekt weitere Ziele wie Bibliotheken oder Unit-Tests hinzuzufügen.

Hinweis: Fügen Sie Ihr Projekt-Build-Verzeichnis zur Liste der ausgeschlossenen Verzeichnisse jeder Antiviren-Anwendung hinzu, die auf Ihrem System läuft.

Erstellen von Bibliotheken

Wenn das Projekt wächst, möchten Sie vielleicht Teile Ihres Anwendungscodes in eine Bibliothek umwandeln, die von der Anwendung und möglicherweise von Unit-Tests verwendet wird. Dieser Abschnitt zeigt, wie Sie eine solche Bibliothek erstellen.

Unsere Anwendung enthält derzeit Geschäftslogik direkt in main.cpp. Wir extrahieren den Code in eine neue statische Bibliothek mit dem Namen businesslogic im Unterverzeichnis "src/businesslogic", wie im vorherigen Abschnitt beschrieben.

Der Einfachheit halber besteht die Bibliothek nur aus einer C++-Quelldatei und der entsprechenden Header-Datei, die von der Anwendung main.cpp eingebunden wird:

<project root>
├── CMakeLists.txt
└── src
    ├── app
    │   ├── ...
    │   └── main.cpp
    └── businesslogic
        ├── CMakeLists.txt
        ├── businesslogic.cpp
        └── businesslogic.h

Werfen wir einen Blick auf die Projektdatei der Bibliothek (src/businesslogic/CMakeLists.txt).

qt_add_library(businesslogic STATIC
    businesslogic.cpp
)
target_link_libraries(businesslogic PRIVATE Qt6::Core)
target_include_directories(businesslogic INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

Schauen wir uns den Inhalt an.

qt_add_library(businesslogic STATIC
    businesslogic.cpp
)

Der Befehl add_library erstellt die Bibliothek businesslogic. Später werden wir die Anwendung mit diesem Ziel verknüpfen lassen.

Das Schlüsselwort STATIC steht für eine statische Bibliothek. Wenn wir eine gemeinsam genutzte oder dynamische Bibliothek erstellen wollten, würden wir das Schlüsselwort SHARED verwenden.

target_link_libraries(businesslogic PRIVATE Qt6::Core)

Wir haben eine statische Bibliothek und müssen eigentlich keine anderen Bibliotheken linken. Da unsere Bibliothek jedoch Klassen aus QtCore verwendet, fügen wir eine Link-Abhängigkeit zu Qt6::Core hinzu. Dadurch werden die erforderlichen QtCore Include-Pfade und Präprozessor-Definitionen eingefügt.

target_include_directories(businesslogic INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

Die API der Bibliothek ist in der Header-Datei businesslogic/businesslogic.h definiert. Durch den Aufruf von target_include_directories stellen wir sicher, dass der absolute Pfad zum Verzeichnis businesslogic automatisch als Include-Pfad zu allen Zielen hinzugefügt wird, die unsere Bibliothek verwenden.

Dies befreit uns in main.cpp von der Verwendung relativer Pfade zum Auffinden von businesslogic.h. Stattdessen können wir einfach schreiben

#include <businesslogic.h>

Zuletzt müssen wir das Unterverzeichnis der Bibliothek zur obersten Projektdatei hinzufügen:

add_subdirectory(src/app)
add_subdirectory(src/businesslogic)

Bibliotheken verwenden

Um die im vorherigen Abschnitt erstellte Bibliothek zu verwenden, weisen wir CMake an, gegen sie zu linken:

target_link_libraries(helloworld PRIVATE
    businesslogic
    Qt6::Widgets
)

Dadurch wird sichergestellt, dass businesslogic.h gefunden wird, wenn main.cpp kompiliert wird. Außerdem wird die statische Bibliothek businesslogic Teil der ausführbaren Datei helloworld.

In der CMake-Sprache legt die Bibliothek businesslogic Verwendungsanforderungen (den Include-Pfad) fest, die jeder Verbraucher unserer Bibliothek (die Anwendung) erfüllen muss. Der Befehl target_link_libraries kümmert sich darum.

Hinzufügen von Ressourcen

Wir wollen einige Bilder in unserer Anwendung anzeigen, also fügen wir sie mit dem Qt Resource System hinzu.

qt_add_resources(helloworld imageresources
    PREFIX "/images"
    FILES logo.png splashscreen.png
)

Der Befehl qt_add_resources erstellt automatisch eine Qt-Ressource, die die referenzierten Bilder enthält. Vom C++-Quellcode aus können Sie auf die Bilder zugreifen, indem Sie das angegebene Ressourcenpräfix voranstellen:

logoLabel->setPixmap(QPixmap(":/images/logo.png"));

Der Befehl qt_add_resources nimmt als erstes Argument entweder einen Variablennamen oder einen Zielnamen an. Wir empfehlen, die zielbasierte Variante dieses Befehls zu verwenden, wie im obigen Beispiel gezeigt.

Hinzufügen von Übersetzungen

Übersetzungen von Strings in einem Qt-Projekt werden in .ts Dateien kodiert. Diese .ts Dateien werden in binäre .qm Dateien kompiliert, die dann von der Qt-Anwendung zur Laufzeit geladen werden. Siehe Internationalisierung mit Qt für weitere Details.

Dieser Abschnitt beschreibt, wie man eine deutsche und französische Übersetzung zur helloworld Anwendung hinzufügt.

Geben Sie beide Sprachen mit qt_standard_project_setup an:

qt_standard_project_setup(I18N_TRANSLATED_LANGUAGES de fr)

Dann rufen Sie qt_add_translations auf dem Ziel auf, das die .qm Dateien laden soll:

qt_add_translations(helloworld)

Bei der ersten Konfiguration erstellt dieser Befehl die Dateien helloworld_de.ts und helloworld_fr.ts im Quellverzeichnis des Projekts. Diese Dateien enthalten die übersetzten Zeichenketten und sollen unter Versionskontrolle gestellt werden.

Der Befehl erstellt auch Build-System-Regeln, um automatisch .qm Dateien aus den .ts Dateien zu generieren. Standardmäßig werden die .qm Dateien in eine Ressource eingebettet und sind unter dem Ressourcenpräfix "/i18n" zugänglich.

Um die Einträge in der Datei .ts zu aktualisieren, erstellen Sie das Ziel update_translations:

$ cmake --build . --target update_translations

Um die Erzeugung der .qm Dateien manuell auszulösen, erstellen Sie das release_translations Ziel:

$ cmake --build . --target release_translations

Für weitere Informationen darüber, wie man die Handhabung von .ts Dateien und die Einbettung in eine Ressource beeinflussen kann, siehe die qt_add_translations Dokumentation.

Der qt_add_translations-Befehl ist ein Komfort-Wrapper. Für eine feinere Kontrolle, wie .ts und .qm Dateien behandelt werden, verwenden Sie die zugrunde liegenden Befehle qt_add_lupdate und qt_add_lrelease.

Weitere Lektüre

Die offizielle CMake-Dokumentation ist eine unschätzbare Quelle für die Arbeit mit CMake.

Das offizielle CMake-Tutorial behandelt allgemeine Aufgaben des Build-Systems.

Das Buch Professional CMake: A Practical Guide bietet eine hervorragende Einführung in die wichtigsten CMake-Funktionen.

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.