if
根据条件执行一组命令。
概要:
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()
根据下面描述的Condition语法,对if子句的条件参数进行评估。如果结果为真,那么就执行if块中的命令。否则,可选的elseif块以同样的方式处理。最后,如果没有条件为真,则执行可选的else块中的命令。
按照惯例,else()和endif()命令允许一个可选的<condition>参数。如果使用的话,它必须是逐字重复开头的if命令的参数。
Condition Syntax / 条件参数语法
以下语法适用于if、elseif和while()子句的条件参数。
复合条件按以下优先顺序进行评估:最里面的括号首先被评估。接下来是单项测试,如EXISTS、COMMAND和DEFINED。然后是二元测试,如EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL, STREQUAL, STRLESS, STRLESS_EQUAL, STRGREATER, STRGREATER_EQUAL, VERSION_EQUAL, VERSION_LESS_EQUAL, VERSION_GREATER, VERSION_GREATER_EQUAL, 和 MATCHES。然后是布尔运算符,顺序为NOT、AND,最后是OR。
基本表达式
if(<constant>)
如果常数是1,ON,YES,TRUE,Y,或者是一个非零的数字(包括浮点数),则为真。如果常数是0、OFF、NO、FALSE、N、IGNORE、NOTFOUND、空字符串,或者以后缀-NOTFOUND结尾,则为假。命名的布尔常数是不区分大小写的。如果参数不是这些特定的常量之一,它将被视为一个变量或字符串(见下面的变量扩展),并适用以下两种形式之一。
if(<variable>)
如果给定一个变量,该变量被定义为一个不是假常数的值,则为真。否则为假,包括该变量未定义。注意,宏参数不是变量。环境变量也不能用这种方式测试,例如,if(ENV{some_var}将总是评估为假。
if(<string>)
一个带引号的字符串总是求值为false,除非:
- 字符串的值是真常数之一,或者
- 策略CMP0054没有设置为 "新",并且字符串的值恰好是一个受CMP0054行为影响的变量名。(具体请参照:CMP0054 — CMake 3.23.0-rc1 Documentation)
编写一个简单的cmake例子试一下,可以参照之前的博文,CMake HelloWorld!
CMakeLists.txt:
cmake_minimum_required(VERSION 3.13)
if(TRUE)
message("If true")
else()
message("ELse")
endif()
project(cmake_test)
运行命令:
$ cmake .
输出: If true
逻辑运算符
if(NOT <condition>)
如果条件不为真,则为真。
if(<cond1> AND <cond2>)
如果两个条件都被单独认为是真的,则为真。
if(<cond1> OR <cond2>)
如果任何一个条件单独被认为是真的,则为真。
if((condition) AND (condition OR (condition)))
括号内的条件首先被评估,然后像其他例子一样评估剩余的条件。如果有嵌套的小括号,最里面的小括号先评估,然后包含它们的条件使用这部分结果继续评估。
存在性检查
if(COMMAND command-name)
如果给定的名称是一个可以调用的命令、宏或函数,则为真。
if(POLICY Policy-id)
如果给定的名称是一个现有的策略(形式为CMP<NNNN>),则为真。
if(TARGET target-name)
如果给定的名称是一个现有的逻辑目标名称,它是通过调用已经被调用的add_executable()、add_library()或add_custom_target()命令创建的(在任何目录下)。
if(TEST test-name)
3.3版新增:如果给定的名称是由add_test()命令创建的现有测试名称,则为真。
if(DEFINED <name>|CACHE{<name>}|ENV{<name>})
如果定义了给定<name>的变量、缓存变量或环境变量,则为真。该变量的值并不重要。请注意以下注意事项:
- 宏参数不是变量。
- 不可能直接测试<name>是否是一个非缓存变量。如果缓存变量或非缓存变量someName存在,表达式if(DEFINED someName)将评估为真。相比之下,表达式if(DEFINED CACHE{someName}只有在缓存变量someName存在的情况下才会评估为真。如果需要知道非缓存变量是否存在,则需要测试这两个表达式:if(DEFINED someName AND NOT DEFINED CACHE{someName})。
3.14版新增:增加了对CACHE{<name>}变量的支持。
if(<variable|string> IN_LIST <variable>)
3.3版新增:如果指定的元素包含在命名的列表变量中,则为真。
文件操作
if(EXISTS path-to-file-or-directory)
如果指定的文件或目录存在,则为真。行为只对明确的全路径有很好的定义(前面的~/不被扩展为主目录,被认为是相对路径)。解决符号链接,即如果命名的文件或目录是一个符号链接,如果符号链接的目标存在,返回真。
if(file1 IS_NEWER_THAN file2)
如果file1比file2新,或者两个文件中的一个不存在,则为真。该行为仅对全路径有明确的定义。如果文件的时间戳完全相同,IS_NEWER_THAN比较会返回真,这样在出现时间戳相等的情况下,任何依赖的构建操作都会发生。这包括为file1和file2传递相同文件名的情况。
if(IS_DIRECTORY path-to-directory)
如果给定的名称是一个目录,则为真。行为仅对全路径有明确的定义。
if(IS_SYMLINK file-name)
如果给定的名称是一个符号链接,则为真。仅对全路径有明确的行为定义。
if(IS_ABSOLUTE path)
如果给定的路径是一个绝对路径,则为真。注意以下的特殊情况。
- 一个空的路径被评估为false。
- 在Windows主机上,任何以盘符和冒号(例如C:)、正斜杠或反斜杠开头的路径都会评估为真。这意味着像C:nobase\dir这样的路径将被评估为真,即使该路径的非驱动器部分是相对的。
- 在非Windows主机上,任何以tilde(~)开头的路径都会被评估为真。
比较
if(<变量|字符串> MATCHES regex)
如果给定的字符串或变量的值符合给定的正则表达式,则为真。关于正则表达式的格式,请看Regex规范。
3.9版新增:()组在CMAKE_MATCH_<n>变量中被捕获。
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>)
3.7版新增:如果给定的字符串或变量的值是一个有效的数字,并且小于或等于右边的数字,则为真。
if(<variable|string> GREATER_EQUAL <variable|string>)
3.7版新增:如果给定的字符串或变量的值是一个有效的数字并且大于或等于右边的数字,则为真。
if(<variable|string> STRLESS <variable|string>)
如果给定的字符串或变量的值比右边的字符串或变量的值要小,则为真。
if(<变量|字符串> STRGREATER <变量|字符串>)
如果给定的字符串或变量的值在字典顺序上大于右边的字符串或变量,则为真。
if(<variable|string> STREQUAL <variable|string>)
如果给定的字符串或变量的值在字典顺序上等于右边的字符串或变量,则为真。
if(<variable|string> STRLESS_EQUAL <variable|string>)
3.7版新增:如果给定的字符串或变量的值在字典顺序上小于或等于右边的字符串或变量,则为真。
if(<variable|string> STRGREATER_EQUAL <variable|string>)
3.7版新增:如果给定的字符串或变量的值在字典顺序上大于或等于右边的字符串或变量,则为真。
版本比较
if(<variable|string> VERSION_LESS <variable|string>)
if(<variable|string> VERSION_GREATER <variable|string>)
if(<variable|string> VERSION_EQUAL <variable|string>)
if(<variable|string> VERSION_LESS_EQUAL <variable|string>)
if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)
逐个部分的整数版本号比较(版本格式为major[.minor[.patch[.tweak]],省略的组成部分被视为零)。每个组成部分的版本信息,在小数点处自动截断。
变量扩展
if命令是在CMake历史上很早的时候编写的,早于${}变量评估语法,为了方便起见,它会评估由其参数命名的变量,如上面的签名所示。注意,在if命令的参数中使用${},在收到参数之前,会进行正常的变量评估。因此,像这样的代码
set(var1 OFF)
set(var2 "var1")
if(${var2})
在if命令中实际上就是:
if(var1)
并根据上面记录的if(<variable>)案例进行评估。其结果是OFF,即为假。然而,如果我们把${}从例子中去掉,那么该命令变成
if(var2)
结果为真,因为var2被定义为var1,而var1不是一个假常数。
在其他情况下,只要上面记载的条件语法接受<变量|字符串>,就会自动评估:
- 首先检查MATCHES的左侧参数是否是一个定义的变量,如果是,则使用该变量的值,否则使用原始值。
- 如果MATCHES的左手参数缺失,则返回false,没有错误。
- LESS、GREATER、EQUAL、LESS_EQUAL和GREATER_EQUAL的左右两个参数都要进行独立测试,看它们是否是定义的变量,如果是,就使用它们的定义值,否则就使用原始值。
- STRLESS、STRGREATER、STREQUAL、STRLESS_EQUAL和STRGREATER_EQUAL的左右两个参数都是独立测试的,看它们是否是定义的变量,如果是,就使用它们的定义值,否则就使用原始值。
- VERSION_LESS, VERSION_GREATER, VERSION_EQUAL, VERSION_LESS_EQUAL和VERSION_GREATER_EQUAL的左右手参数都要进行独立测试,看它们是否是定义的变量,如果是,就使用它们的定义值,否则就使用原值。
- 对NOT的右侧参数进行测试,看它是否是一个布尔常数,如果是,则使用其值,否则假定它是一个变量并使用其引用值。
- AND和OR的左边和右边的参数被独立地测试,看它们是否是布尔常数,如果是,它们就被使用,否则,它们被假定为变量,并使用其引用值。
在3.1版本中的变更:为了防止歧义,可能是变量或关键字的名称可以在引号参数或括号参数中指定。带引号或括号的变量或关键字将被解释为一个字符串,不作为引用值也不进行解释。参见策略CMP0054 (CMP0054 — CMake 3.23.0-rc1 Documentation)。
对于环境或缓存变量引用没有自动评估。它们的值必须以$ENV{<name>}或$CACHE{<name>}的形式引用,只要上面记载的条件语法接受<variable|string>。
参考:
if — CMake 3.23.0-rc1 Documentationhttps://cmake.org/cmake/help/latest/command/if.html