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.