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

时间:2015-06-24 22:00:30

标签: cmake

下次我使用CMake时,我会问这个提醒自己。它永远不会坚持,谷歌的结果也不是很好。

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

3 个答案:

答案 0 :(得分:206)

在编写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())。< / LI>
  • add_subdirectory()function()命令很特殊,因为它们打开了自己的范围。
    • 含义变量set(...)只有在那里可见,它们会复制调用它们的范围级别的所有正常变量(称为父范围)。
    • 因此,如果您在子目录或函数中,则可以使用set(... PARENT_SCOPE)
    • 修改父作用域中已存在的变量
    • 你可以利用这个,例如通过将变量名称作为函数参数传递给函数。一个例子是function(xyz _resultVar)正在设置set(${_resultVar} 1 PARENT_SCOPE)
  • 另一方面,您在include()macro()脚本中设置的所有内容都将直接在调用它们的范围内修改变量。

其次是&#34;全局变量缓存&#34;。您需要了解的有关缓存的事项:

  • 如果在当前范围内没有定义具有给定名称的普通变量,CMake将查找匹配的Cache条目。
  • 缓存值存储在二进制输出目录的CMakeCache.txt文件中。
  • 可以在CMake's GUI应用程序中修改Cache中的值,然后再生成它们。因此,与正常变量相比,它们具有typedocstring。我通常不使用GUI,因此我使用set(... CACHE INTERNAL "")来设置我的全局和持久值。

    请注意,INTERNAL缓存变量类型确实意味着FORCE

  • 在CMake脚本中,如果使用set(... CACHE ... FORCE)语法,则只能更改现有的缓存条目。这种行为是利用例如由CMake本身,因为它通常不会强制缓存条目本身,因此您可以使用其他值预先定义它。

  • 您可以使用命令行使用语法cmake -D var:type=valuecmake -D var=valuecmake -C CMakeInitialCache.cmake设置缓存中的条目。
  • 您可以使用unset(... CACHE)
  • 在缓存中unset个条目

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

可变陷阱和&#34;如何调试变量?&#34;

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

  • 如果两者具有相同的名称,则本地变量会隐藏缓存的变量
  • find_...命令 - 如果成功 - 将结果写为缓存变量&#34;这样任何呼叫都不会再次搜索&#34;
  • Lists in CMake are just strings with semicolons delimiters因此引号很重要
    • set(MyVar a b c)"a;b;c"set(MyVar "a b c")"a b c"
    • 建议您在列表清单时始终使用带引号的引号
    • 通常更喜欢list()命令来处理列表
  • 上述整个范围问题。特别推荐使用functions()代替macros(),因为您不希望局部变量显示在父范围内。
  • CMake使用的很多变量都是通过project()enable_language()调用设置的。因此,在使用这些命令之前设置一些变量可能很重要。
  • 环境变量可能与CMake生成make环境的位置以及make文件的使用时间不同。
    • 环境变量的更改不会重新触发生成过程。
    • 特别是生成的IDE环境可能与命令行不同,因此建议将环境变量转换为缓存的内容。

有时只有调试变量才有帮助。以下内容可以为您提供帮助:

  • 使用printf命令简单地使用旧message()调试样式。还有一些随时可以使用CMake自带的模块:CMakePrintHelpers.cmakeCMakePrintSystemInformation.cmake
  • 查看二进制输出目录中的CMakeCache.txt文件。如果生成环境的实际生成失败,则甚至会生成此文件。
  • 使用variable_watch()查看您的变量的读/写/删除位置。
  • 查看目录属性CACHE_VARIABLESVARIABLES
  • 致电cmake --trace ...以查看CMake的完整解析过程。这是最后一次保留,因为它产生了大量的输出。

特殊语法

  • 环境变量
    • 您可以阅读$ENV{...}并撰写set(ENV{...} ...)环境变量
  • 生成器表达式
    • 生成器表达式$<...>仅在CMake的生成器写入make环境时进行评估(它与被替换的正常变量进行比较&#34;就地#34;由解析器进行比较)
    • 非常方便,例如在编译器/链接器命令行和多配置环境中
  • 参考
    • 使用${${...}},您可以在变量中提供变量名称并引用其内容。
    • 在将变量名称作为函数/宏参数提供时经常使用。
  • 常量值(请参阅if()命令)
    • 使用if(MyVariable),您可以直接检查变量是否为true / false(此处不需要封闭${...}
    • 如果常量为1ONYESTRUEY或非零数字,则为真。
    • 如果常量为0OFFNOFALSENIGNORENOTFOUND,则为假空字符串,或以后缀-NOTFOUND结尾。
    • 此语法通常用于if(MSVC)之类的内容,但对于不知道此语法快捷方式的人来说,这可能会让人感到困惑。
  • 递归替换
    • 您可以使用变量构造变量名称。在CMake替换变量之后,它将再次检查结果是否是变量本身。这是CMake本身使用的非常强大的功能,例如作为一种模板set(CMAKE_${lang}_COMPILER ...)
    • 要注意这会让您在if()命令中感到头痛。以下是CMAKE_CXX_COMPILER_ID"MSVC"MSVC"1"的示例:
      • if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")为真,因为它的评估结果为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)设置为&#34;仅在不加引号时将if()参数解释为变量或关键字。&#34;
  • option()命令
    • 主要是缓存的字符串,只能是ONOFF,并且它们允许一些特殊处理,例如dependencies
    • 要注意,不要将optionset命令混淆。给option的值实际上只是&#34;初始值&#34; (在第一个配置步骤中将一次转移到缓存中),然后由用户通过CMake's GUI进行更改。

参考

答案 1 :(得分:11)

以下是一些快速而简单的基本示例。

一个项目变量

设置变量:

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 docs on variables

答案 2 :(得分:0)

$ENV{FOO}用于使用,其中FOO是从环境变量中获取的。否则使用${FOO},其中FOO是其他变量。对于设置,SET(FOO "foo")将用于cmake。

相关问题