设置和使用变量的CMake语法是什么?

v8wbuo2f  于 2022-11-11  发布在  其他
关注(0)|答案(3)|浏览(174)

我问这个问题是为了提醒我自己下次使用CMake。它从来没有坚持下来,谷歌的结果也不好。
在CMake中设置和使用变量的语法是什么?

nhaq1z21

nhaq1z211#

在编写CMake脚本时,您需要了解很多有关语法以及如何在CMake中使用变量的知识。

语法

使用set()的字符串:

  • set(MyString "Some Text")
  • set(MyStringWithVar "Some other Text: ${MyString}")
  • set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")

或者使用string()

  • string(APPEND MyStringWithContent " ${MyString}")

使用set()的列表:

  • set(MyList "a" "b" "c")
  • set(MyList ${MyList} "d")

或者更好地使用list()

  • list(APPEND MyList "a" "b" "c")
  • list(APPEND MyList "d")

文件名列表:

  • set(MySourcesList "File.name" "File with Space.name")
  • list(APPEND MySourcesList "File.name" "File with Space.name")
  • add_excutable(MyExeTarget ${MySourcesList})

文档

范围或“我的变量有什么值?”

首先是“常规变量”以及您需要了解的有关其作用域的信息:

  • 普通变量对设置它们的CMakeLists.txt和从那里调用的所有内容(add_subdirectory()include()macro()function())都是可见的。
  • add_subdirectory()function()命令很特殊,因为它们打开了自己的作用域。
  • 这意味着变量set(...)只在那里可见,并且它们复制了调用它们的作用域级别(称为父作用域)的所有普通变量。
  • 因此,如果您在子目录或函数中,则可以使用set(... PARENT_SCOPE)修改父作用域中已经存在的变量
  • 您可以在函数中使用此功能,例如将变量名作为函数参数传递。例如function(xyz _resultVar) is setting set(${_resultVar} 1 PARENT_SCOPE)
  • 另一方面,您在include()macro()脚本中设置的所有内容都将直接在调用变量的作用域中修改变量。

第二个是“全局变量缓存”。关于该高速缓存你需要知道的事情:

  • 如果在当前作用域中没有定义具有给定名称的常规变量,CMake将查找匹配的缓存条目。
  • 高速缓存值存储在二进制输出目录中的CMakeCache.txt文件中。
  • 该高速缓存中的值在生成之前可以在CMake's GUI应用程序中修改。因此,与普通变量相比,它们有一个type和一个docstring。我通常不使用GUI,所以我使用set(... CACHE INTERNAL "")来设置我的全局值和持久值。
  • 请注意,INTERNAL缓存变量类型不隐含FORCE *
  • 在CMake脚本中,如果使用set(... CACHE ... FORCE)语法,您只能更改现有的缓存条目。例如,CMake本身使用此行为,因为它通常不会强制缓存条目本身,因此您可以使用另一个值预定义它。
  • 您可以使用命令行,通过语法cmake -D var:type=value、仅cmake -D var=valuecmake -C CMakeInitialCache.cmake来设置该高速缓存中的条目。
  • 您可以使用unset(... CACHE)unset该高速缓存中的项目。

该高速缓存是全局的,你可以在CMake脚本中的任何地方设置它们。但是我建议你在使用Cache变量的时候三思而后行(它们是全局的,也是持久的)。我通常更喜欢用set_property(GLOBAL PROPERTY ...)set_property(GLOBAL APPEND PROPERTY ...)语法来定义我自己的非持久全局变量。

变量陷阱和“如何调试变量更改?”

为了避免陷阱,您应该了解以下有关变量的信息:

  • 如果本地变量和缓存变量具有相同的名称,则本地变量会隐藏缓存变量
  • find_...命令-如果成功-将其结果作为缓存变量写入,“这样就不会有调用再次搜索”
  • 因此引号很重要
  • set(MyVar a b c)"a;b;c",而set(MyVar "a b c")"a b c"
  • 建议您始终使用引号,但当您要将列表给予为list时,有一个例外
  • 通常首选list()命令来处理列表
  • 上面描述的整个作用域问题。特别推荐使用functions()而不是macros(),因为你不希望你的局部变量出现在父作用域中。
  • CMake使用的很多变量都是通过project()enable_language()调用设置的。因此,在使用这些命令之前设置一些变量可能很重要。
  • 环境变量可能与CMake生成make环境的位置以及make文件的使用时间不同。
  • 环境变量中的更改不会重新触发生成过程。
  • 特别是生成的IDE环境可能与您的命令行不同,因此建议将环境变量传输到缓存中。

有时只有调试变量才有帮助。以下内容可能会对您有所帮助:

  • 只需使用message()命令使用旧的printf调试风格即可。CMake本身附带了一些现成的模块:CMakePrintHelpers.cmakeCMakePrintSystemInformation.cmake
  • 查看二进制输出目录中的CMakeCache.txt文件。即使make环境的实际生成失败,也会生成此文件。
  • 使用variable_watch()查看变量的读/写/删除位置。
  • 查看目录属性CACHE_VARIABLESVARIABLES
  • 调用cmake --trace ...来查看CMake的完整解析过程,这是最后一个保留,因为它会生成大量输出。

特殊语法

  • 环境变量

  • 您可以读取$ENV{...}和写入set(ENV{...} ...)环境变量

  • 生成器表达式

  • 生成器表达式$<...>仅在CMake的生成器写入make环境时才被求值(它与被解析器“就地”替换的普通变量相比)

  • 非常方便,例如在编译器/链接器命令行和多配置环境中

  • 参考文献

  • 使用${${...}}可以在变量中给予变量名并引用其内容。

  • 通常在将变量名作为函数/宏参数时使用。

  • 常数值(请参阅if()指令)

  • 使用if(MyVariable),您可以直接检查变量的true/false(这里不需要使用封闭的${...}

  • 如果常数是1ONYESTRUEY或非零的数字,则为True。

  • 如果常数为0OFFNOFALSENIGNORENOTFOUND、空字串,或以后置字符-NOTFOUND结尾,则传回False。

  • 此语法通常用于if(MSVC)之类的内容,但对于不了解此语法快捷方式的人来说,可能会感到困惑。

  • 递归替换

  • 您可以使用变量构造变量名。CMake替换变量后,它会再次检查结果是否是变量本身。这是CMake本身使用的非常强大的功能,例如作为模板set(CMAKE_${lang}_COMPILER ...)

  • 但是,* 请注意 *,在if()命令中,这会给予您感到头疼。下面是一个示例,其中CMAKE_CXX_COMPILER_ID"MSVC"MSVC"1"

  • if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")为true,因为它的计算结果为if("1" STREQUAL "1")

  • if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")为false,因为它的计算结果为if("MSVC" STREQUAL "1")

  • 因此,这里最好的解决方案是(参见上文)直接检查if(MSVC)

  • 好消息是这个问题在CMake 3.1中通过引入policy CMP0054得到了解决。我建议总是将cmake_policy(SET CMP0054 NEW)设置为“仅在不加引号时将if()参数解释为变量或关键字”。

  • option()命令

  • 主要是缓存只能是ONOFF的字符串,它们允许一些特殊处理,例如dependencies

  • 但是 * 请注意 *,不要将optionset命令混淆。option的值实际上只是“初始值”(在第一个配置步骤中传输到该高速缓存一次),之后将由用户通过CMake's GUI进行更改。

参考

wr98u20j

wr98u20j2#

这里有几个基本的例子,让你快速入门。

一个项目变量

设置变量:

SET(INSTALL_ETC_DIR "etc")

使用变量:

SET(INSTALL_ETC_CROND_DIR "${INSTALL_ETC_DIR}/cron.d")

多项变量(即列表)

设置变量:

SET(PROGRAM_SRCS
        program.c
        program_utils.c
        a_lib.c
        b_lib.c
        config.c
        )

使用变量:

add_executable(program "${PROGRAM_SRCS}")

CMake变量文档

jc3wubiy

jc3wubiy3#

$ENV{FOO}以取得使用方式,其中FOO是从环境变量取得的。否则使用为${FOO},其中FOO是其他变数。若要设定,SET(FOO "foo")会在CMake中使用。

相关问题