如何在CMake中跨多行拆分字符串?

Luk*_*sen 85 cmake

我通常在我的项目中有一个策略,永远不会在超过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}")
Run Code Online (Sandbox Code Playgroud)

它已经超过了80行限制.那么如何将CMake中的一行分成多行而不会变得冗长(多个list(APPEND ...)等)?

Hot*_*hke 80

更新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.\
")
Run Code Online (Sandbox Code Playgroud)

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

  • CMake 3.0方法的问题在于它不会忽略缩进.这意味着多行字符串不能与其余代码一起缩进. (14认同)

Dou*_*yds 50

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}")
Run Code Online (Sandbox Code Playgroud)

虽然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}")
Run Code Online (Sandbox Code Playgroud)

使用不带引号的列表连接在一起,没有空格:

message(STATUS "Version: " ${MYPROJ_VERSION_LIST})
-- Version: 1.0.0-rc1
Run Code Online (Sandbox Code Playgroud)

如果您确实需要一个字符串,可以先将列表转换为字符串:

string(REPLACE ";" "" MYPROJ_VERSION "${MYPROJ_VERSION_LIST}")
message(STATUS "Version: ${MYPROJ_VERSION}")
-- Version: 1.0.0-rc1
Run Code Online (Sandbox Code Playgroud)

原始字符串中的任何分号都将被视为列表元素分隔符,并被删除.他们必须逃脱:

set(MY_LIST "Hello World "
            "with a \;semicolon")
Run Code Online (Sandbox Code Playgroud)


Ria*_*son 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}")
Run Code Online (Sandbox Code Playgroud)

给出输出:

$ cmake  ~/project/tmp
-- version: 1.0.0-rc1
-- Configuring done
-- Generating done
-- Build files have been written to: /home/rsanderson/build/temp
Run Code Online (Sandbox Code Playgroud)


DLR*_*ave 8

无法在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}")
Run Code Online (Sandbox Code Playgroud)

但是,CMake使用空格来分隔参数,因此您可以在任何位置将参数分隔符的空格更改为换行符,而不会更改行为.

你可以重新说这个更长的行:

set(MYPROJ_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")
Run Code Online (Sandbox Code Playgroud)

作为这两条较短的线:

set(MYPROJ_VERSION
  "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}-${VERSION_EXTRA}")
Run Code Online (Sandbox Code Playgroud)

它们完全相同.


ing*_*net 8

原始问题中的示例只是关于一个相对较短的字符串。对于更长的字符串(包括其他答案中给出的示例),括号参数可能更好。从文档:

左括号写为[后跟零个或多个,=后跟[. 相应的右括号被写入],随后由相同数量的=后跟]。括号不嵌套。始终可以为左括号和右括号选择唯一的长度以包含其他长度的右括号。

[...]

例如:

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.
]=])```
Run Code Online (Sandbox Code Playgroud)


小智 8

对于那些从如何将 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})
Run Code Online (Sandbox Code Playgroud)

这是因为结果选项在引号中传递给编译器

/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 ’
Run Code Online (Sandbox Code Playgroud)

要计算使用 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})
Run Code Online (Sandbox Code Playgroud)

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

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

  • 在链接的“重复”上发布这个答案的一个版本可能也是值得的。当我遇到这个问题时,这就是我正在寻找的答案。 (2认同)

war*_*rdw 5

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

message("These strings " "will all be "
        "concatenated. Don't forget "
        "your trailing spaces!")
Run Code Online (Sandbox Code Playgroud)

或者直接用

string(CONCAT MYSTR "This and " "that "
                    "and me too!")
Run Code Online (Sandbox Code Playgroud)

就像道格拉斯的回答一样,他有更多细节。但是我认为这可能只是总结了要点。