参考文章

概述

CMake 是基于 CMakeLists.txt 构建的

命令行

构建

创建一个 Build 目录并在此目录下生成 makefile 或其他文件:

$ cmake -S . -B Build

生成项目(编译):

$ cmake --build Build

上面两条命令等同于:

$ mkdir Build
$ cd Build
$ cmake ..
$ make

其他

$ cmake -P CMakeLists.txt

-P 选项告诉 cmake 运行指定脚本,但是不生成构建文件

变量

变量的值都被视为字符串

set 命令

# 设置单个值,双引号可加可不加
set(var1 hello)
set(var2 "world")
message("${var1}")
message("${var2}")

# 设置多个值,使用 ; 或空格分割
set(var3 hello world)
set(var4 hello;world)
message("${var3}")
message("${var4}")
$ cmake -P CMakeLists.txt
hello
world
hello;world
hello;world

list 命令

# 列表添加元素
list(APPEND list1 a0 a1 a3 a8)
message("APPEND:      ${list1}")

# 列表删除元素
list(REMOVE_ITEM list1 a8)
message("REMOVE_ITEM: ${list1}")

# 获取列表元素个数
list(LENGTH list1 len)
message("LENGTH:      ${len}")

# 在列表中查找元素返回索引,索引从 0 开始
list(FIND list1 a3 index)
message("FIND:        ${index}")

# 在指定索引位置插入元素
list(INSERT list1 2 a2)
message("INSERT:      ${list1}")

# 反转 list
list(REVERSE list1)
message("REVERSE:     ${list1}")

# 排序 list
list(SORT list1)
message("SORT:        ${list1}")
$ cmake -P CMakeLists.txt
APPEND:      a0;a1;a3;a8
REMOVE_ITEM: a0;a1;a3
LENGTH:      3
FIND:        2
INSERT:      a0;a1;a2;a3
REVERSE:     a3;a2;a1;a0
SORT:        a0;a1;a2;a3

流程控制

if 条件判断

if(<condition>)
  <commands>
elseif(<condition>)
  <commands>
else()
  <commands>
endif()

逻辑运算符

if(NOT <condition>)
if(<cond1> AND <cond2>)
if(<cond1> OR  <cond2>)

存在性检查

参考:Existence Checks

if(COMMAND <command-name>)
  • COMMAND:如果给定的名称是命令、宏或者函数这类可被调用的对象,则返回真
  • DEFINED:如果变量被定义则为真

文件操作

参考:File Operations

if(EXISTS <path-to-file-or-directory>)
  • EXISTS:如果文件或目录存在并且可读,则为真
  • IS_DIRECTORY:如果路径是目录,则为真

比较

参考:Comparisons

if(<variable|string> MATCHES <regex>)
  • MATCHES:字符串或变量的值与给定的正则表达式匹配,则为真
  • LESS:小于
  • LESS_EQUAL:小于等于
  • EQUAL:等于
  • GREATER:大于
  • GREATER_EQUAL:大于等于

foreach 循环

foreach(<loop_var> <items>)
    <commands>
endforeach()

几种用法:

# 从 0-stop 迭代,stop 不能是负值
foreach(<loop_var> RANGE <stop>)
# 从 start-stop 迭代,步长为 step(默认 1) 
foreach(<loop_var> RANGE <start> <stop> [step])

# 从 list1 list2 ... 中对每个列表依次迭代
foreach(<loop_var> IN LISTS <list1> <list2> ...)
# 从变量 <var1> <var2> ... 中依次取值
foreach(<loop_var> IN ITEMS <var1> <var2> ...)
# 从列表 <list1> <list2> 变量 <var1> <var2> ... 中依次取值
foreach(<loop_var> IN LISTS <list1> <list2> ITEMS <var1> <var2> ...)

# 同时迭代多个列表,每次迭代的值存放在 pair_0 pair_1 ...
foreach(<pair> IN ZIP_LIST <list1> <list2> ...)
# 同时迭代两个列表,上面的另一种写法
foreach(<pair0> <pair1> IN ZIP_LIST <list1> <list2>)

函数

function(<name> [<arg1> ...])
  <commands>
endfunction()

示例,ARGV0、1、2 … 表示函数的第 1、2、3 … 个参数:

function(myfunc first)
	message("FuncName = ${CMAKE_CURRENT_FUNCTION}")
	message("first = ${first}")
	message("ARGV0 = ${ARGV0}")
	message("ARGV1 = ${ARGV1}")
	message("ARGV2 = ${ARGV2}")
	message("ARGV3 = ${ARGV3}")
endfunction()

set(var 1)

myfunc(${var} 2 3 4)
$ cmake -P CMakeLists.txt
FuncName = myfunc
first = 1
ARGV0 = 1
ARGV1 = 2
ARGV2 = 3
ARGV3 = 4

作用域

类似 C 语言:

  • 函数内部可以引用外部定义的变量
  • 外部不能引用函数内部定义的变量
  • 函数内部定义重复变量会覆盖外部定义的变量

想要在函数内部修改外部定义的变量,使用 PARENT_SCOPE 如下:

set(ABC 123)

function(myfunc)
    set(ABC 456 PARENT_SCOPE)
endfunction()

message("Before = ${ABC}")
myfunc()
message("After  = ${ABC}")
$ cmake -P CMakeLists.txt
Before = 123
After  = 456

函数返回值

使用 set 的 PARENT_SCOPE 特性实现:

function(add ret)
    message("ret = ${ret}")
    math(EXPR temp "${ARGV1} + ${ARGV2}")
    # 注意 sum 是作为一个参数(字符串)传入 add 函数,所以下面要使用 ${ret}
    set(${ret} ${temp} PARENT_SCOPE)
endfunction()

add(sum 1 2)
message("sum = ${sum}")
$ cmake -P CMakeLists.txt
ret = sum
sum = 3

未完待续