Minimalversion
Hier ist die erste Zeile jeder CMakeLists.txt
, die der erforderliche Name der Datei ist, nach der CMake sucht:
cmake_minimum_required(VERSION 3.1)
Lassen Sie uns ein wenig über die CMake-Syntax sprechen. Der Befehlsnamecmake_minimum_required
unterscheidet nicht zwischen Groß- und Kleinschreibung, daher ist es üblich, Kleinbuchstaben zu verwenden. 1 Das VERSION
ist ein spezielles Schlüsselwort für diese Funktion. Und der Wert der Version folgt dem Schlüsselwort. Wie überall in diesem Buch, klicken Sie einfach auf den Befehlsnamen, um die offizielle Dokumentation zu sehen, und verwenden Sie das Dropdown-Menü, um die Dokumentation zwischen CMake-Versionen zu wechseln.
Diese Zeile ist besonders! 2 Die Version von CMake diktiert auch die Richtlinien, die Verhaltensänderungen definieren. Wenn Sie also minimum_required
auf VERSION2.8
setzen, werden Sie zum Beispiel unter macOS ein falsches Linking-Verhalten erhalten, selbst in den neuesten CMake-Versionen. Wenn Sie es auf 3.3 oder weniger setzen, erhalten Sie das falsche Verhalten bei versteckten Symbolen, usw. Eine Liste von Policies und Versionen ist verfügbar unterpolicies.
Ab CMake 3.12 wird ein Bereich unterstützt, z.B. VERSION 3.1...3.15
;das bedeutet, dass man bis 3.1 unterstützt, aber auch mit den neuen Policies-Einstellungen bis 3.15 getestet hat. Das ist viel angenehmer für Benutzer, die die besseren Einstellungen brauchen, und aufgrund eines Tricks in der Syntax ist es abwärtskompatibel mit älteren Versionen von CMake (obwohl CMake 3.1-3.11 in diesem Beispiel nur die 3.1-Version der Policies setzen wird, da diese Versionen dies nicht besonders behandeln). Neue Versionen von Policies sind am wichtigsten für macOS- undWindows-Benutzer, die in der Regel auch eine sehr aktuelle Version von CMake haben.
So sollten neue Projekte vorgehen:
cmake_minimum_required(VERSION 3.7...3.20)if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})endif()
Wenn die CMake-Version kleiner als 3.12 ist, wird der if-Block wahr sein und die Policy wird auf die aktuelle CMake-Version gesetzt. Wenn CMake 3.12 oder höher ist, wird der if-Block falsch sein, aber die neue Syntax in cmake_minimum_required
wird respektiert, und dies wird weiterhin richtig funktionieren!
WARNUNG: Der CMake-Server-Modus von MSVC hatte ursprünglich einen Fehler beim Lesen dieses Formats. Wenn Sie also Windows-Builds ohne Kommandozeile für ältere MSVC-Versionen unterstützen müssen, sollten Sie stattdessen Folgendes tun:
cmake_minimum_required(VERSION 3.7)if(${CMAKE_VERSION} VERSION_LESS 3.20) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})else() cmake_policy(VERSION 3.20)endif()
Wenn Sie hier wirklich einen niedrigen Wert einstellen müssen, können Siecmake_policy
verwenden, um die Richtlinienebene bedingt zu erhöhen oder eine bestimmte Richtlinie festzulegen. Bitte tun Sie dies zumindest für Ihre macOS-Benutzer!
Ein Projekt setzen
Jetzt wird jede CMake-Datei auf oberster Ebene die folgende Zeile haben:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Jetzt sehen wir noch mehr Syntax. Strings werden in Anführungszeichen gesetzt, Leerzeichen spielen keine Rolle, und der Name des Projekts ist das erste Argument (positional). Alle Schlüsselwortargumente hier sind optional. Die Version setzt eine Reihe von Variablen, wieMyProject_VERSION
und PROJECT_VERSION
. Die Sprachen sind C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), und SWIFT
(CMake3.15+ experimental). C CXX
ist der Standardwert. In CMake 3.9 wurde DESCRIPTION
hinzugefügt, um auch eine Projektbeschreibung zu setzen. Die Dokumentation fürproject
kann hilfreich sein.
Sie können Kommentare mit dem Zeichen #
hinzufügen. CMake hat auch eine Inline-Syntax für Kommentare, aber sie wird selten benutzt.
Es gibt wirklich nichts Besonderes am Projektnamen. An dieser Stelle werden keine Ziele hinzugefügt.
Erstellen einer ausführbaren Datei
Obwohl Bibliotheken viel interessanter sind und wir die meiste Zeit mit ihnen verbringen werden, lassen Sie uns mit einer einfachen ausführbaren Datei beginnen.
add_executable(one two.cpp three.h)
Hier gibt es mehrere Dinge zu entpacken. one
ist sowohl der Name der erzeugten ausführbaren Datei als auch der Name des erzeugten CMake-Targets (Sie werden bald mehr über Targets erfahren, das verspreche ich). Die Liste der Quelldateien kommt als nächstes, und Sie können so viele auflisten, wie Sie möchten. CMake ist schlau und kompiliert nur Quelldateierweiterungen. Die Header werden in den meisten Fällen ignoriert; der einzige Grund, sie aufzulisten, ist, dass sie in IDEs auftauchen sollen. Targets werden in vielen IDEs als Ordner angezeigt. Mehr über das allgemeine Buildsystem und Targets finden Sie unter buildsystem.
Erstellen einer Bibliothek
Das Erstellen einer Bibliothek erfolgt mit add_library
und ist genauso einfach:
add_library(one STATIC two.cpp three.h)
Sie können den Typ der Bibliothek auswählen, STATIC, SHARED oder MODULE. Wenn Sie diese Option auslassen, wird der Wert von BUILD_SHARED_LIBS
verwendet, um zwischen STATIC und SHARED zu wählen.
Wie Sie in den folgenden Abschnitten sehen werden, müssen Sie oft ein fiktives Ziel erstellen, d.h. eines, bei dem nichts kompiliert werden muss, zum Beispiel für eine reine Header-Bibliothek. Der einzige Unterschied ist, dass keine Dateinamen folgen können.
Sie können auch eine ALIAS
Bibliothek mit einer bestehenden Bibliothek erstellen, was Ihnen einfach einen neuen Namen für ein Ziel gibt. Der einzige Vorteil dabei ist, dass Sie Bibliotheken mit ::
im Namen erstellen können (was Sie später noch sehen werden). 3
Targets sind dein Freund
Nun haben wir ein Target angegeben, wie fügen wir Informationen darüber hinzu? Vielleicht braucht es zum Beispiel ein Include-Verzeichnis:
target_include_directories(one PUBLIC include)
target_include_directories
fügt ein Include-Verzeichnis zu einem Ziel hinzu. PUBLIC
bedeutet nicht viel für eine ausführbare Datei; für eine Bibliothek lässt es CMake wissen, dass alle Ziele, die auf dieses Ziel linken, auch dieses Include-Verzeichnis benötigen. Andere Optionen sind PRIVATE
(wirkt sich nur auf das aktuelle Ziel aus, nicht auf Abhängigkeiten) und INTERFACE
(wird nur für Abhängigkeiten benötigt).
Wir können dann Ziele verketten:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
ist wahrscheinlich der nützlichste und verwirrendste Befehl in CMake. Er nimmt ein Target (another
) und fügt eine Abhängigkeit hinzu, wenn ein Target angegeben ist. Wenn kein Ziel mit diesem Namen (one
) existiert, fügt er einen Link zu einer Bibliothek namens one
in Ihrem Pfad hinzu (daher der Name des Befehls). Sie können auch einen vollständigen Pfad zu einer Bibliothek angeben. Oder ein Linker-Flag. Um noch ein wenig Verwirrung zu stiften: Das klassische CMake erlaubte es, die Auswahl des Schlüsselworts PUBLIC
usw. zu überspringen. Wenn dies bei einem Ziel gemacht wurde, erhalten Sie einen Fehler, wenn Sie versuchen, Stile weiter unten in der Kette zu mischen.
Konzentrieren Sie sich darauf, überall Ziele und überall Schlüsselwörter zu verwenden, und Sie werden gut zurechtkommen.
Ziele können Include-Verzeichnisse, gelinkte Bibliotheken (oder gelinkte Ziele), Kompilieroptionen, Kompilierdefinitionen, Kompilierfunktionen (siehe das Kapitel über C++11) und mehr haben. Wie Sie in den beiden Kapiteln über Include-Projekte sehen werden, können Sie oft Targets erhalten (und immer Targets erstellen), die alle von Ihnen verwendeten Bibliotheken repräsentieren. Selbst Dinge, die keine echten Bibliotheken sind, wie OpenMP, können mit Targets dargestellt werden. Das ist der Grund, warum Modern CMake großartig ist!
Tauchen Sie ein
Sehen Sie, ob Sie der folgenden Datei folgen können. Sie erstellt eine einfache C++11-Bibliothek und ein Programm, das sie verwendet. Keine Abhängigkeiten. Ich werde später mehr C++-Standardoptionen besprechen, wobei ich jetzt das CMake 3.8-System verwende.
cmake_minimum_required(VERSION 3.8)project(Calculator LANGUAGES CXX)add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)target_include_directories(calclib PUBLIC include)target_compile_features(calclib PUBLIC cxx_std_11)add_executable(calc apps/calc.cpp)target_link_libraries(calc PUBLIC calclib)
1. In diesem Buch werde ich es größtenteils vermeiden, Ihnen den falschen Weg zu zeigen, wie man Dinge tut; Sie können viele Beispiele dafür online finden. Ich werde gelegentlich Alternativen erwähnen, aber diese werden nicht empfohlen, es sei denn, sie sind absolut notwendig; oft sind sie nur da, um Ihnen zu helfen, älteren CMake-Code zu lesen.
2. Du wirst hier manchmal
FATAL_ERROR
sehen, das war nötig, um nette Fehler zu unterstützen, wenn man dies in CMake <2.6 ausführt, was kein Problem mehr sein sollte.
3. Die
::
-Syntax war ursprünglich fürINTERFACE IMPORTED
-Bibliotheken gedacht, die explizit als Bibliotheken außerhalb des aktuellen Projekts definiert werden sollten. Aus diesem Grund funktionieren die meistentarget_*
-Befehle nicht mitIMPORTED
-Bibliotheken, was es schwierig macht, sie selbst einzurichten. Verwenden Sie also vorerst nicht dasIMPORTED
-Schlüsselwort und verwenden Sie stattdessen einALIAS
-Target; das wird in Ordnung sein, bis Sie anfangen, Targets zu exportieren. Diese Einschränkung wurde in CMake 3.11 behoben.