cmake常用命令(2)——流程控制

条件控制

一、概览

if()
  
elseif() # optional block, can be repeated
  
else()              # optional block
  
endif()

else和endif中可不带参数,如果要带则需要与if中的条件参数一样。

二、优先级

  1. 括号
  2. 一元测试如EXISTS、COMMAND和DEFINED
  3. 二元测试如EQUAL、LESS等
  4. 一元操作符NOT
  5. 二元操作符AND和OR

三、基础表达式

1.常量

if()

1, ON, YES, TRUE, Y, 或者非0数字(包括浮点数)表示TRUE。

0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, 空字符串,以-NOTFOUND结尾的常量表示FALSE。

常量大小写不敏感。

#constant 大小写不敏感
##constant true
if(1 AND ON AND YES AND TRUE AND Y AND 0.1 )#AND ""
    message("constant true")
endif()

##constant false
if(NOT(0 OR OFF OR NO OR fALSE OR N OR IGNORE OR "" OR NOTFOUND))
#以及以-NOTFOUND结尾的常量
    message("constant false")
endif()

2.变量

if()

如果变量的值不是表示false的常量都为TRUE,否则都是false,包括未定义。

注意:宏参数不是变量。

注意:环境变量不能通过此检测,即都是false。


#variable
set(VAR "1")  
#变量在条件中是直接使用var的,而使用${VAR}实际上走的是constant逻辑
#两者在这里没有什么明显区别,但是在macro中使用就有区别了,macro中,使用参数为false,而使用$则根据参数值确定
#其值只要不是const fasle,且定义了,都是true

if(VAR)
    message("variable ")   
endif()

if(${VAR})  
    message("variable value" )   
endif()

#注意宏参数不是变量
macro(test mvar)
    if(${mvar})
        message("macro argument" ${mvar})   
    endif()
endmacro(test mvar)
test(${VAR})

#env varaiable不能被检测。
set(ENV{CXXFLAGS} "test")
message("-------->" $ENV{CXXFLAGS})
if(ENV{CXXFLAGS})  
    message("variable env " )   
endif()

#print:
#variable
#variable value
#macro argument1
#-------->test

3.字符串

if()

带引号的字符串除了以下的场景外都是false:

  • 字符串值是为true的常量值。
  • CMP0054没被设置为NEW,且字符串值为变量名。
#string
#除非等于constant true或者cmp0054为new,并且字符串值为变量名,否则都是false
set(VAR "111")
if(NOT "test")  
    message("string" )   
endif()

cmake_policy(SET CMP0054 OLD)
if("VAR")  
   message("string var" )   
endif()

#print:
#string
#string var

四、逻辑操作符

NOT、AND、OR

五、存在检测

1.COMMAND

 if(COMMAND )

存在名字为command-name的命令、函数、宏则为true,

2.POLICY

if(POLICY )

如果存在policy-id则为true,形式如CMP0054

3.TARGET

if(TARGET )

已经存在通过add_executable(), add_library(), or add_custom_target()创建的目标名则为true

4.TEST

if(TEST )

已经存在通过add_test()创建的测试名则返回true。

5.DEFINED

if(DEFINED |CACHE{}|ENV{})

如果定义了变量、缓存变量、环境变量name,则返回true。注意name和CACHE{name}是不一样的。

6.IN_LIST

 if( IN_LIST )

判断变量或字符串是否在variable中。

六、文件操作

1.EXISTS

if(EXISTS )

文件或目录是否存在。注意需要传入全路径,如~/开始的目录则不回被扩展为家目录并作为相对目录(即找不到)。

如果路径为符号链接,那么结果由实际目标确定,即如果目标不存在则返回false,否则返回true

字符串为空则为false

2.IS_NEWER_THAN

if( IS_NEWER_THAN )

判断file1是否比file2新

3.IS_DIRECTORY

if(IS_DIRECTORY )

判断是否是目录,要求全路径。

4.IS_SYMLINK

if(IS_SYMLINK )

判断是否是软链接,要求全路径。

5.IS_ABSOLUTE

if(IS_ABSOLUTE )

判断是否是绝对路径。注意一些特殊场景:

  • 空路径为false
  • 在Windows主机上,任何以驱动器号和冒号(例如C:)、正斜杠或反斜杠开头的路径都将计算为true。这意味着像C:no\base\dir这样的路径将计算为true,即使路径的非驱动器部分是相对的。
  • 在非windows主机上,任何以波浪号(~)开头的路径都计算为true

七、比较

1.正则

if( MATCHES )

如果变量或字符串符合正则regex规则,则为true

2.数值判断

if( Comparisons )

Comparisons包括LESS、GREATER、EQUAL、LESS_EQUAL、GREATER_EQUAL。

只有当指定变量或字符串的值为合法数字,并且前者小于、大于、等于、小于等于、大于等于时为true。

3.字符串比较

 if( strComparisons 

Comparisons包括STRLESS、STRGREATER、STREQUAL、STRLESS_EQUAL、STRGREATER_EQUAL。

只有左侧变量或者字符串值的字母顺序小于、、大于、等于、小于等于、大于等于右侧时为true。

八、版本比较

 if( version_Comparisons 

Comparisons包括VERSION_LESS、VERSION_GREATER、VERSION_EQUAL、VERSION_LESS_EQUAL、VERSION_GREATER_EQUAL。

只有左侧变量或者字符串的版本小于、大于、等于、小于等于、大于等于右侧时为true。

九、路径比较

if( PATH_EQUAL )

只有左侧路径等于右侧时为true。

比较时,是按路径的逐个部分进行比较,多个分隔符会被合并,斜杠和反斜杠两种分隔符也不会区分。

# comparison is TRUE
if ("/a//b/c" PATH_EQUAL "/a/b/c")
   ...
endif()
# comparison is TRUE
if ("/a//b/c" PATH_EQUAL "/a\\b/c")
message("path equal" )   
endif()

# comparison is FALSE
if ("/a//b/c" STREQUAL "/a/b/c")
   ...
endif()

十、变量扩展

if命令在CMake的历史中很早就被编写出来了,早于${}变量求值语法,为了方便,它求值由其参数命名的变量,如上面的签名所示。注意,在if命令接收参数之前,使用${}进行正常的变量求值。因此下面的代码

set(var1 OFF)
set(var2 "var1")
if(${var2})

等同于

if(var1)

并且会以if的变量形式处理,即判断var1变量的值,为OFF,因此为false。

而如果我们移除${}

if(var2)

则条件为true,因为var2的变量值不是为false的常量值。

循环一(foreach)

遍历列表中的所有值,并执行一系列命令

一、items

foreach( )
  
endforeach()

items是以分号或者空格分隔的列表。

#items:;或者空格分隔的列表,不要加引号,否则认为是一个
foreach(it  a;b;c;d)  #"a;b;c;d" print:string list:abcd
    message("string list:" ${it})
endforeach(it "a;b;c;d")

#print
#string list:a
#string list:b
#string list:c
#string list:d

二、range

foreach( RANGE )

从0开始到stop的数字(包含stop),stop是非负整数

foreach( RANGE   [])

指定遍历的起始数字、结束数字以及步长。

foreach(it RANGE 5)
message("range 5:"${it})
endforeach(it RANGE 5)

foreach(it RANGE 5 12 2)
message("5-12,step 2:"${it})
endforeach()

print:

range 5:0
range 5:1
range 5:2
range 5:3
range 5:4
range 5:5
5-12,step 2:5
5-12,step 2:7
5-12,step 2:9
5-12,step 2:11

三、IN

foreach( IN [LISTS []] [ITEMS []])

可以通过LISTS或ITEMS将多个列表合并遍历。

set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
foreach(X IN LISTS A B C D E)
    message(STATUS "X=${X}")
endforeach()

print:

-- X=0
-- X=1
-- X=2
-- X=3
-- X=4 5
-- X=6
-- X=7
-- X=8

四、IN ZIP_LISTS

foreach(... IN ZIP_LISTS )

将多个list压缩,类似于多个map。

list(APPEND English one two three four)
list(APPEND Bahasa satu dua tiga)

foreach(num IN ZIP_LISTS English Bahasa)
    message(STATUS "num_0=${num_0}, num_1=${num_1}")
endforeach()

foreach(en ba IN ZIP_LISTS English Bahasa)
    message(STATUS "en=${en}, ba=${ba}")
endforeach()

print:

-- num_0=one, num_1=satu
-- num_0=two, num_1=dua
-- num_0=three, num_1=tiga
-- num_0=four, num_1=
-- en=one, ba=satu
-- en=two, ba=dua
-- en=three, ba=tiga
-- en=four, ba=

遍历次数为最长的那个列表长度。

循环二(while)

while()
  
endwhile()

condition与if相同,为true时重复执行command,可以使用break和continue命令。

你可能感兴趣的:(cmake,cmake)