DDZZ669 发表于 2024-10-1 17:29

CMake构建实战读书笔记03-CMake常用命令

CMake提供了很多很多命令,这么命令可以先做个大致了解,在需要用到的时候,可以单独研究完整的用法细节。

# 1 数值操作命令math

数值操作,即进行算术运算,CMake中不能直接使用运算符运算,需要通过math这个指令来实现运算,例如:

```cmake
math(EXPR a 10*10 OUTPUT_FORMAT DECIMAL) #计算10*10
math(EXPR b "16" OUTPUT_FORMAT HEXADECIMAL) #数字16转为Hex格式
```



# 2 字符串操作命令string

list类似于C++中的字符串,下面介绍它的相关指令

## 2.1 搜索和替换

测试代码:

- 找出aba字符串中第一个a的位置
- 反向找出aba字符串中第一个a的位置
- 找出aba字符串中第一个c的位置

```cmake
string(FIND aba a res)
message("${res}")

string(FIND aba a res REVERSE)
message("${res}")

string(FIND aba cres)
message("${res}")
```

运行结果如下:



## 2.2 正则匹配和替换

CMake中也支持正则表达式。

测试代码如下:

- 定义一个正则表达式"+",表示匹配a、b、c中的任意字符,并且可匹配多次
- 依次测试各个字符串是否满足匹配规则,匹配则会输出

```cmake
set(regex "+")

string(REGEX MATCH ${regex} res aaa)
message("${res}")

string(REGEX MATCH ${regex} res aaa bbb ccc abc)
message("${res}")

string(REGEX MATCH ${regex} res aaad)
message("${res}")
```



## 2.3 取字符串长度

这个比较容易理解,就是获取字符串的长度

```cmake
string(LENGTH "abcde" res)
message("${res}")
```



## 2.4 字符串变换

CONCAT可用于将字符串连接起来

```cmake
set(res "123")
string(CONCAT res a b c)
message("${res}")
```



## 2.5 比较字符串

COMPARE可用于比较字符串,按照字典顺序比较

```cmake
string(COMPARE LESS a abc res)
message("${res}")

string(COMPARE GREATER a abc res)
message("${res}")
```





## 2.6 取哈希值

MD5可以获取字符串的哈希值

```cmake
string(MD5 res "abcde")
message("${res}")
```



## 2.7 字符串生成

ASCII可将对应的ASCII值转换为对应的字符展示

```cmake
string(ASCII 65 66 67 res)
message("${res}")

string(ASCII 228 189 160 res)
message("${res}")
```



## 2.8 字符串模板

template_define.cmake

```cmake
set(template [=[
替换变量a: ${a}
替换变量b: @b@

定义宏C
#cmakedefine C

定义0/1宏D
#cmakedefine01 C

定义值e的宏E
#cmakedefine E e

定义值为F的变量的值的宏E
#cmakedefine F @F@
]=])
```

test8_1.cmake

```cmake
include(template_define.cmake)

set(a "a的值")
set(b "b的值")
set(C "C的值")
set(D "D的值")
set(E "E的值")
set(F "F的值")

string(CONFIGURE ${template} res)
message("${res}")
```

运行结果如下



# 3 列表操作命令list

list类似于C++中的列表,下面介绍它的相关指令

## 3.1 列表

列表可以通过set命令来创建,通过分号来分隔元素

```cmake
set(x "a;b;c")

foreach(i 0 1 2 -1 -2 -3)
        list(GET x ${i} res)
        message("x[${i}] = ${res}")
endforeach()
```

结果如下:



## 3.2 访问列表元素

通过GET可以获取列表中指定索引的元素,例如,访问第0个,以及访问第0个和第2个

```cmake
set(x "a;b;c")

list(GET x 0 res)
message("${res}")

list(GET x 0 2 res)
message("${res}")
```



## 3.3 获取列表长度

获取长度,也比较好理解

```cmake
set(x a;b;c)
list(LENGTH x res)
message("${res}")
```



## 3.4 列表元素增删

通过INSERT,可以在指定索引位置之后插入元素到列表中,可一次插入多个元素

```cmake
set(x "a;d;e")
list(INSERT x 1 b c)
message("${x}")
```



## 3.5 列表变换

通过JOIN可以实现列表元素的连接,该命令于string中的连接功能类似

```cmake
set(x "a;b;c")
list(JOIN x "-" res)
message("${res}")

string(JOIN "-" res ${x})
message("${res}")
```



## 3.6 列表重排

通过SORT可实现列表中元素的排序

```cmake
set(x "a;b;c;D;e")
list(SORT x)
message("${x}")
```



## 3.7 列表元素变换

通过TRANSFORM,可以实现在元素之前或之后添加自定义的字符串,例如,给每个元素加上括号的代码如下

```cmake
set(x "x a b c d e")
list(TRANSFORM x PREPEND "(")
list(TRANSFORM x AEPEND ")")
message("${x}")
```



# 4 文件操作命令file

文件操作命令的内容有很多,这里仅介绍下文件的读取和遍历

## 4.1 读取文件

读取文件中的内容,可以指定读取的长度

```cmake
file(READ example.txt res)
message("${res}")

file(READ example.txt res LIMIT 6)
message("${res}")
```



## 4.2 遍历路径

可以遍历指定目录下的文件

```cmake
file(GLOB res
        RELATIVE "${CMAKE_CURRNT_LIST_DIR}"
        *)
message("${res}")
```



# 5 路径操作命令cmake_path

追加路径

```cmake
cmake_path(APPEND res a b c)
message("${res}")

cmake_path(APPEND_STRING res a b c)
message("${res}")

cmake_path(APPEND res d e)
message("${res}")
```

cmake_path指令需要CMake3.20以上的版本,否则会提示不支持cmake_path指令





# 6 路径操作命令get_filename_component

get_filename_component命令也用于路径相关的操作,但其绝大多数功能已被cmake_path命令取代

```cmake
function(f mode)
        get_filename_component(res "a/b.c.txt" ${mode})
        message("${res}")
endfunction()

f(DIRECTORY)
f(NAME)
f(EXT)
f(NAME_WE)
f(LIST_EXT)
f(NAME_WLE)
```



# 7 配置模板文件configure_file

test471.cmake

```cmake
set(a "a的值")
set(b "b的值")
set(C "C的值")
set(D "D的值")
set(E "E的值")
set(F "F的值")

configure_file(template.h.in res1.h)
configure_file(template.h.in res2.h @ONLY)
configure_file(template.h.in res3.h COPYONLY)
```

template.h.in

```cmake
// 替换变量a:${a}
// 替换变量b:@b@
// 定义宏C
#cmakedefine C
// 定义0/1宏D
#cmakedefine01 D
// 定义值为e的宏E
#cmakedefine E e
// 定义值为F变量的值的宏F
#cmakedefine F @F @
```



# 8 日志输出命令message

类似与C/C++中的printf,用来输出信息。

```cmake
message("hello")

message(WARNING "一般警告")
message(AUTHOR_WARNING "开发警告")

message(SEND_ERROR "一般错误")
message(FATAL_ERROE "致命错误")

message("这条消息不会被输出")
```

除了基础的打印功能,还可以输出不同级别的警告和错误



FATAL_ERROE这种错误输出后,程序应该会退出的,但实际最后一句的输出也打印了出来,没看出哪里问题。

# 9 执行程序execute_process

创建一个脚本,execute_process使其输出两次变量text的值,并且第2次要延迟1s再输出

delay_message.cmake

```cmake
message("${text}")
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 1)
message("${text}")
```

创建另一个脚本,通过execute_process可以并行执行上述的脚本

test491.cmake

```cmake
execute_process(
        COMMAND ${CMAKE_COMMAND} -Dtext=1 -P delay_message.cmake
        COMMAND ${CMAKE_COMMAND} -Dtext=2 -P delay_message.cmake
        COMMAND ${CMAKE_COMMAND} -Dtext=3 -P delay_message.cmake
)
```





# 10 引用CMake程序include

类似与C/C++中的#inclue,用来引入其它文件中的内容。

test_a.cmake

```cmake
message("模块被执行")
set(a "变量a")
```

test410_1.cmake,主要功能为:

- 先引入test_a.cmake,这种带扩展名的,可以是绝对路径,也可以是相对路径
- 然后引入test_a,这种不带扩展名的,会被当做CMake模块,只能是相对路径(但并非当前目录,而是CMAKE_MODULE_PATH变量中的目录),若模块不存在,则会报错,但加上OPTIONAL参数后,则会忽略错误
- 设置CMAKE_MODULE_PATH变量,再次执行include

```cmake
include(test_a.cmake)
message("a: ${a}")

include(test_a OPTIONAL RESULT_VARIABLE out)
message("include(test_a): ${out}")

set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include(test_a RESULT_VARIABLE out)
message("${out}")
```



## 11 总结

本篇介绍了CMake构建实战中的CMake常用命令的相关内容,由于CMake的命令非常多,全部学会也很耗时间,因此可以先对CMake的命令有个大致了解,后续用到哪个再单独查阅对应命令的详细介绍。

































秦天qintian0303 发表于 2024-10-2 11:43

<p>以实践出发,进行命令的测试可以说非常直观有效&nbsp;&nbsp;</p>

苦行者袁 发表于 2024-10-3 18:18

认真学习
页: [1]
查看完整版本: CMake构建实战读书笔记03-CMake常用命令