Cmake 逻辑操作

Posted by 一周思进 on August 24, 2020

6.1.5. Existence Tests

如下语句用于判断 CMake 实体是否存在,在较大、复杂的工程尤其有用

if(DEFINED name)
if(COMMAND name)
if(POLICY name)
if(TARGET name)
if(TEST name) # Available from CMake 3.4 onward

DEFINED
只判断对象是否已存在,而不关心它的值,同样可检测环境变量

COMMAND
用于检查CMake命令、函数、宏(第8章)是否存在

POLTCY
检查是否存在特殊策略,12章

TARGET
检测如下语句的目标是否已存在 add_executable(), add_library() or add_custom_target().

TEST
检测 add_test 是否已经添加过对应的测试对象

下面的测试语句在CMake3.5及之后的版本可用
if(value IN_LIST listVar)

更多复杂的工程会使用下面模式有条件的包含子目录或根据CMake选项或缓存变量执行其他任务。 开发人员可以打开/关闭选项或将变量设置为非默认值,而不需直接修改CMakeList.txt文件。

option(BUILD_MYLIB "Enable building the myLib target")
if(BUILD_MYLIB)
add_library(myLib src1.cpp src2.cpp)
endif()

6.2 Looping 在许多CMake项目中,一些常用的需求是在某个范围值内执行一些动作,或者重复执行直到满足某个条件。

6.2.1 foreach()

常用基础方式:

foreach(loopVar arg1 arg2 ...)
# ...
endforeach()

也可以指定一个或者多个列表,如下:

foreach(loopVar IN [LISTS listVar1 ...] [ITEMS item1 ...])
# ...
endforeach()

其中 ITEMS 必须在 LISTS 后面

示例:

set(list1 A B)
set(list2)
set(foo WillNotBeShown)
foreach(loopVar IN LISTS list1 list2 ITEMS foo bar)
message("Iteration for: ${loopVar}")
endforeach()

foreach() 也支持某个数值范围的迭代:

foreach(loopVar RANGE start stop [step])

从 start 开始,包含 stop,如果指定 step,则按 step 进行步进加操作

也支持单个值指定迭代:

foreach(loopVar RANGE value)

此方式等价于 foreach(loopVar RANGE 0 value),但这种表达方式直观上以为执行 value 次,实际执行 value + 1 次,因此尽量避免使用此方式,使用前面的表达方式。

6.2.2 while()

另一个循环语句 while:

while(condition)
# ...
endwhile()

6.2.3 中断循环

foreach(outerVar IN ITEMS a b c)
unset(s)
foreach(innerVar IN ITEMS 1 2 3)
# Stop inner loop once string s gets long
list(APPEND s "${outerVar}${innerVar}")
string(LENGTH s length)
if(length GREATER 5)
break() ①
endif()
# Do no more processing if outer var is "b"
if(outerVar STREQUAL "b")
continue() ②
endif()
message("Processing ${outerVar}-${innerVar}")
endforeach()
message("Accumulated list: ${s}")
endforeach()

6.3 建议

1、在 if、foreach、while 表达式减少字符串无意识转换为变量 2、避免使用引号的表达式,而是使用字符串比较操作 3、强烈建议使用 CMake 3.1以上版本,避免引号字符串隐式转换问题 4、foreach使用RANGE表达式,建议都指定start和end值 5、使用 IN LISTS 或者 IN ITEMS 表达式,而不是 foreach(loopVar item1 item2 …)