
Einführung
Dieser Artikel beschreibt die Verwendung des CMake-Build-Systems, das in einer Vielzahl von C / C ++ - Projekten verwendet wird. Es wird dringend empfohlen, den ersten Teil des Handbuchs zu lesen, um Missverständnisse der Syntax der CMake-Sprache zu vermeiden, die im gesamten Artikel explizit aufgeführt ist.
CMake-Start
Im Folgenden finden Sie Beispiele für die Verwendung der CMake-Sprache, die Sie üben sollten. Experimentieren Sie mit dem Quellcode, indem Sie vorhandene Befehle ändern und neue hinzufügen. Installieren Sie CMake von der offiziellen Website , um diese Beispiele auszuführen.
Arbeitsprinzip
Das CMake-Build-System ist ein Wrapper über andere plattformabhängige Dienstprogramme (z. B. Ninja oder Make ). Somit nimmt der Montageprozess selbst, egal wie paradox dies klingen mag, nicht direkt teil.
Das CMake-Build-System akzeptiert eine CMakeLists.txt
Datei mit einer Beschreibung der Build-Regeln in der formalen CMake-Sprache und generiert dann Zwischen- und native Build-Dateien in demselben Verzeichnis, das auf Ihrer Plattform akzeptiert wird.
Generierte Dateien enthalten bestimmte Namen von Systemdienstprogrammen, Verzeichnissen und Compilern, während CMake-Befehle nur das abstrakte Konzept des Compilers verwenden und nicht an plattformabhängige Tools gebunden sind, die sich auf verschiedenen Betriebssystemen stark unterscheiden.
Überprüfen der CMake-Version
Der Befehl cmake_minimum_required
überprüft die laufende Version von CMake: Wenn sie unter dem angegebenen Minimum liegt, wird CMake mit einem schwerwiegenden Fehler beendet. Ein Beispiel, das die typische Verwendung dieses Befehls am Anfang einer CMake-Datei demonstriert:
Wie in den Kommentaren erwähnt, setzt der Befehl cmake_minimum_required
alle Kompatibilitätsflags (siehe cmake_policy
). Einige Entwickler legen absichtlich eine niedrige Version von CMake fest und passen die Funktionalität dann manuell an. Auf diese Weise können Sie gleichzeitig die alten Versionen von CMake unterstützen und an einigen Stellen neue Funktionen nutzen.
Zu Beginn jeder CMakeLists.txt
die Projektmerkmale mit dem Projektteam angeben, um ein besseres Design mit integrierten Umgebungen und anderen Entwicklungstools zu erzielen.
Es ist erwähnenswert, dass die Standardsprachen C CXX
sind, wenn das Schlüsselwort LANGUAGES
weggelassen wird. Sie können die Angabe von Sprachen auch deaktivieren, indem Sie das Schlüsselwort NONE
als Liste von Sprachen schreiben oder einfach eine leere Liste hinterlassen.
Ausführen von Skriptdateien
Der Befehl include
ersetzt die Zeile seines Aufrufs durch den Code der angegebenen Datei und verhält sich ähnlich wie der Befehl include
des C / C ++ - Präprozessors include
. In diesem Beispiel wird die Skriptdatei MyCMakeScript.cmake
beschriebenen Befehl ausgeführt:
message("'TEST_VARIABLE' is equal to [${TEST_VARIABLE}]")
In diesem Beispiel benachrichtigt die erste Nachricht, dass die Variable TEST_VARIABLE
noch nicht definiert wurde. Wenn das Skript MyCMakeScript.cmake
diese Variable MyCMakeScript.cmake
, informiert die zweite Nachricht bereits über den neuen Wert der MyCMakeScript.cmake
. Daher erstellt die im Befehl include
enthaltene Skriptdatei keinen eigenen Bereich, der in den Kommentaren zum vorherigen Artikel erwähnt wurde .
Zusammenstellung ausführbarer Dateien
Der Befehl add_executable
kompiliert die ausführbare Datei mit dem angegebenen Namen aus der add_executable
. Es ist wichtig zu beachten, dass der endgültige Dateiname von der Zielplattform abhängt (z. B. <ExecutableName>.exe
oder nur <ExecutableName>
). Ein typisches Beispiel für das Aufrufen dieses Befehls:
Bibliothekszusammenstellung
Der Befehl add_library
kompiliert die Bibliothek mit der angegebenen Ansicht und dem angegebenen Namen aus der Quelle. Es ist wichtig zu beachten, dass der endgültige Bibliotheksname von der Zielplattform abhängt (z. B. lib<LibraryName>.a
oder <LibraryName>.lib
). Ein typisches Beispiel für das Aufrufen dieses Befehls:
- Statische Bibliotheken werden durch das Schlüsselwort
STATIC
als zweites Argument definiert und sind Archive von Objektdateien, die ausführbaren Dateien und anderen Bibliotheken zur Kompilierungszeit zugeordnet sind. - Dynamische Bibliotheken werden durch das Schlüsselwort
SHARED
als zweites Argument angegeben und sind SHARED
die vom Betriebssystem während der Programmausführung geladen werden. - Modulare Bibliotheken werden durch das Schlüsselwort
MODULE
als zweites Argument definiert und sind MODULE
die mithilfe der Ausführungstechnik von der ausführbaren Datei selbst geladen werden. - Objektbibliotheken werden durch das Schlüsselwort
OBJECT
als zweites Argument definiert und sind eine Reihe von Objektdateien, die ausführbaren Dateien und anderen Bibliotheken zur Kompilierungszeit zugeordnet sind.
Quelle zum Ziel hinzufügen
Es gibt Fälle, in denen mehrere Quelldateien zum Ziel hinzugefügt werden müssen. Zu diesem target_sources
Befehl target_sources
, mit dem dem Ziel viele Male Quellen target_sources
können.
Das erste Argument für den Befehl target_sources
ist der Name des Ziels, das zuvor mit den add_executable
add_library
oder add_executable
wurde. Die nachfolgenden Argumente sind eine Liste der hinzuzufügenden Quelldateien.
Wiederholte Aufrufe des target_sources
fügen die Quelldateien dem Ziel in der Reihenfolge hinzu, in der sie aufgerufen wurden, sodass die beiden unteren Codeblöcke funktional äquivalent sind:
Generierte Dateien
Der Speicherort der Ausgabedateien, die mit den add_library
add_executable
und add_library
generiert wurden, wird erst in der Generierungsphase festgelegt. Diese Regel kann jedoch mit mehreren Variablen geändert werden, die den endgültigen Speicherort der Binärdateien bestimmen:
Ausführbare Dateien gelten immer als Ausführungsziele, statische Bibliotheken als Archivierungsziele und modulare Bibliotheken als Bibliotheksziele. Bei "Nicht-DLL" -Plattformen werden dynamische Bibliotheken als Bibliotheksziele und bei "DLL-Plattformen" als Ausführungsziele betrachtet. Solche Variablen werden für Objektbibliotheken nicht bereitgestellt, da diese Art von Bibliotheken im Darm des CMakeFiles
Verzeichnisses CMakeFiles
.
Es ist wichtig zu beachten, dass alle Windows-basierten Plattformen, einschließlich Cygwin, als "DLL-Plattformen" betrachtet werden.
Bibliothekslayout
Der Befehl target_link_libraries
Bibliothek oder ausführbare Datei mit anderen bereitgestellten Bibliotheken. Das erste Argument für diesen Befehl ist der Name des Ziels, das durch die add_library
add_executable
oder add_library
generiert wurde, und die nachfolgenden Argumente sind die Namen der Bibliotheksziele oder die vollständigen Pfade zu den Bibliotheken. Ein Beispiel:
Es ist anzumerken, dass modulare Bibliotheken nicht mit ausführbaren Dateien oder anderen Bibliotheken verknüpft werden können, da sie ausschließlich zum Laden durch Ausführungstechniken bestimmt sind.
Mit Zielen arbeiten
Wie in den Kommentaren erwähnt, unterliegen Ziele in CMake ebenfalls einer manuellen Manipulation, sind jedoch sehr begrenzt.
Es ist möglich, die Eigenschaften von Zielen zu steuern, mit denen der Projektzusammenstellungsprozess festgelegt werden soll. Der Befehl get_target_property
Wert der get_target_property
angegebene Variable. In diesem Beispiel wird der Wert der C_STANDARD
Eigenschaft des C_STANDARD
Ziels auf dem Bildschirm angezeigt:
Der Befehl set_target_properties
setzt die angegebenen set_target_properties
auf die angegebenen Werte. Dieser Befehl akzeptiert eine Liste von Zielen, für die Eigenschaftswerte festgelegt werden, und anschließend das Schlüsselwort PROPERTIES
, gefolgt von einer Liste der Form < > < >
:
Im obigen Beispiel werden die Eigenschaften der MyTarget
Ziele festgelegt, die sich auf den Kompilierungsprozess auswirken: Beim Kompilieren des MyTarget
Ziels MyTarget
Compiler für CMake den C11-Standard verwenden. Alle bekannten Namen von Zieleigenschaften werden auf dieser Seite aufgelistet.
Es ist auch möglich, zuvor definierte Ziele mit dem Konstrukt if(TARGET <TargetName>)
zu überprüfen:
Unterprojekte hinzufügen
Der Befehl add_subdirectory
fordert CMake auf, die angegebene Unterprojektdatei sofort zu verarbeiten. Das folgende Beispiel zeigt die Anwendung des beschriebenen Mechanismus:
In diesem Beispiel ist das erste Argument für den Befehl add_subdirectory
Unterprojekt add_subdirectory
Das zweite Argument ist optional und informiert CMake über den Ordner, der für die generierten Dateien des enthaltenen Unterprojekts vorgesehen ist (z. B. CMakeCache.txt
und cmake_install.cmake
).
Es ist zu beachten, dass alle Variablen aus dem übergeordneten Bereich vom hinzugefügten Verzeichnis geerbt werden und alle in diesem Verzeichnis definierten und neu definierten Variablen nur für dieses sichtbar sind (wenn das Schlüsselwort PARENT_SCOPE
nicht durch das Befehlsargument set
angegeben wurde). Diese Funktion wurde in den Kommentaren zum vorherigen Artikel erwähnt .
Paketsuche
Der Befehl find_package
findet und lädt die Einstellungen eines externen Projekts. In den meisten Fällen wird es für die spätere Verknüpfung externer Bibliotheken wie Boost und GSL verwendet . In diesem Beispiel wird der beschriebene Befehl aufgerufen , um nach der GSL- Bibliothek zu suchen und dann zu verknüpfen:
Im obigen Beispiel akzeptiert der Befehl find_package
den Namen des Pakets als erstes Argument und dann die erforderliche Version. Die Option REQUIRED
erfordert das Drucken eines schwerwiegenden Fehlers und das Beenden von CMake, wenn das erforderliche Paket nicht gefunden wird. Das Gegenteil ist die QUIET
Option, bei der CMake seine Arbeit fortsetzen muss, auch wenn das Paket nicht gefunden wurde.
Als Nächstes wird die MyExecutable
mit dem Befehl target_link_libraries
mithilfe der Variablen GSL::gsl
mit der GSL-Bibliothek GSL::gsl
, die den Speicherort der bereits kompilierten GSL kapselt.
Am Ende wird der Befehl target_include_directories
, der den Compiler über den Speicherort der GSL-Bibliotheksheaderdateien informiert. Bitte beachten Sie, dass die Variable GSL_INCLUDE_DIRS
verwendet wird, GSL_INCLUDE_DIRS
von mir beschriebenen Header zu GSL_INCLUDE_DIRS
(dies ist ein Beispiel für importierte Paketeinstellungen).
Sie möchten wahrscheinlich das Ergebnis einer QUIET
überprüfen, wenn Sie die Option QUIET
angegeben haben. Dies kann durch Überprüfen der <PackageName>_FOUND
, die nach Abschluss des find_package
automatisch ermittelt wird. Wenn Sie beispielsweise erfolgreich GSL-Einstellungen in Ihr Projekt importieren, wird die Variable GSL_FOUND
wahr.
Im Allgemeinen hat der Befehl find_package
zwei find_package
des Starts: modular und Konfiguration. Im obigen Beispiel wurde eine modulare Form angewendet. Dies bedeutet, dass CMake beim Find<PackageName>.cmake
des CMAKE_MODULE_PATH
Verzeichnis CMAKE_MODULE_PATH
nach einer Skriptdatei der Form Find<PackageName>.cmake
CMAKE_MODULE_PATH
, diese dann startet und alle erforderlichen Einstellungen importiert (in diesem Fall hat CMake die Standarddatei FindGSL.cmake
gestartet).
Möglichkeiten, Header einzuschließen
Sie können den Compiler mit zwei Befehlen über den Speicherort der enthaltenen Header informieren: include_directories
und target_include_directories
. Sie entscheiden, welche Sie verwenden möchten. Es lohnt sich jedoch, einige Unterschiede zwischen ihnen zu berücksichtigen (die Idee wird in den Kommentaren vorgeschlagen ).
Der Befehl include_directories
wirkt sich auf den Bereich des Verzeichnisses aus. Dies bedeutet, dass alle durch diesen Befehl angegebenen Header-Verzeichnisse für alle Zwecke der aktuellen CMakeLists.txt
sowie für verarbeitete Teilprojekte verwendet werden (siehe add_subdirectory
).
Der Befehl target_include_directories
wirkt sich target_include_directories
auf das im ersten Argument angegebene Ziel aus und nicht auf andere Ziele. Das folgende Beispiel zeigt den Unterschied zwischen den beiden Befehlen:
add_executable(RequestGenerator RequestGenerator.c) add_executable(ResponseGenerator ResponseGenerator.c)
In den Kommentaren wird erwähnt, dass in modernen Projekten die Verwendung der link_libraries
include_directories
und link_libraries
unerwünscht ist. Eine Alternative sind die target_link_libraries
target_include_directories
und target_link_libraries
, die nur auf bestimmte Ziele und nicht auf den gesamten aktuellen Bereich target_link_libraries
.
Projektinstallation
Der Befehl install
generiert Installationsregeln für Ihr Projekt. Dieser Befehl kann mit Zielen, Dateien, Ordnern und mehr arbeiten. Betrachten Sie zunächst das Setzen von Zielen.
Um Ziele festzulegen, müssen Sie das Schlüsselwort TARGETS
als erstes Argument der beschriebenen Funktion übergeben, gefolgt von einer Liste der festzulegenden Ziele und dem Schlüsselwort DESTINATION
mit dem Speicherort des Verzeichnisses, in dem die angegebenen Ziele festgelegt werden. Dieses Beispiel zeigt eine typische Zielsetzung:
Der Prozess zum Beschreiben der Installation von Dateien ist ähnlich, außer dass TARGETS
anstelle des Schlüsselworts TARGETS
angeben müssen. Ein Beispiel für die Installation von Dateien:
Der Prozess zum Beschreiben der Installation von Ordnern ist ähnlich, außer dass Sie DIRECTORY
anstelle des Schlüsselworts FILES
angeben müssen. Es ist wichtig zu beachten, dass während der Installation der gesamte Inhalt des Ordners kopiert wird und nicht nur sein Name. Ein Beispiel für die Installation von Ordnern lautet wie folgt:
Nachdem Sie die CMake-Verarbeitung aller Ihrer Dateien abgeschlossen haben, können Sie alle beschriebenen Objekte mit dem sudo checkinstall
installieren (wenn CMake ein Makefile
generiert), oder Sie können diese Aktion mit der integrierten Entwicklungsumgebung ausführen, die CMake unterstützt.
Visuelles Beispiel des Projekts
Dieses Handbuch wäre nicht vollständig, ohne ein reales Beispiel für die Verwendung des CMake-Build-Systems zu demonstrieren. Betrachten Sie ein einfaches Projektdiagramm mit CMake als einzigem Build-System:
+ MyProject - CMakeLists.txt - Defines.h - StartProgram.c + core - CMakeLists.txt - Core.h - ProcessInvoker.c - SystemManager.c
Die CMakeLists.txt
Datei CMakeLists.txt
beschreibt die Kompilierung des gesamten Programms: Zuerst wird der Befehl add_executable
, der die ausführbare Datei kompiliert, dann der Befehl add_subdirectory
, der die Verarbeitung des Teilprojekts anregt, und schließlich wird die ausführbare Datei mit der kompilierten Bibliothek verknüpft:
Die Datei core/CMakeLists.txt
wird von der core/CMakeLists.txt
aufgerufen und kompiliert die statische Bibliothek MyProgramCore
die für die Verknüpfung mit der ausführbaren Datei vorgesehen ist:
Nach einer Reihe von cmake . && make && sudo checkinstall
Befehlen cmake . && make && sudo checkinstall
cmake . && make && sudo checkinstall
CMake Build System wird erfolgreich abgeschlossen. Der erste Befehl beginnt mit der Verarbeitung der Datei CMakeLists.txt
im Stammverzeichnis des Projekts, der zweite Befehl kompiliert schließlich die erforderlichen Binärdateien und der dritte Befehl installiert die kompilierte MyProgram
im System.
Fazit
Jetzt können Sie Ihre eigenen CMake-Dateien schreiben und die CMake-Dateien anderer Personen verstehen. Weitere Informationen zu anderen Mechanismen finden Sie auf der offiziellen Website .
Der nächste Artikel in diesem Handbuch konzentriert sich auf das Testen und Erstellen von Paketen mit CMake und wird in einer Woche veröffentlicht. Bis bald!