如果

有条件地执行一组命令。

概要

if(<condition>)
  <commands>
elseif(<condition>) # optional block, can be repeated
  <commands>
else()              # optional block
  <commands>
endif()

根据下面描述的“条件语法”评估“if”子句的“条件”参数。如果结果为真,则执行 if 块中的``commands``。否则,可选的 elseif 块以相同的方式处理。最后,如果没有“条件”为真,则执行可选“else”块中的“命令”。

根据传统, else()endif() 命令接受一个可选的 <condition> 参数。如果使用,它必须逐字重复开头的“if”命令的参数。

条件语法

以下语法适用于 ifelseifwhile() 子句的 condition 参数。

复合条件按以下优先顺序进行评估:

  1. 括号。

  2. 一元测试,例如 EXISTSCOMMANDDEFINED

  3. 二进制测试,例如`EQUAL`_、LESSLESS_EQUALGREATERGREATER_EQUALSTREQUALSTRLESSSTRLESS_EQUALSTRGREATER、` STRGREATER_EQUAL`_、VERSION_EQUALVERSION_LESSVERSION_LESS_EQUALVERSION_GREATERVERSION_GREATER_EQUALPATH_EQUALMATCHES

  4. 一元逻辑运算符“NOT”_。

  5. 二元逻辑运算符 ANDOR,从左到右,没有任何短路。

基本表达式

如果(<常量>)

如果常量为“1”、“ON”、“YES”、“TRUE”、“Y”或非零数(包括浮点数),则为真。如果常量为 0OFFNOFALSENIGNORENOTFOUND、空字符串则为假,或以后缀“-NOTFOUND”结尾。命名的布尔常量不区分大小写。如果参数不是这些特定常量之一,则将其视为变量或字符串(请参阅下面的“变量扩展”),并且适用以下两种形式之一。

如果(<变量>)

如果给定的变量定义为非假常量的值,则为真。否则为假,包括变量是否未定义。请注意,宏参数不是变量。 Environment Variables 也不能以这种方式进行测试,例如``if(ENV{some_var})`` 将始终评估为 false。

如果(<字符串>)

带引号的字符串总是计算为 false,除非:

  • 字符串的值是真正的常量之一,或者

  • 策略 CMP0054 未设置为 NEW 并且字符串的值恰好是受 CMP0054 的行为影响的变量名称。

逻辑运算符

如果(不是<条件>)

如果条件不为真,则为真。

如果(<cond1> <cond2>)

如果两个条件都被认为是真实的,则为真。

如果(<cond1> <cond2>)

如果任一条件被单独视为真,则为真。

如果((条件)和(条件或(条件)))

首先评估括号内的条件,然后像其他示例一样评估其余条件。在有嵌套括号的地方,最里面的括号被评估为评估包含它们的条件的一部分。

存在检查

if(COMMAND 命令名)

如果给定名称是可以调用的命令、宏或函数,则为真。

如果(策略策略-id)

如果给定名称是现有策略(形式为“CMP<NNNN>”),则为真。

如果(目标目标名称)

如果给定的名称是通过调用 add_executable 、 add_library 或 add_custom_target 已经调用的命令创建的现有逻辑目标名称(在任何目录中),则为真。

如果(测试测试名称)

在 3.3 版本加入: 如果给定名称是由 add_test 命令创建的现有测试名称,则为真。

if(DEFINED <name>|CACHE{<name>}|ENV{<name>})

如果定义了具有给定“<名称>”的变量、缓存变量或环境变量,则为真。变量的值无关紧要。请注意以下注意事项:

  • 宏参数不是变量。

  • 无法直接测试 <name> 是否为非缓存变量。如果存在缓存或非缓存变量“someName”,则表达式“if(DEFINED someName)”的计算结果为真。相比之下,表达式 if(DEFINED CACHE{someName}) 只有在存在缓存变量 someName 时才会计算为真。如果您需要知道是否存在非缓存变量,则需要测试这两个表达式:if(DEFINED someName AND NOT DEFINED CACHE{someName})

在 3.14 版本加入: 添加了对 CACHE{<name>} 变量的支持。

如果(<变量|字符串> IN_LIST <变量>)

在 3.3 版本加入: 如果给定元素包含在命名列表变量中,则为真。

文件操作

如果(EXISTS 路径到文件或目录)

如果指定的文件或目录存在则为真。行为仅针对显式完整路径进行了明确定义(前导的 ~/ 不会扩展为主目录,而是被视为相对路径)。解析符号链接,即如果指定的文件或目录是符号链接,则如果符号链接的目标存在则返回 true。

如果给定路径为空字符串,则为 False。

如果(file1 IS_NEWER_THAN file2)

如果 file1file2 新,或者两个文件之一不存在,则为真。行为仅针对完整路径进行了明确定义。如果文件时间戳完全相同,则 IS_NEWER_THAN 比较返回 true,因此在出现平局时将发生任何相关的构建操作。这包括为 file1 和 file2 传递相同文件名的情况。

如果(IS_DIRECTORY 路径)

如果 path 是目录,则为真。行为仅针对完整路径进行了明确定义。

如果给定路径为空字符串,则为 False。

如果(IS_SYMLINK 文件名)

如果给定名称是符号链接,则为真。行为仅针对完整路径进行了明确定义。

如果(IS_ABSOLUTE 路径)

如果给定路径是绝对路径,则为真。注意以下特殊情况:

  • 空的 path 计算结果为 false。

  • 在 Windows 主机上,任何以驱动器号和冒号(例如 C:)、正斜杠或反斜杠开头的“路径”都将计算为真。这意味着像“C:nobasedir”这样的路径将评估为真,即使路径的非驱动器部分是相对的。

  • 在非 Windows 主机上,任何以波浪号 (~) 开头的``路径`` 计算结果为真。

比较

如果(<变量|字符串>匹配正则表达式)

如果给定的字符串或变量的值与给定的正则表达式匹配则为真。请参阅 正则表达式规范 了解正则表达式格式。

在 3.9 版本加入: () 组在 CMAKE_MATCH_<n> 变量中捕获。

如果(<变量|字符串> LESS <变量|字符串>)

如果给定的字符串或变量的值是有效数字并且小于右边的数字,则为真。

如果(<变量|字符串> GREATER <变量|字符串>)

如果给定的字符串或变量的值是有效数字并且大于右边的数字,则为真。

如果(<变量|字符串>等于<变量|字符串>)

如果给定的字符串或变量的值是有效数字并且等于右边的数字,则为真。

如果(<变量|字符串> LESS_EQUAL <变量|字符串>)

在 3.7 版本加入: 如果给定的字符串或变量的值是有效数字并且小于或等于右边的数字,则为真。

如果(<变量|字符串> GREATER_EQUAL <变量|字符串>)

在 3.7 版本加入: 如果给定的字符串或变量的值是有效数字并且大于或等于右边的数字,则为真。

如果(<变量|字符串> STRLESS <变量|字符串>)

如果给定的字符串或变量的值按字典顺​​序小于右侧的字符串或变量,则为真。

如果(<变量|字符串> STRGREATER <变量|字符串>)

如果给定的字符串或变量的值在字典序上大于右侧的字符串或变量,则为真。

如果(<变量|字符串> STREQUAL <变量|字符串>)

如果给定的字符串或变量的值在字典序上等于右侧的字符串或变量,则为真。

如果(<变量|字符串> STRLESS_EQUAL <变量|字符串>)

在 3.7 版本加入: 如果给定的字符串或变量的值按字典顺​​序小于或等于右侧的字符串或变量,则为真。

如果(<变量|字符串> STRGREATER_EQUAL <变量|字符串>)

在 3.7 版本加入: 如果给定字符串或变量的值按字典顺​​序大于或等于右侧的字符串或变量,则为真。

版本比较

如果(<变量|字符串> VERSION_LESS <变量|字符串>)

组件方面的整数版本号比较(版本格式为``major[.minor[.patch[.tweak]]]``,省略的组件被视为零)。任何非整数版本组件或版本组件的非整数尾随部分都会在该点有效截断字符串。

如果(<变量|字符串> VERSION_GREATER <变量|字符串>)

组件方面的整数版本号比较(版本格式为``major[.minor[.patch[.tweak]]]``,省略的组件被视为零)。任何非整数版本组件或版本组件的非整数尾随部分都会在该点有效截断字符串。

如果(<变量|字符串> VERSION_EQUAL <变量|字符串>)

组件方面的整数版本号比较(版本格式为``major[.minor[.patch[.tweak]]]``,省略的组件被视为零)。任何非整数版本组件或版本组件的非整数尾随部分都会在该点有效截断字符串。

如果(<变量|字符串> VERSION_LESS_EQUAL <变量|字符串>)

在 3.7 版本加入: 组件方面的整数版本号比较(版本格式为``major[.minor[.patch[.tweak]]]``,省略的组件被视为零)。任何非整数版本组件或版本组件的非整数尾随部分都会在该点有效截断字符串。

如果(<变量|字符串> VERSION_GREATER_EQUAL <变量|字符串>)

在 3.7 版本加入: 组件方面的整数版本号比较(版本格式为``major[.minor[.patch[.tweak]]]``,省略的组件被视为零)。任何非整数版本组件或版本组件的非整数尾随部分都会在该点有效截断字符串。

路径比较

如果(<变量|字符串> PATH_EQUAL <变量|字符串>)

在 3.24 版本加入.

逐个组件地比较两条路径。只有当两条路径的每个组件都匹配时,两条路径才会比较相等。多个路径分隔符有效地折叠成一个分隔符,但请注意,反斜杠不会转换为正斜杠。没有执行其他 path normalization

由于对多个路径分隔符的处理,基于组件的比较优于基于字符串的比较。在以下示例中,表达式使用 PATH_EQUAL 计算结果为真,但使用 STREQUAL 计算结果为假:

# comparison is TRUE
if ("/a//b/c" PATH_EQUAL "/a/b/c")
   ...
endif()

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

有关详细信息,请参见:ref:cmake_path(COMPARE) <Path COMPARE>

变量扩展

if 命令在 CMake 的历史中很早就编写了,早于 ${} 变量评估语法,并且为了方便评估由其参数命名的变量,如上面的签名所示。请注意,在 if 命令甚至接收到参数之前,使用 ${} 的普通变量评估就适用了。因此代码像

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

在 if 命令中显示为

if(var1)

并根据上面记录的 if(<variable>) 案例进行评估。结果是 OFF,这是错误的。但是,如果我们从示例中删除 ${} 那么命令会看到

if(var2)

这是真的,因为 var2 被定义为 var1 而不是假常量。

只要上面记录的条件语法接受``<variable|string>``,自动评估就适用于其他情况:

  • 首先检查“MATCHES”的左手参数,看它是否是已定义的变量,如果是,则使用变量的值,否则使用原始值。

  • 如果缺少“MATCHES”的左手参数,它将返回 false 而不会出错

  • LESSGREATEREQUALLESS_EQUALGREATER_EQUAL 的左手和右手参数都被独立测试以查看它们是否是已定义的变量,如果因此使用它们定义的值,否则使用原始值。

  • STRLESSSTRGREATERSTREQUALSTRLESS_EQUALSTRGREATER_EQUAL 的左手和右手参数都被独立测试以查看它们是否是已定义的变量,如果是的话使用它们定义的值,否则使用原始值。

  • VERSION_LESSVERSION_GREATERVERSION_EQUALVERSION_LESS_EQUALVERSION_GREATER_EQUAL 的左手和右手参数都被独立测试以查看它们是否是已定义的变量,如果是的话使用它们定义的值,否则使用原始值。

  • 测试“NOT”的右侧参数以查看它是否是布尔常量,如果是则使用该值,否则假定它是变量并取消引用。

  • ANDOR 的左手和右手参数被独立测试以查看它们是否是布尔常量,如果是,则按原样使用,否则它们被假定为变量并被取消引用。

在 3.1 版本发生变更: 为防止歧义,可以在 引用的参数括号参数 中指定潜在的变量或关键字名称。带引号或括号的变量或关键字将被解释为字符串,而不是取消引用或解释。请参阅政策:policy:CMP0054

没有针对环境或缓存的自动评估 变量引用。它们的值必须被引用为 $ENV{<name>}$CACHE{<name>} 只要上面记录的条件语法接受 <variable|string>

也可以看看