Як розділити рядки на кілька рядків у CMake?


96

У своєму проекті я зазвичай маю політику - ніколи не створювати рядки в текстових файлах, що перевищують довжину рядка 80, тому їх легко редагувати у всіх видах редакторів (ви знаєте угоду). Але з CMake у мене виникає проблема, що я не знаю, як розділити просту рядок на кілька рядків, щоб уникнути однієї величезної лінії. Розглянемо цей базовий код:

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

Це вже перевищує межу 80 рядків. Тож як я розбиваю рядок у CMake на кілька рядків, не переходячи до багатослівного (множинного list(APPEND ...)чи подібного)?

Відповіді:


88

Оновлення для CMake 3.0 та новіших версій :

продовження лінії можливо за допомогою \. див. 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.\
")

Наявність версій CMake:

Debian Wheezy (2013): 2.8.9
Debian Wheezy-бекпорти: 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 доступний через Homebrew , Macports та Fink
Windows: cmake-3 доступний через Chocolatey


20
Проблема підходу CMake 3.0 полягає в тому, що він не ігнорує відступ. Це означає, що багаторядкові рядки не можуть бути відступними від решти коду.
void.pointer

@ void.pointer Я зіткнувся з тією ж проблемою, чи ви зрозуміли, як відступити багаторядкові?
user3667089

Крім того, якщо ви хочете використовувати відступ і обмежені обмеженням 80 знаків, то інший спосіб - це зробити так: <code> message ("Це значення змінної:" <br> "$ {varValue}") </code>
мюнсінг

54

CMake 3.0 і новіші

Використовуйте string(CONCAT)команду:

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

Незважаючи на те, що CMake 3.0 і новіший рядок підтримки продовжують цитовані аргументи , ви не можете відступити другий або наступні рядки, не включивши пробіл пробілів у відступ.

CMake 2.8 та старші

Можна скористатися списком. Кожен елемент списку може бути розміщений у новому рядку:

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

Список, що використовується без лапок, об'єднується без пробілів:

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

Якщо вам дійсно потрібен рядок, спочатку можна перетворити список у рядок:

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

Будь-яка крапка з комою у вихідних рядках буде розглядатися як розділювач елементів списку та видалятися. Їх треба уникати:

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

1
Для дуже довгих рядків новий рядок після імені змінної ще більше покращує цей шаблон (непотрібний у цьому прикладі).
шавлія

З цікавості , чи було б правильним здогадуватися, що подвійні лапки в рядку також потрібно уникнути за допомогою зворотної косої риси, і тому чи роблять зворотні косої риски, які повинні відображатись як символи в рядку?
Джонатан Леффлер,

@JonathanLeffler Так, їм потрібно було б втекти. Мовні правила тут: cmake.org/cmake/help/latest/manual/…, але це стає заплутано. Дивіться також: stackoverflow.com/a/40728463
Дуглас Ройдс

9

Це все ще трохи багатослівно, але якщо обмеження 80 символів насправді вас не вражає, ви можете неодноразово додавати ту саму змінну:

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

Дає вихід:

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

7

Немає способу розділити буквений рядок на кілька рядків у файлах CMakeLists.txt або у скриптах CMake. Якщо ви включите новий рядок в рядок, в самому рядку буде буквально новий рядок.

# 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 використовує пробіл для розділення аргументів, тож ви можете змінити простір, який є роздільником аргументів, у новий рядок, де завгодно, не змінюючи поведінку.

Ви можете переформулювати цей довший рядок:

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

як ці дві короткі лінії:

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

Вони цілком рівноцінні.


5

Приклад у вихідному питанні стосується лише відносно короткого рядка. Для довших рядків (включаючи приклади, наведені в інших відповідях) аргумент у дужках може бути кращим. З документації:

Записується відкриваюча дужка, [за якою слідує нуль або більше, =після чого [. Записується відповідна закриваюча дужка, ]за якою йде така сама кількість, за =якою слідує ]. Дужки не гніздяться. Для відкриваючих і закриваючих кронштейнів завжди можна вибрати унікальну довжину, щоб містити закриваючі дужки інших довжин.

[...]

Наприклад:

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

Якщо я розумію , це правильно, LINEBREAK в джерелі буде також ввести розрив рядка в рядку. Наприклад, буде \ п після «довжини 1.». Будь-який спосіб уникнути цього?
Lukas Schmelzeisen

Це правильно, буде \ns. Якщо ви не хочете цього, я не думаю , що аргументи дужки ваше рішення.
ingomueller.net

До речі, він дійсний для версії 3.x, а не 2.x
Максим Суслов

4

Для тих, кого сюди привезли звідки я розділити вираз генератора CMake на кілька рядків? Я хотів би додати кілька приміток.

Метод продовження рядка не буде працювати, CMake не може проаналізувати список генераторів, створений з пробілами (відступи) та продовженням рядка.

У той час як рядкове (CONCAT) рішення забезпечить генераторне вираження, яке можна оцінити, оцінене вираження буде оточене лапки, якщо результат містить пробіл.

Для кожного окремого варіанту, який потрібно додати, повинен бути побудований окремий список генераторів, тому параметри стекування, як я робив у наступному, спричинять збій збій:

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

Це тому, що отримані параметри передаються компілятору в лапки

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

Для оцінки тривалих виразів генератора, представлених за допомогою рядкового (CONCAT) рішення, кожен вираз генератора повинен оцінювати до одного варіанту без пробілів:

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

Це може бути не пов'язане з питанням, на яке я публікую відповідь, на жаль, питання, на яке я відповідаю, неправильно позначено як дублікат цього питання.

Списки генераторів не обробляються та розбираються так само, як і рядки, і через це необхідно вжити додаткових заходів, щоб розділити список генераторів на кілька рядків.


Напевно, варто було б також розмістити версію цієї відповіді на пов'язаному "дублікаті". Це була відповідь, яку я шукав, коли натрапив на неї.
Кіт Пруссінг

3

Для збереження хорошого відступу у вашому коді досить просто зробити

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

Або сформуйте рядок безпосередньо з

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

як у відповіді Дугласа, хто має більше деталей. Однак я думав, що це може просто узагальнити суттєвий момент.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.