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

ujv3wf0j  于 2022-11-11  发布在  其他
关注(0)|答案(7)|浏览(301)

我在项目中通常有一个策略,就是永远不要在文本文件中创建超过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 ...)或类似的内容)呢?

hujrc8aj

hujrc8aj1#

CMake 3.0及更高版本的更新:

使用\可以进行行续行。请参阅最新的cmake文档

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气喘吁吁(2013):2.8.9
Debian气喘吁吁的backports:2.8.11
Debian杰西(2015):3.0.2
Ubuntu 14.04(LTS):2.8.12
Ubuntu 15.04版:3.0.2
Mac OS X:通过HomebrewMacportsFink提供cmake-3
Windows:可通过Chocolatey使用cmake-3

exdqitrt

exdqitrt2#

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

lokaqttq3#

对于那些从How do I split a CMake generator expression to multiple lines?被带到这里的人,我想补充一些注意事项。
行继续符方法将不起作用,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})

这可能与我正在张贴答案的问题无关,不幸的是,我正在回答的问题被错误地标记为此问题的重复。
生成器列表的处理和解析方式与字符串不同,因此,必须采取额外的措施将生成器列表拆分为多行。

svgewumm

svgewumm4#

这仍然有点冗长,但是如果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
rta7y2nd

rta7y2nd5#

原始问题中的示例只是关于一个相对较短的字符串。对于较长的字符串(包括其他答案中给出的示例),括号参数可能更好。请参阅文档:
一个左括号写为[,后面跟着零个或多个=,后面跟着[。相应的右括号写为],后面跟着相同数目的=,后面跟着]。括号不嵌套。左括号和右括号总是可以选择唯一的长度,以包含其他长度的右括号。
[...]
例如:

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

3hvapo4f6#

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

它们完全等同。

pprl5pva

pprl5pva7#

要在代码中保持良好的缩进,只需简单地执行以下操作

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

或直接与

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

正如在Douglas' answer谁有更多的细节。不过,我认为这可能只是总结了基本点。

相关问题