CMake语法
注释
单行注释使用#
,多行注释使用[=[
开始,使用]=]
结束,其中等号可以是任意数量的,但是开始和结束的等号数量必须一致。
指令
执行指令是CMake列表文件的基本功能,提供它的名称,后面跟着小括号,在小括号中可以包含一个以空格为分隔的参数列表,例如message("hello" world)
。
指令名不区分大小写,但一般约定使用小写并以下划线连接。
指令参数
在底层,CMake识别的唯一数据类型只有字符串,但是静态的字符串并不好用,所以CMake提供了三种类型的参数。
类型 | 说明 |
---|---|
方括号参数 | 方括号参数不会求值,只用于将多行字符串作为单个参数传递给命令,和多行注释一样,使用两层方括号标识。 |
引号参数 | 类似于C++中的常规字符串,同时可以支持将变量引用包装进字符串中,比如${target} 这种。 |
非引号参数 | 和引号参数差不多,都可以当作常规字符串使用,但是要小心使用; ,因为分号会被当作参数间的分隔符。 |
变量
CMake中有三类变量——普通变量、缓存变量和环境变量。
- 变量名区分大小写,可以包括任何字符
- 变量在内部都是作为字符串存储,有些时候又可以解释为其他数据类型的值
- 基本的变量操作指令是
set()
和unset()
,分别表示设置变量和取消变量。但也可以被其他指令影响,比如string()
和list()
。
变量引用
通过$符号和大括号来使用变量引用。比如
1 | set(name "xiaoming") |
打印出来的就是字符串"xiaoming"。
CMake会将${}
包裹的内容查找其对应的字符串,然后做简单的替换,并且可以支持嵌套,例如
1 | set(MyInner "hello") |
输出的是"Hello World",首先将MyOuter替换成"${My",然后"${My"和"Inner}“组成了”${MyInner}",又被替换成了Hello,所以最终打印的是Hello World。
当涉及到变量类型时,
- ${}用于引用普通变量和缓存变量。
- $ENV{}用于引用环境变量
- $CACHE{}用于引用缓存变量。
设置环境变量时也需要添加"ENV"关键字,比如set(ENV{CXX} "clang++")
。设置的环境变量只会影响CMake的项目配置,不会真正改变系统变量。
缓存变量会保存在CMakeCache.txt文件中,包含在项目配置阶段收集的信息,比如编译器的路径、链接器的路径、GUI中用户设置的信息。
缓存变量的设置有些复杂,
1 | set(<variable> <value> CACHE <type> <docstring> [FORCE]) |
缓存变量因为需要能够配置,GUI需要知道如何显示它,所以要求提供
- BOOL: 布尔值,GUI上显示为一个复选框
- FILEPATH: 磁盘上的文件路径,GUI将打开一个文件对话框
- STRING: 字符串,GUI通过一个下拉菜单选择替换
- INTERNAL: 一行字符串,GUI会跳过这个条目。
变量的作用域
CMake有两个作用域
- 函数作用域:用于执行function()定义的自定义函数。
- 目录作用域:当从add_subdirectory()指令执行嵌套目录中的CMakeLists.txt文件时。
当创建嵌套作用域时,CMake只用当前作用域的所有变量的副本填充,然后在退出嵌套的作用域时会删除副本,而原始的父作用域恢复。也就是说,在子作用域中即使使用unset
取消了父作用域中的变量,其实也只是取消了其副本,父作用域中的变量不会受到影响。如果确实想要取消或设置父作用域中的变量,需要在后面加上关键字,set(parent_value "new value" PARENT_SCOPE)
,不过需要注意的是这样设置的是父作用域中的变量,而当前作用域中的变量不会被修改。
列表
当set
的变量后有多个参数时,这个变量就是一个列表了,例如set(MyList 1 2 3 4 5)
就是一个有5个元素的列表。
CMake还提供了list
指令来操作列表。
1 | # 部分用法 |
控制结构
CMake中也有条件块、循环和自定义指令。
条件块
CMake中的条件块必须使用endif()
来关闭,可以有任意数量的elseif()
和一个可选的else()
,顺序如下
1 | if(<condition>) |
判断的条件支持NOT,AND和OR逻辑运算符,当然条件也可以是一个变量,不过如果是变量引用的话,其值为ON、Y、YES、TRUE或者一个非零的数才会判断为真。而如果是一个没有加引用的裸变量,将会判断其值为OFF,NO,FALSE,N,IGNORE,NOTFOUND,以-NOTFOUND结尾的字符串,空字符串或者零的其中一个时(不区分大小写),条件才为false。
另外还可以通过EQUAL,LESS,LESS_EQUAL,GREATER和GREATER_EQUAL来进行比较判断。
循环
CMake支持while()
和foreach()
两种循环指令。break()
可以停止循环并跳出,continue()
会跳过当前循环执行下次循环。
同样的,也需要end来指明循环的范围。
1 | while(<condition>) |
CMake 将为每个提供的列表创建一个 num_<N> 变量,用每个列表中的项填充该变量。可以传递多个 <loop_var> 变量名 (每个列表一个),每个列表将使用单独的变量来存储。
定义指令
CMake可以通过macro()
和function()
来自定义指令,类似于写一个自己的函数,其中macro()
类似于宏,只是执行简单的替换,而fuction()
类似于调用一个函数,并会创建一个自身的作用域。
这两个指令都允许传递参数,CMake中允许通过下列引用来访问命令调用中传递的参数:
${ARGC}
: 参数的数量${ARGV}
: 所有参数的列表${ARG0}
,${ARG1}
: 特定索引处的实参值
1 | macro(<name> [<argument>...]) |