如何在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 ...)等)?

Answers:


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-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可通过Homebrew获得MacportsFink
Windows:可通过Chocolatey获得的cmake-3


20
CMake 3.0方法的问题在于它不会忽略缩进。这意味着多行字符串不能与其余代码缩进。
void.pointer

@ void.pointer我遇到了同样的问题,您知道如何缩进多行吗?
user3667089

另外,如果要使用缩进并且限制为80个字符,那么另一种方法是这样的:<code> message(“这是变量的值:” <br>“ $ {varValue}”)</ code>
munsingh

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
Douglas Royds '18年

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

如果我正确理解这一点,那么源代码中的换行符也会在字符串中引入换行符。例如,在“长度1”之后将有一个\ n。有什么办法避免这种情况?
卢卡斯·施梅尔吉森

没错,会有\ns。如果您不希望这样做,那么我不认为方括号参数是您的解决方案。
ingomueller.net

顺便说一句,它仅对3.x版本有效,对2.x版本无效
Maxim Suslov

4

对于那些来自的人,我如何将CMake生成器表达式拆分为多行?我想补充一些笔记。

行继续方法将不起作用,CMake无法解析使用空格(缩进)和行继续创建的生成器列表。

虽然string(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 ’

要评估使用string(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})

这可能与我要发布答案的问题无关,不幸的是,我正在回答的问题被错误地标记为该问题的重复项。

生成器列表的处理和解析方式与字符串不同,因此,必须采取其他措施才能将生成器列表分成多行。


也可以在链接的“重复项”上发布此答案的版本。这是我遇到它时要寻找的答案。
Keith Prussing

3

为了在代码中保持良好的缩进,这样做非常简单

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

或直接用

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

就像道格拉斯的答案中谁有更多细节一样。但是,我认为这可能只是要点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.