指令

指令的格式:

指令名(指令参数)
  • 指令名不区分大小写
  • 多个指令参数用空格分隔
  • 不需要在调用结束时使用分号
  • 每行源代码最多可以包含一个指令调用
  • 指令调用不是表达式,不能为调用指令提供另一个指令作为参数

变量

有三类变量:普通变量、缓存变量和环境变量。

定义变量

  • 变量名区分大小写,可以包含任何字符
  • 变量都在内部作为字符串存储
  • 基本的变量操作指令是set()和unset() 建议在变量名中只使用字母数字字符、减号(-) 和下划线(_)。

引用变量

创建对已定义变量的引用,需要使用${}语法。不同类别变量的使用:

  • ${}用于引用普通变量或缓存变量。
  • $ENV{}用于引用环境变量。
  • $CACHE{}用于引用缓存变量。

普通变量

set(MyString1 "Text1")
message(${MyString1})
unset({MyString1})

求值时CMake将遍历作用域堆栈,并将${MyString1}替换为值,若没有找到变量则替换为空字符串。这个过程称为变量求值、展开或插值。

展开是由内而外的方式执行的,CMake将重复展开过程,直到不能再展开为止。

环境变量

CMake生成环境中用于启动CMake进程的变量的副本,并使它们在单一的全局作用域中可用。查看所有环境变量:

cmake -E environment

CMake允许设置变量(set())和取消设置变量(unset()),但更改只会在运行的CMake进程中对本地副本进行,而不会对实际的系统环境进行更改。

set(ENV{CXX} "clang++")
message("generated with " $ENV{CXX})
unset(ENV{VERBOSE})

缓存变量

缓存变量是存储在构建树中的CMakeCache.txt文件中的变量,包含在项目配置阶段收集的信息,包 括从系统(到编译器、链接器、工具和其他的路径)和通过GUI从用户收集的信息。

缓存变量在脚本中不可用(因为没有CMakeCache.txt 文件),其只存在于项目中。

set(<variable> <value> CACHE <type> <docstring> [FORCE])

set(FOO "BAR" CACHE STRING "interesting value")
set(FOO "BAR" CACHE STRING "interesting value" FORCE)

变量作用域

CMake有两个作用域:

  • 函数作用域: 用于执行用function()定义的自定义函数
  • 目录作用域: 当从add_subdirectory()指令执行嵌套目录中的CMakeLists.txt文件时

当创建嵌套作用域时,CMake只需用来自当前作用域的所有变量的副本填充。后续命令将影响这些副本。但若完成了嵌套作用域的执行,所有的副本都会删除,而原始的父作用域将恢复。

控制语句

条件语句

if(<condition>)
    <commands>
elseif(<condition>)
    <commands>
else()
    <commands>
endif()

if() 条件支持NOT、AND和OR逻辑操作符:

  • NOT
  • AND
  • OR 条件的嵌套也可以通过匹配的括号(()) 来实现,CMake语言尊重求值的顺序,从最里面的括号开始。

if() 条件支持支持比较操作:EQUAL,LESS,LESS_EQUAL,GREATER 和GREATER_EQUAL。

循环语句

CMake中的循环可以使用while()或foreach()。这两个命令都支持循环控制机制:

  • break():循环停止剩余块的执行,并从封闭循环中断开。
  • continue():循环停止当前迭代的执行,并开启下一个迭代。

while

while(<condition>)
    <commands>
endwhile()

foreach

foreach(<loop_var> RANGE <max>)
    <commands>
endforeach()

foreach(<loop_var> RANGE <min> <max> [<step>])
    <commands>
endforeach()

foreach(<loop_var> IN [LISTS <lists>] [ITEMS <items>])
    <commands>
endforeach()

指令

可以使用macro()或function()定义指令。

  • function() 为本地变量创建一个单独的作用域。
  • macro()的工作方式更像是查找和替换指令,没有单独的作用域。

macro()不会在调用堆栈上创建单独的条目。所以宏中调用return()将比在函数中返回调用语句的级别高一级。

function(MyFunction Arg1 Arg2)
    <commands>
endfunction()