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会跳过这个条目。

只是一个标签,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()

作者:cwtxx

出处:https://www.cnblogs.com/cwtxx/p/18718164

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   cwtxx  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示