和 CMake 打交道其实就是和 CMake 命令打交道,这里作者列举了一系列最常用的命令,可以当做手册来查询,非常使用。作者详细的介绍了命令的作用和参数,又举了例子,非常贴心。
数值操作命令 math
math 命令的参数构成如下:
math (EXPR <结果变量> “<表达式字符串>” [OUTPUT_FORMAT <格式选项>])
其中的“格式选项”有两种取值,分别代码十进制(默认)和十六进制表达方式。
- HEXDECIMAL,即结果变量的数字用十六进制表示,以0x前缀开始;
- DECIMAL,即十进制表达方式,默认形式;
在 CMake 中计算数学表达式不常见,这里不举例了。
字符串操作命令 string
字符串操作命令和后面的列表、文件操作命令调用形式类似:提供一个操作名称,在提供操作的参数,就可以获得结果。
搜索字符串 FIND
string(FIND <长字符串> <短字符串> <结果变量> [REVERSE])
这个命令表示在 <长字符串> 中搜索 <短字符串> 并将 <短字符串> 第一次出现的位置存放到 <结果变量> 中。如果指定了 REVERSE 参数,则表示反向搜索。如果 <短字符串> 不存在,则结果变量的值为-1.
在这个示例中,从 “Hello, Where are you?” 字符串中搜索 “e” 出现的位置。
第一次正向搜索,”e” 出现的位置是1,结果正确。
第二次反向搜索,”e” 出现的位置是15,结果正确。注意,无论正向搜索还是反向搜索,序号都是从0开始,从前往后计算。
替换字符串 REPLACE
string(REPLACE <匹配字符串> <替换字符串> <结果变量> <输入字符串> [<输入字符串>…])
此命令会将若干个 <输入字符串> 连接在一起,将其中出现的所有 <匹配字符串> 替换为 <替换字符串>,并将最终结果存入 <结果变量>。
如下图示例中,把字符串中的 “a” 替换为 “A”,可知 REPLACE 有两个关键点:
- 字符串区分大小写;
- 拼接字符串,保留原有的空格;
正则匹配和替换
这个是重头戏。
先了解下 CMake 支持的正则表达式语法
语法结构 |
描述 |
^ |
匹配输入的起始点 |
$ |
匹配输入的终止点 |
. |
匹配任意单个字符 |
\<字符> |
匹配指定的<字符>,一般用于转义正则中的特殊字符。例如 \. 可匹配.;\\ 可匹配单个 \。 |
[] |
匹配方括号中的任意某个字符 |
[^] |
匹配任意某个不再方括号中的字符 |
- |
在方括号中表示字符区间。例如[a-c]等价于[abc] |
* |
匹配其前面的模式出现零次或者多次 |
+ |
匹配其前面的模式出现一次或者多次 |
? |
匹配其前面的模式出现零次或者一次 |
| |
匹配其两侧的模式之一 |
() |
用于声明一个子表达式,可以在字符串的正则替换命令中引用。 |
正则表达式的其他用法,参见本书作者丰富的示例。
取字符串长度 LENGTH
string(LENGTH <输入字符串> <结果变量>)
字符串变换
追加字符串 APPEND
string(APPEND <字符串变量> [<输入字符串>…])
将输入字符串依次追加到 <字符串变量> 的尾部。
前插字符串 PREPEND
string(PREPEND <字符串变量> [<输入字符串>…])
将 <输入字符串> 依次插入到 <字符串变量> 的头部。
连接字符串 CONCAT
string(CONCAT <结果变量> [<输入字符串>…])
将全部<输入字符串>拼接在一起,保存到 <结果变量> 中。
分隔符连接 JOIN
string(JOIN <分隔符> <结果变量> [<输入字符串>…])
用分隔符拼接输入字符串并保存到 <结果变量> 中。
大小写转换 TOLOWER/TOUPPER
string(TOLOWER <输入字符串> <结果变量>)
string(TOUPPER <输入字符串> <结果变量>)
重复字符串 REPEAT
string(REPEAT <输入字符串> <重复次数> <结果变量>)
取子字符串 SUBSTRING
string(SUBSTRING <输入字符串> <起始位置> <截取长度> <结果变量>)
删除首尾空白字符 STRIP
string(STRIP <输入字符串> <结果变量>)
删除生成器表达式 GENEX_STRIP
string(GENEX_STRIP <输入字符串> <结果变量>)
计算哈希值 MD5/SHA1/SHA224/…
string(<哈希算法> <结果变量> <输入字符串>)
关于字符串相关的命令,还有一些 JSON 格式的命令,获取 JSON 值,获取 JSON 元素类型,索引获取 JSON 键名等,本书作者亦做了解释并附上示例。我在使用 CMake 的经验中并没有用到 JSON 的需求,故略过。
列表
切记,列表本质上是以分好分隔的一系列字符串。
创建列表的方式
可以直接通过 set 命令创建。
上面的示例中创建了4个变量,其中 list_3 不是列表,它的长度为1.注意,在创建 list_3 是没有用分号隔开,如果隔开了就同 list_4 ,它才是列表。
访问列表元素
通过索引获取元素 GET
列表相关的命令很多都和 string 类似。
list(GET <列表变量> <元素索引> [<元素索引>…] <结果变量>)
示例中的获取列表中下标1/4的元素都成功了,但是获取下标为100的元素不存在,直接报错。注释掉第6行代码,才顺利运行。
搜索列表元素 FIND
list(FIND <列表变量> <搜索值> <结果变量>)
在列表中搜索指定的搜索值,将找到的元素的下标保存到 <结果变量> 中。如果没有找到则返回-1.
获取列表长度 LENGTH
list(LENGTH <列表变量> <结果变量>)
获取列表的长度,并保存到 <结果变量> 中。
列表搜索和获取长度的示例如下
列表元素增删
追加元素 APPEND
list(APPEND <列表变量> [<元素值>…])
前插元素 PREPEND
list(PREPEND <列表变量> [<元素值>…])
插入元素 INSERT
list(INSERT <列表变量> <插入索引> [<元素值>…])
把<元素值>插入到列表中指定查 <插入索引> 位置处。
以上三个命令的示例如下
弹出尾项元素 POP_BACK
list(POP_BACK <列表变量> [<结果变量>…])
这个命令很实用。如果没有指定 <结果变量>,该命令只会移除列表中最后一个元素;如果指定了若干个<结果变量>,该命令将会移除指定列表中位于末尾的同样数量的元素,并一次赋值给对应的结果变量。
示例如下,每次从列表弹出一个元素这个容易理解。但是如果一次弹出多个元素,需要注意弹出的元素顺序,依次保存到 <结果变量> 中。注意下面弹出 c, b 两个元素,先把 c 保存到 y1 ,再把 b 保存到 y2。而且 POP_BACK 会影响原列表变量。还需要注意,列表弹空了,多余的结果变量为空值。
弹出首项元素 POP_FRONT
list(POP_FRONT <列表变量> <[结果变量]…>
和 POP_BACK 相反,此命令从列表头部开始弹出元素
索引移除元素 REMOVE_AT
list(REMOVE_AT <列表变量> <索引> [<索引>…])
把列表中指定的索引的元素删除。
移除元素值 REMOVE_ITEM
list(REMOVE_ITEM <列表变量> <值> [<值>…]
将列表中所有值为指定的 <值> 的元素都给删除。
移除重复元素 REMOVE_DUPLICATES
list(REMOVE_DUPLICATES <列表变量>)
移除列表中所有重复的值,列表中重复出现的值仅保留首次出现的一个,其他值仍然存在于列表中,且保持原有顺序。
列表变换
列表的这些操作类似于 string() 的对应的一些命令,熟悉了字符串操作,自然从命令名字看出其功能和参数。
下面列举出一些常见的列表变换命令。
连接列表 |
List(JOIN <列表变量> <分隔字符串> <结果变量>) |
取子列表 |
List(SUBLIST <列表变量> <起始索引> <截取长度> <结果变量>) |
列表筛选 |
List(FILTER <列表变量> <INCLUDE|EXCLUDE> REGEX <正则表达式>) |
翻转列表 |
List(REVERSE <列表变量>) |
排序列表 |
List(SORT <列表变量> [COPARE <排序依据>] [CASE <大小写敏感>] [ORDER <排序方向>]) |
文件操作命令 file
file 命令用于需要访问文件系统的文件和路径操作。
对于无需访问文件系统的路径字符串语法层面的一些操作,通常使用 cmake_path 命令完成。
【题外话】file 文件操作还是很重要的,例如构建过程中需要读取 SDK 的版本号,从头文件或者制定的文件中读取,使用 CMake 内置的命令就很方便。当然也有其他工具可以完成,但是不如内置的 file 命令方便,值得深入学习 file 命令。
读取文件
读取文件内容 READ
file(READ <文件名> <结果变量> [OFFSET <偏移量>] [LIMIT <最大长度>] [HEX])
从指定的 <文件名> 读取内容保存到 <结果变量>.
上面这个例子 file(READ) 读取文件并展示文件内容,读取的文件正好是这个脚本文件自身。
计算文件哈希
file(<哈希算法> <文件名> <结果变量>)
该命令会以指定的 <哈希算法> 计算文件内容,把结果保存到 <结果变量> 中。 <哈希算法> 参数同前面 string 命令中的一样。
上面这个示例中,计算了 ch4_demo_14.cmake 文件的 MD5 和 SHA1 哈希值。
【题外话】这个命令挺有用的,有时从网上下载文件会附带文件的哈希值文件,那么就可以在 CMake 脚本中调用命令来计算文件哈希值与网站给出的哈希值比对,判断下载是否出错、文件是否被篡改。
写入文件
写文件内容 WRITE/APPEND
file([WRITE|APPEND] <文件名> <内容字符串>…)
此命令将 <内容字符串> 写入到文件。区别是如果 <文件名> 存在,WRITE 则会覆盖文件内容,而 APPEND 则在文件尾部添加内容。
遍历路径
遍历路径 GLOB
file(GLOB <结果变量>
[LIST_DIRECTORIES true|false]
[RELATIVE <父路径>]
[CONFIGURE_DEPENDS]
[<路径遍历表达式>…])
该路径会根据指定的 <路径遍历表达式> 匹配相应的文件或目录,并将他们的路径按照字典序以列表形式保存到 <结果变量>中。
【题外话】这个命令使用频率还是比较高的。在构建配置中,例如源码某个目录下源文件很多不希望一个个源文件添加到构建目标中,而是以遍历的方式查找所有源文件,这个命令就很实用。
递归遍历路径 GLOB_RECURSE
该命令与遍历路径的功能大体已知,只不过多了递归遍历的支持。
file其他命令
file 还有其他实用的命令,作者在书中详尽的解释了,而且命令从参数就可以看出用法,比较简单,这里就不演示了。
删除文件 |
File(REMOVE [<文件路径>…]) |
递归删除 |
File(REMOVE_RECURSE [<路径>…]) |
创建目录 |
File(MAKE_DIRECTORY [<目录路径>…]) |
复制文件或目录 |
File(<COPY|INSTALL> <路径>… DESTINATION <目标目录>) |
取文件大小 |
Fie(SIZE <文件名> <结果变量>) |
文件下载 |
File(DOWNLOAD <URL> [<文件路径>] [<下载选项>…]) |
文件上传 |
File(UPLOAD <文件路径> <URL> [<上传选项>…]) |
创建归档文件 |
File(ARCHIVE_CREATE OUTPUT <归档文件名>
PATHS <被归档路径>…
[FORMAT <归档文件格式>]
[COMPRESSION <压缩算法>]
[COMPRESSION_LEVEL <压缩级别>]
[MTIME <文件修改时间>]
[VERBOSE]) |
提取归档文件 |
File(ARCHIVE_EXTRACT <归档文件名>
[DESTINATION <目标提取目录>]
[LIST_ONLY]
[PATTERNS <路径遍历表达式>…]
[VERBOSE]) |
生成文件 |
File(GENERATE OUTPUT <输出文件路径>
INPUT <输入文件路径> | CONTENT <文件内容>
[CONDITION <条件表达式>]
[TARGET <构建目标>]
[NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS | FILE_PERMISSIONS <文件权限>…]
[NEWLINE_STYLE UNIX|DOS|WIN32|LF|CRLF]) |
本文来自论坛,点击查看完整帖子内容。