Komplette CMake-Anleitung. Erster Teil: Syntax


Einführung


CMake ist eine offene und plattformübergreifende Reihe von Dienstprogrammen, mit denen das Testen, Kompilieren und Erstellen von Projektpaketen in C / C ++ automatisiert werden kann. Wenn Sie einmal ein kleines Skript schreiben, das jeder versteht, stellen Sie sicher, dass Ihr Projekt auf jeder Plattform, auf der CMake verfügbar ist, den gleichen Build aufweist.


Die CMake-Sprache , die in eine native Assembly-Datei (z. B. Makefile oder Ninja) übersetzt wird, definiert den Prozess des gesamten Projektmanagements. Auf der funktionalen Seite stehen Ihnen nur Teams zur Verfügung, die zu recht komplexen Strukturen geformt werden können. Wir werden mit ihnen beginnen.


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.


Teams


Befehle in CMake ähneln Funktionen in vielen Programmiersprachen. Um einen Befehl aufzurufen, müssen Sie seinen Namen schreiben und ihm dann Argumente geben, die in Klammern stehen und durch Leerzeichen getrennt sind. Im obigen Beispiel werden sechs Argumente an den message zur Ausgabe an die Konsole übergeben:


 #    "CMake is the most powerful buildsystem!" message("CMake " "is " "the " "most " "powerful " "buildsystem!") 

Argumente


Argumente in doppelten Anführungszeichen ermöglichen eine Abschirmung und eine variable Substitution im Inneren. Ungerahmte Argumente erlauben die Produktion solcher Dinge nicht und können die Zeichen ()#"\ und Leerzeichen nicht enthalten, sind jedoch bequemer zu verwenden. Beispiel:


 #  "Hello, my lovely CMake",    "!": message("Hello, my lovely CMake\t!") #  "Hello,_my_lovely_CMake!"  : message(Hello,_my_lovely_CMake!) 

Es ist anzumerken, dass das Argument Walk;around;the;forest zur Liste erweitert wird. Walk around the forest , da jedes ungerahmte Argument automatisch zu einer Liste von Werten erweitert wird (vorausgesetzt, die Werte des ursprünglichen Arguments sind durch Semikolons getrennt), jedoch doppelt umrahmt Anführungszeichen als Argument Eine solche Transformation findet nicht statt (Semikolonzeichen verschwinden einfach). Diese Funktion wurde in den Kommentaren erwähnt.


Kommentare


Kommentare beginnen mit einem Nummernzeichen und enden am Ende der Zeile, in der sie gedruckt wurden. Der in den Kommentaren enthaltene Text wird vom Build-System ignoriert und hat keine Auswirkungen auf dessen Betrieb. Die obigen Beispiele zeigen auch die Verwendung von Kommentaren.


Variablen


Variablen können durch Aufrufen des Befehls set definiert und durch Aufrufen von unset gelöscht werden. Sie können den Wert einer Variablen erhalten, indem Sie ${VARIABLE} . Wenn die Variable noch nicht definiert wurde und irgendwo ihr Wert abgerufen werden musste, wird diese Variable zu einer leeren Zeichenfolge. Ein Beispiel:


 #   VARIABLE   "Mr. Thomas": set(VARIABLE "Mr. Thomas") #  "His name is: Mr. Thomas": message("His name is: " ${VARIABLE}) #  "'BINGO' is equal to: []",   "BINGO"  : message("'BINGO' is equal to: [${BINGO}]") #   VARIABLE: unset(VARIABLE) 

Optionen


CMake unterstützt Einstellungsoptionen, die vom Benutzer geändert werden können. Optionen ähneln Variablen und werden mit dem Befehl option , der nur drei Argumente akzeptiert: den Namen der Variablen, die Zeichenfolgenbeschreibung der Variablen und den Standardwert der Variablen ( ON oder OFF ):


 #   `USE_ANOTHER_LIBRARY`   # "Do you want to use an another library?"   "OFF": option(USE_ANOTHER_LIBRARY "Do you want to use an another library?" OFF) 

Logische Ausdrücke


Bevor Sie mit der Untersuchung von bedingten Operatoren und zyklischen Konstruktionen fortfahren, müssen Sie die Arbeit logischer Ausdrücke verstehen. Logische Ausdrücke werden beim Überprüfen von Bedingungen verwendet und können einen von zwei Werten annehmen: wahr oder falsch. Zum Beispiel ist der Ausdruck 52 LESS 58 wahr, da 52 <58. Der Ausdruck 88 EQUAL 88 ist wahr, 63 GREATER 104 ist falsch. Sie können nicht nur Zahlen, sondern auch Zeichenfolgen, Versionen, Dateien, Listenmitgliedschaft und reguläre Ausdrücke vergleichen. Eine vollständige Liste der logischen Ausdrücke finden Sie hier .


Bedingte Anweisungen


Bedingte Operatoren in CMake funktionieren genau wie in anderen Programmiersprachen. In diesem Beispiel funktioniert nur der erste bedingte Operator, der prüft, ob 5> 1. Die zweite und dritte Bedingung sind falsch, da 5 nicht kleiner oder gleich eins sein kann. Die elseif und else sind optional. endif erforderlich und signalisiert den Abschluss vorheriger Überprüfungen.


 #  "Of course, 5 > 1!": if(5 GREATER 1) message("Of course, 5 > 1!") elseif(5 LESS 1) message("Oh no, 5 < 1!") else() message("Oh my god, 5 == 1!") endif() 

Zyklen


Schleifen in CMake ähneln Schleifen in anderen Programmiersprachen. Im obigen Beispiel wird der Wert der Variablen VARIABLE auf Airport , und dann werden vier verschachtelte Befehle nacheinander ausgeführt, bis der Wert der Variablen VARIABLE gleich Airport . Der letzte vierte set(VARIABLE "Police station") Befehl set(VARIABLE "Police station") setzt den Wert der aktivierten Variablen in der Police station , sodass die Schleife unmittelbar vor Erreichen der zweiten Iteration stoppt. Der Befehl endwhile signalisiert den Abschluss der Liste der in der Schleife verschachtelten Befehle.


 #      "VARIABLE is still 'Airport'": set(VARIABLE Airport) while(${VARIABLE} STREQUAL Airport) message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") message("VARIABLE is still '${VARIABLE}'") set(VARIABLE "Police station") endwhile() 

Dieses Beispiel für jede foreach funktioniert wie folgt: Bei jeder Iteration dieser Schleife wird der Variablen VARIABLE der folgende Wert aus der Liste zugewiesen. Give me the sugar please! Anschließend wird der Befehl message(${VARIABLE}) ausgeführt, der den aktuellen Wert der Variablen VARIABLE anzeigt. Wenn die Liste keine Werte enthält, beendet die Schleife ihre Ausführung. Der Befehl endforeach signalisiert den Abschluss der Liste der in der Schleife verschachtelten Befehle.


 #  "Give me the sugar please!"   : foreach(VARIABLE Give me the sugar please!) message(${VARIABLE}) endforeach() 

Es gibt 3 weitere Arten, eine foreach schreiben. Der erste Zyklus in diesem Beispiel generiert Ganzzahlen von 0 bis 10 anstelle der Liste, der zweite Zyklus generiert im Bereich von 3 bis 15 und der dritte Zyklus arbeitet im Segment von 50 bis 90, jedoch mit einem Schritt von 10.


 #  "0 1 2 3 4 5 6 7 8 9 10"   : foreach(VARIABLE RANGE 10) message(${VARIABLE}) endforeach() #  "3 4 5 6 7 8 9 10 11 12 13 14 15"   : foreach(VARIABLE RANGE 3 15) message(${VARIABLE}) endforeach() #  "50 60 70 80 90"   : foreach(VARIABLE RANGE 50 90 10) message(${VARIABLE}) endforeach() 

Funktionen und Makros


Mit der CMake-Syntax können Sie Ihre eigenen Befehle definieren, die genau wie integriert aufgerufen werden können. Das folgende Beispiel zeigt die Verwendung von Funktionen und Makros: Zunächst werden eine Funktion und ein Makro mit ihren eigenen Befehlen definiert, und beim Aufruf werden ihre Befehle nacheinander ausgeführt.


 #   "print_numbers": function(print_numbers NUM1 NUM2 NUM3) message(${NUM1} " " ${NUM2} " " ${NUM3}) endfunction() #   "print_words": macro(print_words WORD1 WORD2 WORD3) message(${WORD1} " " ${WORD2} " " ${WORD3}) endmacro() #   "print_numbers",   "12 89 225": print_numbers(12 89 225) #   "print_words",   "Hey Hello Goodbye": print_words(Hey Hello Goodbye) 

Der function den Namen der zukünftigen Funktion als erstes Argument, und die restlichen Argumente sind die Namen der Parameter, die als normale Variablen verwendet werden können. Die Parameter sind nur für die zu definierende Funktion sichtbar, was bedeutet, dass wir außerhalb der Funktion keinen Zugriff auf ihre Parameter erhalten können. Darüber hinaus sind alle anderen innerhalb der Funktion definierten und neu definierten Variablen nur für sich selbst sichtbar.


Makros ähneln Funktionen mit der Ausnahme, dass sie keinen eigenen Bereich haben: Alle Variablen in Makros werden als global betrachtet. Weitere Informationen zu den Unterschieden zwischen Makros und Funktionen finden Sie hier .


Wie in den Kommentaren erwähnt, ähneln Makros in CMake Makros im C-Präprozessor: Wenn Sie den Befehl return in den Makrotext einfügen, beenden Sie die aufrufende Funktion (oder das gesamte Skript), wie dieses Beispiel zeigt:


 #  ,   : macro(demonstrate_macro) return() endmacro() #  ,   : function(demonstrate_func) demonstrate_macro() message("The function was invoked!") endfunction() #  "Something happened with the function!" demonstrate_func() message("Something happened with the function!") 

Im obigen Beispiel hat die Funktion demonstrate_func keine Zeit, die Nachricht zu drucken. The function was invoked! Nach wie vor wird der Ort, an dem das Makro demonstrate_macro aufgerufen wird, ersetzt und der Befehl exit ausgeführt.


Argumente analysieren


Wie in den Kommentaren erwähnt, ermöglicht der leistungsstarke Mechanismus cmake_parse_arguments Parsen von Argumenten, die an eine Funktion oder ein Makro übergeben werden.


Dieser Befehl akzeptiert das Präfix, das bei der Definition von Variablen verwendet wird (siehe nächster Absatz), eine Liste von Optionen, die ohne nachfolgende Werte verwendet werden, eine Liste von Schlüsselwörtern, gefolgt von einem einzelnen Wert, eine Liste von Schlüsselwörtern, gefolgt von Wertesätzen, und eine Liste aller an die Funktion übergebenen Werte oder Makro.


Die Arbeit des Argumentanalyse-Mechanismus besteht darin, die empfangenen Argumente in variable Werte umzuwandeln. Daher definiert der betrachtete Befehl für jede Option und jedes Schlüsselwort eine eigene Variable der Form <Prefix>_<OptionOrKeyword> , die einen bestimmten Wert kapselt. Bei Optionen sind dies boolesche Werte (true - die Option wird angezeigt; andernfalls false) und bei Schlüsselwörtern alle übertragenen Werte nach ihnen.


Die Funktion custom_function enthält einen Aufruf von cmake_parse_arguments und druckt dann die Werte bestimmter Variablen. Als nächstes wird die Funktion mit den Argumenten LOW NUMBER 30 COLORS red green blue aufgerufen, wonach der Bildschirm gedruckt wird:


 function(custom_function) #       : cmake_parse_arguments(CUSTOM_FUNCTION "LOW;HIGH" "NUMBER" "COLORS" ${ARGV}) #  "'LOW' = [TRUE]": message("'LOW' = [${CUSTOM_FUNCTION_LOW}]") # "'HIGH' = [FALSE]": message("'HIGH' = [${CUSTOM_FUNCTION_HIGH}]") #  "'NUMBER' = [30]": message("'NUMBER' = [${CUSTOM_FUNCTION_NUMBER}]") #  "'COLORS' = [red;green;blue]": message("'COLORS' = [${CUSTOM_FUNCTION_COLORS}]") endfunction() #   "custom_function"   : custom_function(LOW NUMBER 30 COLORS red green blue) 

Geltungsbereich


Im vorherigen Abschnitt haben Sie erfahren, dass einige Konstrukte in CMake ihren eigenen Bereich definieren können. Tatsächlich werden alle Variablen standardmäßig als global betrachtet (der Zugriff auf sie ist überall möglich), mit Ausnahme derjenigen, die in Funktionen definiert und neu definiert wurden. Es gibt auch Cache-Variablen , die ihren eigenen Bereich haben, aber nicht so oft verwendet werden.


Wie in den Kommentaren erwähnt, können Variablen mit dem Befehl set(VARIABLE ... PARENT_SCOPE) im Bereich "parent" definiert werden. Dieses Beispiel zeigt diese Funktion:


 # ,   "VARIABLE"   # "In the parent scope..."    : function(demonstrate_variable) set(VARIABLE "In the parent scope..." PARENT_SCOPE) endfunction() #   "VARIABLE"    : demonstrate_variable() #      "VARIABLE" : message("'VARIABLE' is equal to: ${VARIABLE}") 

Wenn PARENT_SCOPE aus der Definition der Variablen VARIABLE wird, ist die Variable nur für die Funktion demonstrate_variable zugänglich und nimmt im globalen Bereich einen leeren Wert an.


Fazit


Damit ist die CMake-Syntax abgeschlossen. Der nächste Artikel wird in ein paar Tagen veröffentlicht und die Verwendung des CMake-Build-Systems vorstellen. Bis bald!

Source: https://habr.com/ru/post/de431428/


All Articles