Bagaimana cara membagi string di beberapa baris di CMake?

96

Saya biasanya memiliki kebijakan dalam proyek saya, untuk tidak pernah membuat baris dalam file teks yang melebihi panjang baris 80, sehingga mudah diedit di semua jenis editor (Anda tahu kesepakatannya). Tetapi dengan CMake saya mendapatkan masalah bahwa saya tidak tahu bagaimana membagi string sederhana menjadi beberapa baris untuk menghindari satu baris besar. Pertimbangkan kode dasar ini:

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

Itu sudah melebihi batas 80 baris. Jadi, bagaimana cara memecah baris di CMake menjadi beberapa baris tanpa menjadi verbose (banyak list(APPEND ...)atau sejenisnya)?

Lukas Schmelzeisen
sumber

Jawaban:

89

Pembaruan untuk CMake 3.0 dan yang lebih baru :

kelanjutan jalur dimungkinkan dengan \. lihat 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.\
")

Ketersediaan versi 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 tersedia melalui Homebrew , Macports dan Fink
Windows: cmake-3 tersedia melalui Chocolatey

Hotschke
sumber
20
Masalah dengan pendekatan CMake 3.0 adalah ia tidak mengabaikan indentasi. Artinya, string multi-baris tidak dapat diindentasi dengan kode lainnya.
void.pointer
@ void.pointer Saya mengalami masalah yang sama, apakah Anda mengetahui cara membuat indentasi dengan multi-baris?
pengguna3667089
Juga jika ingin menggunakan indentasi dan dibatasi 80 karakter maka cara lain adalah melakukannya seperti ini: <code> message ("Ini adalah nilai variabel:" <br> "$ {varValue}") </code>
munsingh
54

CMake 3.0 dan yang lebih baru

Gunakan string(CONCAT)perintah:

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

Meskipun CMake 3.0 dan baris dukungan yang lebih baru merupakan kelanjutan dari argumen kutipan , Anda tidak dapat membuat indentasi baris kedua atau berikutnya tanpa memasukkan spasi lekukan dalam string Anda.

CMake 2.8 dan yang lebih tua

Anda dapat menggunakan daftar. Setiap elemen dari daftar dapat diletakkan di baris baru:

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

Daftar yang digunakan tanpa tanda kutip digabungkan tanpa spasi:

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

Jika Anda benar-benar membutuhkan string, Anda dapat mengonversi daftar menjadi string terlebih dahulu:

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

Setiap titik koma di string asli Anda akan dilihat sebagai pemisah elemen daftar, dan dihapus. Mereka harus di-escape:

set(MY_LIST "Hello World "
            "with a \;semicolon")
Douglas Royds
sumber
1
Untuk garis yang sangat panjang, baris baru setelah nama variabel semakin meningkatkan pola ini (tidak perlu dalam contoh ini).
bijak
Karena penasaran , apakah benar untuk menebak bahwa tanda kutip ganda dalam string juga perlu di-escape dengan garis miring terbalik, dan begitu pula garis miring terbalik yang perlu muncul sebagai karakter dalam string?
Jonathan Leffler
@JonathanLeffler Ya, mereka perlu melarikan diri. Aturan bahasa ada di sini: cmake.org/cmake/help/latest/manual/… tapi itu membingungkan. Lihat juga: stackoverflow.com/a/40728463
Douglas Royds
9

Ini masih sedikit bertele-tele, tetapi jika batas 80 karakter benar-benar mengganggu Anda, maka Anda dapat berulang kali menambahkan variabel yang sama:

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

Memberikan keluaran:

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

Tidak ada cara untuk membagi string literal menjadi beberapa baris dalam file CMakeLists.txt atau dalam skrip CMake. Jika Anda menyertakan baris baru dalam string, akan ada baris baru literal di string itu sendiri.

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

Namun, CMake menggunakan spasi putih untuk memisahkan argumen, sehingga Anda bisa mengubah spasi yang merupakan pemisah argumen menjadi baris baru di mana pun Anda suka, tanpa mengubah perilakunya.

Anda dapat menyusun ulang baris yang lebih panjang ini:

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

sebagai dua garis pendek berikut:

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

Mereka sepenuhnya setara.

DLRdave
sumber
5

Contoh pada pertanyaan awal hanya tentang string yang relatif pendek. Untuk string yang lebih panjang (termasuk contoh yang diberikan dalam jawaban lain), argumen braket bisa lebih baik. Dari dokumentasi:

Tanda kurung buka ditulis [diikuti oleh nol atau lebih =diikuti oleh [. Tanda kurung tutup yang sesuai ditulis ]diikuti dengan angka yang sama =diikuti oleh ]. Tanda kurung tidak bersarang. Panjang yang unik selalu dapat dipilih untuk tanda kurung buka dan tutup yang berisi tanda kurung tutup dengan panjang lain.

[...]

Sebagai contoh:

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
sumber
Jika saya memahami hal ini dengan benar, Pemutusan baris dalam sumber juga akan memperkenalkan pemutusan baris dalam string. Misalnya, akan ada \ n setelah "panjang 1.". Ada cara untuk menghindarinya?
Lukas Schmelzeisen
Itu benar, akan ada \ns. Jika Anda tidak menginginkannya, menurut saya argumen braket bukanlah solusi Anda.
ingomueller.net
BTW, ini berlaku untuk versi 3.x, bukan 2.x
Maxim Suslov
4

Bagi mereka yang dibawa ke sini dari Bagaimana cara membagi ekspresi generator CMake menjadi beberapa baris? Saya ingin menambahkan beberapa catatan.

Metode kelanjutan baris tidak akan berfungsi, CMake tidak dapat mengurai daftar generator yang dibuat dengan spasi (indentasi) dan kelanjutan baris.

Sementara solusi string (CONCAT) akan memberikan ekspresi generator yang dapat dievaluasi, ekspresi yang dievaluasi akan diapit oleh tanda kutip jika hasilnya berisi spasi.

Untuk setiap opsi individu yang akan ditambahkan, daftar generator terpisah harus dibuat, jadi opsi susun seperti yang telah saya lakukan berikut ini akan menyebabkan build gagal:

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

Ini karena opsi yang dihasilkan diteruskan ke kompiler dalam tanda kutip

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

Untuk mengevaluasi ekspresi generator yang panjang yang direpresentasikan menggunakan solusi string (CONCAT), setiap ekspresi generator harus mengevaluasi ke satu opsi tanpa spasi:

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

Ini mungkin tidak terkait dengan pertanyaan yang saya posting jawabannya, sayangnya pertanyaan yang saya jawab salah ditandai sebagai duplikat dari pertanyaan ini.

Daftar generator tidak ditangani dan diurai dengan cara yang sama seperti string, dan karena itu, ada tindakan tambahan yang harus diambil untuk memisahkan daftar generator menjadi beberapa baris.

Parker Gibson
sumber
Mungkin akan bermanfaat juga untuk memposting versi jawaban ini pada "duplikat" yang ditautkan. Ini adalah jawaban yang saya cari ketika saya menemukannya.
Keith Prussing
3

Untuk mempertahankan indentasi yang baik dalam kode Anda, cukup mudah dilakukan

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

Atau bentuk string langsung dengan

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

seperti dalam jawaban Douglas yang memiliki lebih banyak detail. Namun saya pikir ini mungkin hanya meringkas poin penting.

wardw
sumber