流程控制
在 CMake 的 CMakeLists.txt 中也可以进行流程控制,也就是说可以像写 shell 脚本那样进行条件判断和循环。
1. 条件判断
关于条件判断其语法格式如下:
if(<condition>)
<commands>
elseif(<condition>) # 可选快, 可以重复
<commands>
else() # 可选快
<commands>
endif()
在进行条件判断的时候,如果有多个条件,那么可以写多个elseif,最后一个条件可以使用else,但是开始和结束是必须要成对出现的,分别为:if和endif。
1.1 基本表达式
if(<expression>)
如果是基本表达式,expression 有以下三种情况:常量、变量、字符串。
- 如果是1, ON, YES, TRUE, Y, 非零值,非空字符串时,条件判断返回True
- 如果是 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND,空字符串时,条件判断返回False
1.2 逻辑判断
if(NOT <condition>)
if(<cond1> AND <cond2>)
if(<cond1> OR <cond2>)
- NOT:其实这就是一个取反操作,如果条件condition为True将返回False,如果条件condition为False将返回True。
- AND:如果cond1和cond2同时为True,返回True否则返回False。
- or:如果cond1和cond2两个条件中至少有一个为True,返回True,如果两个条件都为False则返回False。
1.3 比较
基于数值的比较
if(<variable|string> LESS <variable|string>)
if(<variable|string> GREATER <variable|string>)
if(<variable|string> EQUAL <variable|string>)
if(<variable|string> LESS_EQUAL <variable|string>)
if(<variable|string> GREATER_EQUAL <variable|string>)
- LESS:如果左侧数值小于右侧,返回True
- GREATER:如果左侧数值大于右侧,返回True
- EQUAL:如果左侧数值等于右侧,返回True
- LESS_EQUAL:如果左侧数值小于等于右侧,返回True
- GREATER_EQUAL:如果左侧数值大于等于右侧,返回True
基于字符串的比较
if(<variable|string> STRLESS <variable|string>)
if(<variable|string> STRGREATER <variable|string>)
if(<variable|string> STREQUAL <variable|string>)
if(<variable|string> STRLESS_EQUAL <variable|string>)
if(<variable|string> STRGREATER_EQUAL <variable|string>)
- STRLESS:如果左侧字符串小于右侧,返回True
- STRGREATER:如果左侧字符串大于右侧,返回True
- STREQUAL:如果左侧字符串等于右侧,返回True
- STRLESS_EQUAL:如果左侧字符串小于等于右侧,返回True
- STRGREATER_EQUAL:如果左侧字符串大于等于右侧,返回True
1.4 文件操作
if(EXISTS path-to-file-or-directory)
判断文件或者目录是否存在:如果文件或者目录存在返回True,否则返回False。
if(IS_DIRECTORY path)
判断是不是目录:此处目录的 path 必须是绝对路径。如果目录存在返回True,目录不存在返回False。
if(IS_SYMLINK file-name)
此处的 file-name 对应的路径必须是绝对路径。如果软链接存在返回True,软链接不存在返回False。
软链接相当于 Windows 里的快捷方式
if(IS_ABSOLUTE path)
关于绝对路径:如果是Linux,该路径需要从根目录开始描述;如果是Windows,该路径需要从盘符开始描述。
如果是绝对路径返回True,如果不是绝对路径返回False。
1.5 其他
if(<variable|string> IN_LIST <variable>)
判断某个元素是否在列表中。如果这个元素在列表中返回True,否则返回False。
if(<variable|string> PATH_EQUAL <variable|string>)
比较两个路径是否相等。关于路径的比较其实就是两个字符串的比较,如果路径格式书写没有问题也可以通过下面这种方式进行比较:
if(<variable|string> STREQUAL <variable|string>)
我们在书写某个路径的时候,可能由于误操作会多写几个分隔符,比如把/a/b/c写成/a//b///c,此时通过STREQUAL对这两个字符串进行比较肯定是不相等的,但是通过PATH_EQUAL去比较两个路径,得到的结果确实相等的。
在进行路径比较的时候,如果使用 PATH_EQUAL 可以自动剔除路径中多余的分割线然后再进行路径的对比,使用 STREQUAL 则只能进行字符串比较。
2. 循环
在 CMake 中循环有两种方式,分别是:foreach和while。
2.1 foreach
使用 foreach 进行循环,语法格式如下:
foreach(<loop_var> <items>)
<commands>
endforeach()
通过foreach我们就可以对items中的数据进行遍历,然后通过loop_var将遍历到的当前的值取出,在取值的时候有以下几种用法。
方法1
foreach(<loop_var> RANGE <stop>)
- RANGE:关键字,表示要遍历范围
- stop:这是一个正整数,表示范围的结束值,在遍历的时候从 0 开始,最大值为 stop。
- loop_var:存储每次循环取出的值
cmake_minimum_required(VERSION 3.2)
project(test)
# 循环
foreach(item RANGE 10)
message(STATUS "当前遍历的值为: ${item}" )
endforeach()
结果:在对一个整数区间进行遍历的时候,得到的范围是这样的 【0,stop】,右侧是闭区间包含 stop 这个值。
$ cmake ..
-- 当前遍历的值为: 0
-- 当前遍历的值为: 1
-- 当前遍历的值为: 2
-- 当前遍历的值为: 3
-- 当前遍历的值为: 4
-- 当前遍历的值为: 5
-- 当前遍历的值为: 6
-- 当前遍历的值为: 7
-- 当前遍历的值为: 8
-- 当前遍历的值为: 9
-- 当前遍历的值为: 10
-- Configuring done
-- Generating done
-- Build files have been written to: /home/robin/abc/a/build
方法2
foreach(<loop_var> RANGE <start> <stop> [<step>])
- RANGE:关键字,表示要遍历范围
- start:这是一个正整数,表示范围的起始值,也就是说最小值为 start
- stop:这是一个正整数,表示范围的结束值,也就是说最大值为 stop
- step:控制每次遍历的时候以怎样的步长增长,默认为1,可以不设置
- loop_var:存储每次循环取出的值
cmake_minimum_required(VERSION 3.2)
project(test)
foreach(item RANGE 10 30 2)
message(STATUS "当前遍历的值为: ${item}" )
endforeach()
结果:
$ cmake ..
-- 当前遍历的值为: 10
-- 当前遍历的值为: 12
-- 当前遍历的值为: 14
-- 当前遍历的值为: 16
-- 当前遍历的值为: 18
-- 当前遍历的值为: 20
-- 当前遍历的值为: 22
-- 当前遍历的值为: 24
-- 当前遍历的值为: 26
-- 当前遍历的值为: 28
-- 当前遍历的值为: 30
-- Configuring done
-- Generating done
-- Build files have been written to: /home/robin/abc/a/build
方法3
foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items>]])
- IN:关键字,表示在 xxx 里边
- LISTS:关键字,对应的是列表list,通过set、list可以获得
- ITEMS:关键字,对应的也是列表
- loop_var:存储每次循环取出的值
cmake_minimum_required(VERSION 3.2)
project(test)
# 创建 list
set(WORD a b c d)
set(NAME ace sabo luffy)
# 遍历 list
foreach(item IN LISTS WORD NAME)
message(STATUS "当前遍历的值为: ${item}" )
endforeach()
结果:
$ cd build/
$ cmake ..
-- 当前遍历的值为: a
-- 当前遍历的值为: b
-- 当前遍历的值为: c
-- 当前遍历的值为: d
-- 当前遍历的值为: ace
-- 当前遍历的值为: sabo
-- 当前遍历的值为: luffy
-- Configuring done
-- Generating done
-- Build files have been written to: /home/robin/abc/a/build
接下来看另外一种方式:
cmake_minimum_required(VERSION 3.2)
project(test)
set(WORD a b c "d e f")
set(NAME ace sabo luffy)
foreach(item IN ITEMS ${WORD} ${NAME})
message(STATUS "当前遍历的值为: ${item}" )
endforeach()
遍历过程中将关键字LISTS改成了ITEMS,后边跟的还是一个或者多个列表,只不过此时需要通过${}将列表中的值取出。其输出的信息和上一个例子是一样的。
方法4
foreach(<loop_var>... IN ZIP_LISTS <lists>)
- loop_var:存储每次循环取出的值,可以根据要遍历的列表的数量指定多个变量,用于存储对应的列表当前取出的那个值。
- 如果指定了多个变量名,它们的数量应该和列表的数量相等
- 如果只给出了一个 loop_var,那么它将一系列的 loop_var_N 变量来存储对应列表中的当前项,也就是说 loop_var_0 对应第一个列表,loop_var_1 对应第二个列表,以此类推…
- 如果遍历的多个列表中一个列表较短,当它遍历完成之后将不会再参与后续的遍历(因为其它列表还没有遍历完)。
- IN:关键字,表示在 xxx 里边
- ZIP_LISTS:关键字,对应的是列表list,通过set 、list可以获得
cmake_minimum_required(VERSION 3.17)
project(test)
# 通过list给列表添加数据
list(APPEND WORD hello world "hello world")
list(APPEND NAME ace sabo luffy zoro sanji)
# 遍历列表
foreach(item1 item2 IN ZIP_LISTS WORD NAME)
message(STATUS "当前遍历的值为: item1 = ${item1}, item2=${item2}" )
endforeach()
message("=============================")
# 遍历列表
foreach(item IN ZIP_LISTS WORD NAME)
message(STATUS "当前遍历的值为: item1 = ${item_0}, item2=${item_1}" )
endforeach()
结果:
$ cd build/
$ cmake ..
-- 当前遍历的值为: item1 = hello, item2=ace
-- 当前遍历的值为: item1 = world, item2=sabo
-- 当前遍历的值为: item1 = hello world, item2=luffy
-- 当前遍历的值为: item1 = , item2=zoro
-- 当前遍历的值为: item1 = , item2=sanji
=============================
-- 当前遍历的值为: item1 = hello, item2=ace
-- 当前遍历的值为: item1 = world, item2=sabo
-- 当前遍历的值为: item1 = hello world, item2=luffy
-- 当前遍历的值为: item1 = , item2=zoro
-- 当前遍历的值为: item1 = , item2=sanji
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/robin/abc/a/build
2.2 while
while(<condition>)
<commands>
endwhile()
while循环比较简单,只需要指定出循环结束的条件即可。
cmake_minimum_required(VERSION 3.5)
project(test)
# 创建一个列表 NAME
set(NAME luffy sanji zoro nami robin)
# 得到列表长度
list(LENGTH NAME LEN)
# 循环
while(${LEN} GREATER 0)
message(STATUS "names = ${NAME}")
# 弹出列表头部元素
list(POP_FRONT NAME)
# 更新列表长度
list(LENGTH NAME LEN)
endwhile()
结果:
$ cd build/
$ cmake ..
-- names = luffy;sanji;zoro;nami;robin
-- names = sanji;zoro;nami;robin
-- names = zoro;nami;robin
-- names = nami;robin
-- names = robin
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/robin/abc/a/build