Come dividere le stringhe su più righe in CMake?


96

Di solito ho una politica nel mio progetto, per non creare mai righe in file di testo che superano una lunghezza di riga di 80, quindi sono facilmente modificabili in tutti i tipi di editor (conosci il problema). Ma con CMake ho il problema di non sapere come dividere una semplice stringa in più righe per evitare una riga enorme. Considera questo codice di base:

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}")

Supera già il limite di 80 righe. Quindi come faccio a spezzare una riga in CMake in più righe senza arrivare a verbose (multiple list(APPEND ...)o simili)?

Risposte:


88

Aggiornamento per CMake 3.0 e versioni successive :

la continuazione della linea è possibile con \. vedere 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.\
")

Disponibilità delle versioni di CMake:

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 disponibile tramite Homebrew , Macports e Fink
Windows: cmake-3 disponibile tramite Chocolatey


20
Il problema con l'approccio CMake 3.0 è che non ignora il rientro. Ciò significa che le stringhe su più righe non possono essere rientrate con il resto del codice.
void

@ void.pointer Mi sono imbattuto nello stesso problema, hai capito come rientrare con il multi-linea?
user3667089

Inoltre, se si desidera utilizzare il rientro e il limite di 80 caratteri è vincolato, un altro modo è fare così: <code> message ("Questo è il valore della variabile:" <br> "$ {varValue}") </code>
munsingh

54

CMake 3.0 e versioni successive

Usa il string(CONCAT)comando:

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}")

Sebbene CMake 3.0 e le versioni successive supportino la continuazione della riga di argomenti tra virgolette , non è possibile far rientrare la seconda o le righe successive senza ottenere lo spazio vuoto di rientro incluso nella stringa.

CMake 2.8 e versioni precedenti

Puoi usare un elenco. Ogni elemento della lista può essere messo su una nuova riga:

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}")

Un elenco utilizzato senza virgolette viene concatenato senza spazi bianchi:

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

Se hai davvero bisogno di una stringa, puoi prima convertire l'elenco in una stringa:

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

Eventuali punti e virgola nelle stringhe originali verranno visualizzati come separatori di elementi dell'elenco e rimossi. Devono essere evasi:

set(MY_LIST "Hello World "
            "with a \;semicolon")

1
Per righe molto lunghe, una nuova riga dopo il nome della variabile migliora ulteriormente questo modello (non necessario in questo esempio).
saggio

Per curiosità , sarebbe corretto supporre che anche le virgolette doppie nella stringa debbano essere precedute da una barra rovesciata, e così anche le barre rovesciate che devono apparire come un carattere nella stringa?
Jonathan Leffler

@JonathanLeffler Sì, avrebbero bisogno di scappare. Le regole della lingua sono qui: cmake.org/cmake/help/latest/manual/… ma crea confusione. Vedi anche: stackoverflow.com/a/40728463
Douglas Royds

9

È ancora un po 'prolisso, ma se il limite di 80 caratteri ti infastidisce davvero, potresti aggiungere ripetutamente alla stessa variabile:

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}")

Fornisce output:

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

7

Non è possibile dividere una stringa letterale su più righe nei file CMakeLists.txt o negli script CMake. Se includi una nuova riga all'interno di una stringa, ci sarà una nuova riga letterale nella stringa stessa.

# 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}")

Tuttavia, CMake utilizza gli spazi per separare gli argomenti, quindi puoi modificare uno spazio che è un separatore di argomenti in una nuova riga ovunque tu voglia, senza modificare il comportamento.

Potresti riformulare questa riga più lunga:

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

come queste due linee più brevi:

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

Sono del tutto equivalenti.


5

L'esempio nella domanda originale riguarda solo una stringa relativamente breve. Per stringhe più lunghe (inclusi gli esempi forniti in altre risposte), un argomento tra parentesi potrebbe essere migliore. Dalla documentazione:

Viene scritta una parentesi di apertura [seguita da zero o più =seguiti da [. Viene scritta la parentesi di chiusura corrispondente ]seguita dallo stesso numero di =seguito da ]. Le parentesi non si annidano. È sempre possibile scegliere una lunghezza unica per le parentesi di apertura e chiusura per contenere parentesi di chiusura di altre lunghezze.

[...]

Per esempio:

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.
]=])```

Se lo capisco correttamente, un'interruzione di riga nel sorgente introdurrà anche un'interruzione di riga nella stringa. Ad esempio, ci sarà un \ n dopo la "lunghezza 1.". Qualche modo per evitarlo?
Lukas Schmelzeisen

È corretto, ci saranno \ns. Se non lo vuoi, non penso che gli argomenti tra parentesi siano la tua soluzione.
ingomueller.net

BTW, è valido per la versione 3.x, non 2.x
Maxim Suslov

4

Per coloro che sono stati portati qui da Come divido un'espressione del generatore CMake su più righe? Vorrei aggiungere alcune note.

Il metodo di continuazione della riga non funzionerà, CMake non può analizzare un elenco di generatori creato con spazi bianchi (rientro) e continuazione di riga.

Mentre la soluzione stringa (CONCAT) fornirà un'espressione generatore che può essere valutata, l'espressione valutata sarà racchiusa tra virgolette se il risultato contiene uno spazio.

Per ogni singola opzione da aggiungere deve essere creato un elenco di generatori separato, quindi le opzioni di impilamento come ho fatto di seguito causeranno il fallimento della compilazione:

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})

Questo perché le opzioni risultanti vengono passate al compilatore tra virgolette

/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 ’

Per valutare lunghe espressioni del generatore rappresentate utilizzando la soluzione stringa (CONCAT), ciascuna espressione del generatore deve valutare una singola opzione senza spazi:

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})

Ciò potrebbe non essere correlato alla domanda a cui sto inviando una risposta, purtroppo la domanda a cui sto rispondendo è erroneamente contrassegnata come un duplicato di questa domanda.

Gli elenchi di generatori non vengono gestiti e analizzati allo stesso modo delle stringhe e, per questo motivo, sono necessarie misure aggiuntive per dividere un elenco di generatori su più righe.


Probabilmente varrebbe la pena di pubblicare anche una versione di questa risposta sul "duplicato" collegato. Questa era la risposta che stavo cercando quando l'ho trovata.
Keith Prussing l'

3

Per mantenere una buona indentazione nel codice è abbastanza semplice da fare

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

Oppure forma una stringa direttamente con

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

come nella risposta di Douglas che ha maggiori dettagli. Tuttavia ho pensato che questo potesse riassumere il punto essenziale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.