CMake语法
注释#
单行注释使用#
,多行注释使用[=[
开始,使用]=]
结束,其中等号可以是任意数量的,但是开始和结束的等号数量必须一致。
指令#
执行指令是CMake列表文件的基本功能,提供它的名称,后面跟着小括号,在小括号中可以包含一个以空格为分隔的参数列表,例如message("hello" world)
。
指令名不区分大小写,但一般约定使用小写并以下划线连接。
指令参数#
在底层,CMake识别的唯一数据类型只有字符串,但是静态的字符串并不好用,所以CMake提供了三种类型的参数。
类型 | 说明 |
---|---|
方括号参数 | 方括号参数不会求值,只用于将多行字符串作为单个参数传递给命令,和多行注释一样,使用两层方括号标识。 |
引号参数 | 类似于C++中的常规字符串,同时可以支持将变量引用包装进字符串中,比如${target} 这种。 |
非引号参数 | 和引号参数差不多,都可以当作常规字符串使用,但是要小心使用; ,因为分号会被当作参数间的分隔符。 |
变量#
CMake中有三类变量——普通变量、缓存变量和环境变量。
- 变量名区分大小写,可以包括任何字符
- 变量在内部都是作为字符串存储,有些时候又可以解释为其他数据类型的值
- 基本的变量操作指令是
set()
和unset()
,分别表示设置变量和取消变量。但也可以被其他指令影响,比如string()
和list()
。
变量引用#
通过$符号和大括号来使用变量引用。比如
set(name "xiaoming")
message(STATUS ${name})
打印出来的就是字符串"xiaoming"。
CMake会将${}
包裹的内容查找其对应的字符串,然后做简单的替换,并且可以支持嵌套,例如
set(MyInner "hello")
set(MyOuter "${My")
message("${MyOuter}Inner} World")
输出的是"Hello World",首先将MyOuter替换成"${My",然后"${My"和"Inner}"组成了"${MyInner}",又被替换成了Hello,所以最终打印的是Hello World。
当涉及到变量类型时,
- ${}用于引用普通变量和缓存变量。
- $ENV{}用于引用环境变量
- $CACHE{}用于引用缓存变量。
设置环境变量时也需要添加"ENV"关键字,比如set(ENV{CXX} "clang++")
。设置的环境变量只会影响CMake的项目配置,不会真正改变系统变量。
缓存变量会保存在CMakeCache.txt文件中,包含在项目配置阶段收集的信息,比如编译器的路径、链接器的路径、GUI中用户设置的信息。
缓存变量的设置有些复杂,
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
指令来操作列表。
# 部分用法
list(LENGTH <list> <out_var>)
list(GET <list> <element index> [<index> ...] <out_var>)
list(JOIN <list> <glue> <out_var>)
list(SUBLIST <list> <begin> <length> <out_var>)
list(FIND <list> <value> <out-var>)
list(APPEND <list> [<element> ...])
list(FILTER <list> {INCLUDE | EXCLUDE} REGEX <regex>)
list(INSERT <list> <index> [<element> ...])
list(POP_BACK <list> [<out-var> ...])
list(POP_FRONT <list> [<out-var> ...])
list(PREPEND <list> [<element> ...])
list(REMOVE_ITEM <list> <value>...)
list(REMOVE_AT <list> <index>...)
list(REMOVE_DUPLICATES <list>)
list(TRANSFORM <list> <ACTION> [...])
list(REVERSE <list>)
list(SORT <list> [...])
控制结构#
CMake中也有条件块、循环和自定义指令。
条件块#
CMake中的条件块必须使用endif()
来关闭,可以有任意数量的elseif()
和一个可选的else()
,顺序如下
if(<condition>)
<commands>
elseif(<condition>)
<commands>
else()
<commands>
endif()
判断的条件支持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来指明循环的范围。
while(<condition>)
<commands>
endwhile()
foreach(<loop_var> RANGE <max>)
<commands>
endforeach()
foreach(VAR 1 2 3 4 5)
<commands>
endforeach()
set(L1 "one;two;three;four")
set(L2 "1;2;3;4;5")
foreach(num IN ZIP_LISTS L1 L2)
message("num_0=${num_0}, num_1=${num_1}")
endforeach()
foreach(word num IN ZIP_LISTS L1 L2)
message("word=${word}, num=${num}")
endforeach()
CMake 将为每个提供的列表创建一个 num_<N> 变量,用每个列表中的项填充该变量。可以传递多个 <loop_var> 变量名 (每个列表一个),每个列表将使用单独的变量来存储。
定义指令#
CMake可以通过macro()
和function()
来自定义指令,类似于写一个自己的函数,其中macro()
类似于宏,只是执行简单的替换,而fuction()
类似于调用一个函数,并会创建一个自身的作用域。
这两个指令都允许传递参数,CMake中允许通过下列引用来访问命令调用中传递的参数:
${ARGC}
: 参数的数量${ARGV}
: 所有参数的列表${ARG0}
,${ARG1}
: 特定索引处的实参值
macro(<name> [<argument>...])
<commands>
endmacro()
function(<name> [<argument>...])
<commands>
endfunction()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南