Wie teile ich Strings in CMake über mehrere Zeilen?

94

Normalerweise habe ich in meinem Projekt die Richtlinie, niemals Zeilen in Textdateien zu erstellen, die eine Zeilenlänge von 80 überschreiten, sodass sie in allen Arten von Editoren leicht bearbeitet werden können (Sie kennen den Deal). Aber mit CMake habe ich das Problem, dass ich nicht weiß, wie man eine einfache Zeichenfolge in mehrere Zeilen aufteilt, um eine große Zeile zu vermeiden. Betrachten Sie diesen grundlegenden Code:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
set(MYPROJ_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")

Das Limit von 80 Zeilen wird bereits überschritten. Wie kann ich eine Zeile in CMake in mehrere Zeilen aufteilen, ohne ausführlich zu werden (mehrere list(APPEND ...)oder ähnliches)?

Lukas Schmelzeisen
quelle

Antworten:

87

Update für CMake 3.0 und neuer :

Leitungsfortsetzung ist möglich mit \. siehe cmake-3.0-doc

message("\
This is the first line of a quoted argument. \
In fact it is the only line but since it is long \
the source code uses line continuation.\
")

Verfügbarkeit von CMake-Versionen:

Debian Wheezy (2013): 2.8.9
Debian Wheezy-Backports: 2.8.11
Debian Jessy (2015): 3.0.2
Ubuntu 14.04 (LTS): 2.8.12
Ubuntu 15.04: 3.0.2
Mac OSX: cmake-3 über Homebrew erhältlich , Macports und Fink
Windows: cmake-3 über Chocolatey erhältlich

Hotschke
quelle
19
Das Problem beim CMake 3.0-Ansatz besteht darin, dass Einrückungen nicht ignoriert werden. Dies bedeutet, dass mehrzeilige Zeichenfolgen nicht mit dem Rest des Codes eingerückt werden können.
void.pointer
@ void.pointer Ich bin auf das gleiche Problem gestoßen. Hast du herausgefunden, wie man mit mehreren Zeilen einrückt?
user3667089
Wenn Sie einen Einzug verwenden möchten und ein Limit von 80 Zeichen haben, können Sie dies auch folgendermaßen tun: <code> message ("Dies ist der Wert der Variablen:" <br> "$ {varValue}") </ code>
Munsingh
54

CMake 3.0 und neuer

Verwenden Sie den string(CONCAT)Befehl:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
string(CONCAT MYPROJ_VERSION "${MYPROJ_VERSION_MAJOR}"
                             ".${MYPROJ_VERSION_MINOR}"
                             ".${MYPROJ_VERSION_PATCH}"
                             "-${MYPROJ_VERSION_EXTRA}")

Obwohl CMake 3.0 und neuere die Fortsetzung von Argumenten in Anführungszeichen unterstützen , können Sie die zweite oder nachfolgende Zeile nicht einrücken, ohne das Leerzeichen für die Einrückung in Ihrer Zeichenfolge zu erhalten.

CMake 2.8 und älter

Sie können eine Liste verwenden. Jedes Element der Liste kann in eine neue Zeile gesetzt werden:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
set(MYPROJ_VERSION_LIST "${MYPROJ_VERSION_MAJOR}"
                        ".${MYPROJ_VERSION_MINOR}"
                        ".${MYPROJ_VERSION_PATCH}"
                        "-${MYPROJ_VERSION_EXTRA}")

Eine Liste ohne Anführungszeichen wird ohne Leerzeichen verkettet:

message(STATUS "Version: " ${MYPROJ_VERSION_LIST})
-- Version: 1.0.0-rc1

Wenn Sie wirklich eine Zeichenfolge benötigen, können Sie die Liste zuerst in eine Zeichenfolge konvertieren:

string(REPLACE ";" "" MYPROJ_VERSION "${MYPROJ_VERSION_LIST}")
message(STATUS "Version: ${MYPROJ_VERSION}")
-- Version: 1.0.0-rc1

Alle Semikolons in Ihren ursprünglichen Zeichenfolgen werden als Listenelementtrennzeichen angezeigt und entfernt. Sie müssen entkommen:

set(MY_LIST "Hello World "
            "with a \;semicolon")
Douglas Royds
quelle
1
Bei sehr langen Zeilen verbessert eine neue Zeile nach dem Variablennamen dieses Muster noch weiter (in diesem Beispiel nicht erforderlich).
Salbei
Wäre es aus Neugier richtig zu erraten, dass doppelte Anführungszeichen in der Zeichenfolge auch mit einem Backslash maskiert werden müssen, und auch Backslashes, die als Zeichen in der Zeichenfolge erscheinen müssen?
Jonathan Leffler
@ JonathanLeffler Ja, sie müssten fliehen. Sprachregeln finden Sie hier: cmake.org/cmake/help/latest/manual/…, aber es wird verwirrend. Siehe auch: stackoverflow.com/a/40728463
Douglas Royds
9

Es ist immer noch ein wenig ausführlich, aber wenn Sie das Limit von 80 Zeichen wirklich stört, können Sie wiederholt an dieselbe Variable anhängen:

set(MYPROJ_VERSION_MAJOR "1")
set(MYPROJ_VERSION_MINOR "0")
set(MYPROJ_VERSION_PATCH "0")
set(MYPROJ_VERSION_EXTRA "rc1")
set(MYPROJ_VERSION "${MYPROJ_VERSION_MAJOR}.")
set(MYPROJ_VERSION "${MYPROJ_VERSION}${MYPROJ_VERSION_MINOR}.")
set(MYPROJ_VERSION "${MYPROJ_VERSION}${MYPROJ_VERSION_PATCH}-")
set(MYPROJ_VERSION "${MYPROJ_VERSION}${MYPROJ_VERSION_EXTRA}")
message(STATUS "version: ${MYPROJ_VERSION}")

Gibt Ausgabe:

$ cmake  ~/project/tmp
-- version: 1.0.0-rc1
-- Configuring done
-- Generating done
-- Build files have been written to: /home/rsanderson/build/temp
Rian Sanderson
quelle
7

Es gibt keine Möglichkeit, ein Zeichenfolgenliteral in CMakeLists.txt-Dateien oder in CMake-Skripten auf mehrere Zeilen aufzuteilen. Wenn Sie eine neue Zeile in eine Zeichenfolge einfügen, enthält die Zeichenfolge selbst eine wörtliche neue Zeile.

# Don't do this, it won't work, MYPROJ_VERSION will contain newline characters:
set(MYPROJ_VERSION "${VERSION_MAJOR}.
  ${VERSION_MINOR}.${VERSION_PATCH}-
  ${VERSION_EXTRA}")

CMake verwendet jedoch Leerzeichen, um Argumente zu trennen, sodass Sie ein Leerzeichen, das ein Argumenttrennzeichen ist, an einer beliebigen Stelle in eine neue Zeile ändern können, ohne das Verhalten zu ändern.

Sie könnten diese längere Zeile umformulieren:

set(MYPROJ_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")

wie diese zwei kürzeren Zeilen:

set(MYPROJ_VERSION
  "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")

Sie sind völlig gleichwertig.

DLRdave
quelle
5

Das Beispiel in der ursprünglichen Frage handelt nur von einer relativ kurzen Zeichenfolge. Für längere Zeichenfolgen (einschließlich der Beispiele in anderen Antworten) könnte ein Klammerargument besser sein. Aus der Dokumentation:

Eine öffnende Klammer wird geschrieben, [gefolgt von null oder mehr, =gefolgt von [. Die entsprechende schließende Klammer wird geschrieben, ]gefolgt von der gleichen Anzahl von =gefolgt von ]. Klammern nisten nicht. Es kann immer eine eindeutige Länge für die Öffnungs- und Schließklammern gewählt werden, um Schließklammern anderer Längen zu enthalten.

[...]

Beispielsweise:

message([=[
This is the first line in a bracket argument with bracket length 1.
No \-escape sequences or ${variable} references are evaluated.
This is always one argument even though it contains a ; character.
The text does not end on a closing bracket of length 0 like ]].
It does end in a closing bracket of length 1.
]=])```
ingomueller.net
quelle
Wenn ich das richtig verstehe, führt ein Zeilenumbruch in der Quelle auch einen Zeilenumbruch in die Zeichenfolge ein. Zum Beispiel wird nach "Länge 1" ein \ n stehen. Wie kann man das vermeiden?
Lukas Schmelzeisen
Das ist richtig, es wird \ns geben. Wenn Sie das nicht wollen, denke ich nicht, dass Klammerargumente Ihre Lösung sind.
ingomueller.net
Übrigens gilt es für Version 3.x, nicht für 2.x
Maxim Suslov
4

Für diejenigen, die hierher gebracht wurden von Wie teile ich einen CMake-Generatorausdruck in mehrere Zeilen auf? Ich möchte einige Notizen hinzufügen.

Die Zeilenfortsetzungsmethode funktioniert nicht. CMake kann keine Generatorliste analysieren, die mit Leerzeichen (Einrückung) und Zeilenfortsetzung erstellt wurde.

Während die String-Lösung (CONCAT) einen Generatorausdruck bereitstellt, der ausgewertet werden kann, wird der ausgewertete Ausdruck von Anführungszeichen umgeben, wenn das Ergebnis ein Leerzeichen enthält.

Für jede einzelne Option, die hinzugefügt werden soll, muss eine separate Generatorliste erstellt werden. Wenn also Stapeloptionen wie im Folgenden ausgeführt werden, schlägt der Build fehl:

string(CONCAT WARNING_OPTIONS "$<"
    "$<OR:"
        "$<CXX_COMPILER_ID:MSVC>,"
        "$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>"
    ">:"
    "/D_CRT_SECURE_NO_WARNINGS "
">$<"
    "$<AND:"
        "$<CXX_COMPILER_ID:Clang,GNU>,"
        "$<NOT:$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>"
    ">:"
    "-Wall -Werror "
">$<"
    "$<CXX_COMPILER_ID:GNU>:"
    "-Wno-multichar -Wno-sign-compare "
">")
add_compile_options(${WARNING_OPTIONS})

Dies liegt daran, dass die resultierenden Optionen in Anführungszeichen an den Compiler übergeben werden

/usr/lib64/ccache/c++  -DGTEST_CREATE_SHARED_LIBRARY=1 -Dgtest_EXPORTS -I../ThirdParty/googletest/googletest/include -I../ThirdParty/googletest/googletest -std=c++11 -fno-rtti -fno-exceptions -fPIC    -std=c++11 -fno-rtti -fno-exceptions -Wall -Wshadow -DGTEST_HAS_PTHREAD=1 -fexceptions -Wextra -Wno-unused-parameter -Wno-missing-field-initializers "-Wall -Werror -Wno-multichar -Wno-sign-compare " -fdiagnostics-color -MD -MT ThirdParty/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o -MF ThirdParty/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o.d -o ThirdParty/googletest/googletest/CMakeFiles/gtest.dir/src/gtest-all.cc.o -c ../ThirdParty/googletest/googletest/src/gtest-all.cc
c++: error: unrecognized command line option ‘-Wall -Werror -Wno-multichar -Wno-sign-compare ’

Um lange Generatorausdrücke auszuwerten, die mit der String (CONCAT) -Lösung dargestellt werden, muss jeder Generatorausdruck eine einzelne Option ohne Leerzeichen ergeben:

string(CONCAT WALL "$<"
    "$<AND:"
        "$<CXX_COMPILER_ID:Clang,GNU>,"
        "$<NOT:$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>"
    ">:"
    "-Wall"
">")
string(CONCAT WERROR "$<"
    "$<AND:"
        "$<CXX_COMPILER_ID:Clang,GNU>,"
        "$<NOT:$<STREQUAL:${CMAKE_CXX_SIMULATE_ID},MSVC>>"
    ">:"
    "-Werror"
">")
message(STATUS "Warning Options: " ${WALL} ${WERROR})
add_compile_options(${WALL} ${WERROR})

Dies hängt möglicherweise nicht mit der Frage zusammen, auf die ich eine Antwort poste. Leider ist die Frage, die ich beantworte, fälschlicherweise als Duplikat dieser Frage markiert.

Generatorlisten werden nicht wie Zeichenfolgen behandelt und analysiert. Aus diesem Grund müssen zusätzliche Maßnahmen ergriffen werden, um eine Generatorliste auf mehrere Zeilen aufzuteilen.

Parker Gibson
quelle
Es würde sich wahrscheinlich lohnen, auch eine Version dieser Antwort auf dem verlinkten "Duplikat" zu veröffentlichen. Dies war die Antwort, nach der ich gesucht hatte, als ich darauf stieß.
Keith Prussing
3

Um eine gute Einrückung in Ihrem Code beizubehalten, ist dies einfach genug

message("These strings " "will all be "
        "concatenated. Don't forget "
        "your trailing spaces!")

Oder bilden Sie eine Zeichenfolge direkt mit

string(CONCAT MYSTR "This and " "that "
                    "and me too!")

wie in Douglas 'Antwort, wer mehr Details hat. Ich dachte jedoch, dies könnte nur den wesentlichen Punkt zusammenfassen.

wardw
quelle