Es ist bekanntermaßen schwierig, als Anfänger nützliche Informationen über CMake zu erhalten. Bisher habe ich einige Tutorials zum Einrichten eines sehr einfachen Projekts gesehen. Keines davon erklärt jedoch die Gründe für alles , was in ihnen gezeigt wird, und lässt immer viele Löcher zu füllen.
Was bedeutet Aufruf CMake auf einem CMakeLists bedeuten ? Soll es einmal pro Build-Baum aufgerufen werden oder was? Wie verwende ich unterschiedliche Einstellungen für jeden Build, wenn alle dieselbe CMakeLists.txt-Datei aus derselben Quelle verwenden? Warum benötigt jedes Unterverzeichnis eine eigene CMakeLists-Datei? Wäre es sinnvoll, CMake in einer anderen CMakeLists.txt als der im Stammverzeichnis des Projekts zu verwenden? Wenn ja, in welchen Fällen? Was ist der Unterschied zwischen der Angabe, wie eine ausführbare Datei oder Bibliothek aus der CMakeLists-Datei in ihrem eigenen Unterverzeichnis erstellt wird, und der Angabe in der CMakeLists-Datei im Stammverzeichnis aller Quellen? Kann ich ein Projekt für Eclipse und ein anderes für Visual Studio erstellen und dabei die -G
Option beim Aufrufen von CMake ändern ? Wird es überhaupt so verwendet?
Keines der Tutorials, Dokumentationsseiten oder Fragen / Antworten, die ich bisher gesehen habe, gibt nützliche Einblicke in das Verständnis der Verwendung von CMake. Die Beispiele sind einfach nicht gründlich. Egal welche Tutorials ich lese, ich habe das Gefühl, dass mir etwas Wichtiges fehlt.
Es gibt viele Fragen von CMake-Neulingen wie mir, die dies nicht explizit stellen, aber die Tatsache deutlich machen, dass wir als Neulinge keine Ahnung haben, wie wir mit CMake umgehen sollen oder was wir daraus machen sollen.
Antworten:
Wofür ist CMake?
Laut Wikipedia:
Mit CMake müssen Sie keine separaten Einstellungen mehr für Ihre Compiler- / Build-Umgebung vornehmen. Sie haben eine Konfiguration, die in vielen Umgebungen funktioniert .
CMake kann aus denselben Dateien eine Microsoft Visual Studio-Lösung, ein Eclipse-Projekt oder ein Makefile-Labyrinth generieren, ohne etwas daran zu ändern.
Bei einer Reihe von Verzeichnissen mit Code verwaltet CMake alle Abhängigkeiten, Erstellungsaufträge und anderen Aufgaben, die Ihr Projekt ausführen muss, bevor es kompiliert werden kann. Es kompiliert eigentlich nichts. Um CMake verwenden zu können, müssen Sie (unter Verwendung der Konfigurationsdateien CMakeLists.txt) mitteilen, welche ausführbaren Dateien Sie kompilieren müssen, mit welchen Bibliotheken sie verknüpft sind, welche Verzeichnisse sich in Ihrem Projekt befinden und welche darin enthalten sind sowie Details wie Flags oder alles andere, was Sie brauchen (CMake ist ziemlich mächtig).
Wenn dies korrekt eingerichtet ist, verwenden Sie CMake, um alle Dateien zu erstellen, die Ihre "native Build-Umgebung" Ihrer Wahl für ihre Arbeit benötigt. Unter Linux bedeutet dies standardmäßig Makefiles. Sobald Sie CMake ausführen, werden eine Reihe von Dateien für den eigenen Gebrauch sowie einige
Makefile
s erstellt. Alles, was Sie danach tun müssen, ist, jedes Mal, wenn Sie Ihren Code bearbeitet haben, "make" aus dem Stammordner in die Konsole einzugeben, und bam wird eine kompilierte und verknüpfte ausführbare Datei erstellt.Wie funktioniert CMake? Was tut es?
Hier ist ein Beispiel für ein Projekt-Setup, das ich durchgehend verwenden werde:
Der Inhalt jeder Datei wird später angezeigt und erläutert.
CMake richtet Ihr Projekt gemäß dem Stammverzeichnis
CMakeLists.txt
Ihres Projekts ein und zwar in dem Verzeichnis,cmake
aus dem Sie es in der Konsole ausgeführt haben. Wenn Sie dies aus einem Ordner heraus tun, der nicht das Stammverzeichnis Ihres Projekts ist, wird ein so genannter Out-of-Source- Build erstellt. Dies bedeutet, dass Dateien, die während der Kompilierung erstellt wurden (obj-Dateien, lib-Dateien, ausführbare Dateien, wie Sie wissen), in diesem Ordner abgelegt werden , vom eigentlichen Code getrennt gehalten. Es hilft, Unordnung zu reduzieren und wird auch aus anderen Gründen bevorzugt, auf die ich nicht eingehen werde.Ich weiß nicht, was passiert, wenn Sie
cmake
auf einer anderen als der Wurzel ausführenCMakeLists.txt
.In diesem Beispiel muss ich, da alles in den
build/
Ordner verschoben werden soll, zuerst dorthin navigieren und dann CMake das Verzeichnis übergeben, in dem sich das StammverzeichnisCMakeLists.txt
befindet.Standardmäßig wird hiermit Makefiles wie gesagt eingerichtet. So sollte der Build-Ordner jetzt aussehen:
Was sind all diese Dateien? Das einzige, worüber Sie sich Sorgen machen müssen, sind das Makefile und die Projektordner .
Beachten Sie die Ordner
src/
undlib/
. Diese wurden erstellt, weilsimple/CMakeLists.txt
sie mit dem Befehl auf sie verweisenadd_subdirectory(<folder>)
. Dieser Befehl weist CMake an, in diesem Ordner nach einer anderenCMakeLists.txt
Datei zu suchen und dieses Skript auszuführen. Daher muss in jedem auf diese Weise hinzugefügten Unterverzeichnis eineCMakeLists.txt
Datei enthalten sein. In diesem Projekt wirdsimple/src/CMakeLists.txt
beschrieben, wie die eigentliche ausführbare Datei erstellt wird undsimple/lib/CMakeLists.txt
wie die Bibliothek erstellt wird. Jedes Ziel, das einCMakeLists.txt
beschreibt, wird standardmäßig in seinem Unterverzeichnis innerhalb des Build-Baums platziert. Also nach einer kurzenIn der Konsole von
build/
werden einige Dateien hinzugefügt:Das Projekt wird erstellt und die ausführbare Datei kann ausgeführt werden. Was tun Sie, wenn die ausführbaren Dateien in einem bestimmten Ordner abgelegt werden sollen? Legen Sie die entsprechende CMake-Variable fest oder ändern Sie die Eigenschaften eines bestimmten Ziels . Mehr zu CMake-Variablen später.
Wie sage ich CMake, wie ich mein Projekt erstellen soll?
Hier ist der erläuterte Inhalt jeder Datei im Quellverzeichnis:
simple/CMakeLists.txt
::Die minimal erforderliche Version sollte immer festgelegt werden, entsprechend der Warnung, die CMake auslöst, wenn Sie dies nicht tun. Verwenden Sie eine beliebige Version von CMake.
Der Name Ihres Projekts kann später verwendet werden und weist darauf hin, dass Sie mehr als ein Projekt aus denselben CMake-Dateien verwalten können. Ich werde mich jedoch nicht damit befassen.
Wie bereits erwähnt, wird
add_subdirectory()
dem Projekt ein Ordner hinzugefügt. Dies bedeutet, dass CMake erwartet, dass es einen Ordner enthältCMakeLists.txt
, den es dann ausführt, bevor es fortfährt. Übrigens, wenn Sie eine CMake-Funktion definiert haben, können Sie sie aus anderenCMakeLists.txt
s in Unterverzeichnissen verwenden, aber Sie müssen sie definieren, bevor Sie sie verwenden, sonstadd_subdirectory()
wird sie nicht gefunden. CMake ist jedoch schlauer in Bezug auf Bibliotheken, sodass dies wahrscheinlich das einzige Mal ist, dass Sie auf diese Art von Problem stoßen.simple/lib/CMakeLists.txt
::Um Ihre eigene Bibliothek zu erstellen, geben Sie ihr einen Namen und listen dann alle Dateien auf, aus denen sie erstellt wurde. Einfach. Wenn
foo.cxx
zum Kompilieren eine andere Datei benötigt wird , schreiben Sie stattdessenadd_library(TestLib TestLib.cxx foo.cxx)
. Dies funktioniert beispielsweise auch für Dateien in anderen Verzeichnissenadd_library(TestLib TestLib.cxx ${CMAKE_SOURCE_DIR}/foo.cxx)
. Mehr zur Variablen CMAKE_SOURCE_DIR später.Sie können damit auch angeben, dass Sie eine gemeinsam genutzte Bibliothek möchten. Das Beispiel :
add_library(TestLib SHARED TestLib.cxx)
. Fürchte dich nicht, hier beginnt CMake dein Leben zu erleichtern. Unabhängig davon, ob es freigegeben ist oder nicht, müssen Sie nur noch den Namen verwenden, den Sie hier angegeben haben, um eine auf diese Weise erstellte Bibliothek zu verwenden. Der Name dieser Bibliothek lautet jetzt TestLib, und Sie können von überall im Projekt darauf verweisen . CMake wird es finden.Gibt es eine bessere Möglichkeit, Abhängigkeiten aufzulisten? Auf jeden Fall ja . Weitere Informationen hierzu finden Sie weiter unten.
simple/lib/TestLib.cxx
::simple/lib/TestLib.h
::simple/src/CMakeLists.txt
::Der Befehl
add_executable()
funktioniert genauso wieadd_library()
, außer dass stattdessen eine ausführbare Datei generiert wird. Diese ausführbare Datei kann jetzt als Ziel für Dinge wie referenziert werdentarget_link_libraries()
. Da tutorial.cxx Code aus der TestLib-Bibliothek verwendet, weisen Sie CMake wie gezeigt darauf hin.Ebenso müssen alle .h-Dateien #, die von Quellen in
add_executable()
diesem Verzeichnis enthalten sind, die sich nicht im selben Verzeichnis wie die Quelle befinden, irgendwie hinzugefügt werden. Wenn dertarget_include_directories()
Befehllib/TestLib.h
nicht vorhanden ist, wird er beim Kompilieren des Lernprogramms nicht gefunden, sodass der gesamtelib/
Ordner zu den Include-Verzeichnissen hinzugefügt wird, in denen nach #includes gesucht werden soll. Möglicherweise wird auch der Befehlinclude_directories()
angezeigt, der sich auf ähnliche Weise verhält, mit der Ausnahme, dass Sie kein Ziel angeben müssen, da es für alle ausführbaren Dateien vollständig global festgelegt wird. Ich werde CMAKE_SOURCE_DIR später noch einmal erklären.simple/src/tutorial.cxx
::Beachten Sie, wie die Datei "TestLib.h" enthalten ist. Sie müssen nicht den vollständigen Pfad angeben: CMake kümmert sich dank all dem um alles hinter den Kulissen
target_include_directories()
.Technisch gesehen, in einem einfachen Quellbaum wie das Sie ohne die tun können ,
CMakeLists.txt
s unterlib/
undsrc/
und das Hinzufügen nur so etwas wieadd_executable(Tutorial src/tutorial.cxx)
zusimple/CMakeLists.txt
. Es liegt an Ihnen und den Anforderungen Ihres Projekts.Was sollte ich noch wissen, um CMake richtig zu verwenden?
(AKA-Themen, die für Ihr Verständnis relevant sind)
Pakete finden und verwenden : Die Antwort auf diese Frage erklärt es besser als ich es jemals könnte.
Deklarieren von Variablen und Funktionen, Verwenden des Kontrollflusses usw . : In diesem Lernprogramm werden die Grundlagen des Angebots von CMake erläutert und eine gute Einführung im Allgemeinen gegeben.
CMake-Variablen : Es gibt viele. Im Folgenden finden Sie einen Crash-Kurs, der Sie auf den richtigen Weg bringt. Das CMake-Wiki ist ein guter Ort, um detailliertere Informationen zu Variablen und angeblich auch zu anderen Dingen zu erhalten.
Möglicherweise möchten Sie einige Variablen bearbeiten, ohne den Build-Baum neu zu erstellen. Verwenden Sie dazu ccmake (es bearbeitet die
CMakeCache.txt
Datei). Denkenc
Sie daran, eine Konfiguration vorzunehmen, wenn Sie mit den Änderungen fertig sind, und danng
Makefiles mit der aktualisierten Konfiguration zu aktivieren.Lesen Sie das zuvor erwähnte Tutorial , um mehr über die Verwendung von Variablen zu erfahren, aber kurz gesagt:
set(<variable name> value)
um eine Variable zu ändern oder zu erstellen.${<variable name>}
um es zu benutzen.CMAKE_SOURCE_DIR
: Das Stammverzeichnis der Quelle. Im vorherigen Beispiel ist dies immer gleich/simple
CMAKE_BINARY_DIR
: Das Stammverzeichnis des Builds. Im vorherigen Beispiel ist dies gleichsimple/build/
, aber wenn Siecmake simple/
von einem Ordner wie z. B. ausgeführt werdenfoo/bar/etc/
, werden alle Verweise aufCMAKE_BINARY_DIR
in diesem Build-Baum/foo/bar/etc
.CMAKE_CURRENT_SOURCE_DIR
: Das Verzeichnis, in dem sich der StromCMakeLists.txt
befindet. Dies bedeutet, dass er sich im Laufe der Zeit ändert: Drucken aussimple/CMakeLists.txt
Erträgen/simple
und Drucken aussimple/src/CMakeLists.txt
Erträgen/simple/src
.CMAKE_CURRENT_BINARY_DIR
: Du hast die Idee. Dieser Pfad hängt nicht nur vom Ordner ab, in dem sich der Build befindet, sondern auch vomCMakeLists.txt
Speicherort des aktuellen Skripts.Warum sind diese wichtig? Quelldateien befinden sich offensichtlich nicht im Build-Baum. Wenn Sie etwas wie
target_include_directories(Tutorial PUBLIC ../lib)
im vorherigen Beispiel versuchen , ist dieser Pfad relativ zum Build-Baum, dh es ist wie beim Schreiben${CMAKE_BINARY_DIR}/lib
, das nach innen schautsimple/build/lib/
. Es sind dort keine .h-Dateien enthalten. höchstens werden Sie findenlibTestLib.a
. Du willst${CMAKE_SOURCE_DIR}/lib
stattdessen.CMAKE_CXX_FLAGS
: Flags, die an den Compiler weitergeleitet werden sollen, in diesem Fall an den C ++ - Compiler. Erwähnenswert ist auch,CMAKE_CXX_FLAGS_DEBUG
welche stattdessen verwendet wird, wennCMAKE_BUILD_TYPE
DEBUG eingestellt ist. Es gibt mehr davon; Schauen Sie sich das CMake-Wiki an .CMAKE_RUNTIME_OUTPUT_DIRECTORY
: Sagen Sie CMake, wo alle ausführbaren Dateien beim Erstellen abgelegt werden sollen. Dies ist eine globale Einstellung. Sie können es beispielsweise einstellenbin/
und alles ordentlich dort platzieren.EXECUTABLE_OUTPUT_PATH
ist ähnlich, aber veraltet, falls Sie darauf stoßen.CMAKE_LIBRARY_OUTPUT_DIRECTORY
: Ebenso eine globale Einstellung, um CMake mitzuteilen, wo alle Bibliotheksdateien abgelegt werden sollen.Zieleigenschaften : Sie können Eigenschaften festlegen, die nur ein Ziel betreffen, sei es eine ausführbare Datei oder eine Bibliothek (oder ein Archiv ... Sie haben die Idee). Hier ist ein gutes Beispiel für die Verwendung (mit
set_target_properties()
.Gibt es eine einfache Möglichkeit, einem Ziel automatisch Quellen hinzuzufügen? Verwenden Sie GLOB, um alles in einem bestimmten Verzeichnis unter derselben Variablen aufzulisten . Beispielsyntax ist
FILE(GLOB <variable name> <directory>/*.cxx)
.Können Sie verschiedene Build-Typen angeben? Ja, obwohl ich nicht sicher bin, wie das funktioniert oder welche Einschränkungen dies hat. Es erfordert wahrscheinlich einige if / then'ning, aber CMake bietet einige grundlegende Unterstützung, ohne etwas zu konfigurieren, wie
CMAKE_CXX_FLAGS_DEBUG
zum Beispiel die Standardeinstellungen für. Sie können Ihren Build-Typ entwederCMakeLists.txt
über die Datei festlegenset(CMAKE_BUILD_TYPE <type>)
oder CMake beispielsweise über die Konsole mit den entsprechenden Flags aufrufencmake -DCMAKE_BUILD_TYPE=Debug
.Gibt es gute Beispiele für Projekte, die CMake verwenden? Wikipedia hat eine Liste von Open-Source-Projekten, die CMake verwenden, wenn Sie sich das ansehen möchten. Online-Tutorials waren in dieser Hinsicht bisher nichts anderes als eine Enttäuschung für mich, aber diese Frage zum Stapelüberlauf hat ein ziemlich cooles und leicht verständliches CMake-Setup. Es ist einen Blick wert.
Verwenden von Variablen aus CMake in Ihrem Code : Hier ist ein schnelles und schmutziges Beispiel (angepasst aus einem anderen Tutorial ):
simple/CMakeLists.txt
::simple/TutorialConfig.h.in
::Die von CMake generierte resultierende Datei
simple/src/TutorialConfig.h
:Mit dieser cleveren Verwendung können Sie coole Dinge wie das Ausschalten einer Bibliothek und dergleichen tun. Ich empfehle, sich dieses Tutorial anzusehen , da es einige etwas fortgeschrittenere Dinge gibt, die früher oder später bei größeren Projekten sehr nützlich sein müssen.
Für alles andere steckt Stack Overflow voller spezifischer Fragen und prägnanter Antworten, was für alle außer den Uneingeweihten großartig ist.
quelle
make
in Bash verwenden müssen, um Ihr Projekt zu erstellen.