if

有条件地执行一组命令。

概要

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

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

根据传统,else()endif() 命令允许可选的 <condition> 参数。如果使用,它必须是打开 if 命令的参数的完全重复。

条件语法

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

复合条件的评估优先级如下

  1. 圆括号.

  2. 一元测试,例如 COMMAND, POLICY, TARGET, TEST, EXISTS, IS_READABLE, IS_WRITABLE, IS_EXECUTABLE, IS_DIRECTORY, IS_SYMLINK, IS_ABSOLUTE, 和 DEFINED

  3. 二元测试,例如 EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL, STREQUAL, STRLESS, STRLESS_EQUAL, STRGREATER, STRGREATER_EQUAL, VERSION_EQUAL, VERSION_LESS, VERSION_LESS_EQUAL, VERSION_GREATER, VERSION_GREATER_EQUAL, PATH_EQUAL, IN_LIST, IS_NEWER_THAN, 和 MATCHES

  4. 一元逻辑运算符 NOT

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

基本表达式

if(<constant>)

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

if(<variable>)

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

if(<string>)

带引号的字符串始终评估为假,除非

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

  • 在 4.0 之前的 CMake 版本中,策略 CMP0054 未设置为 NEW,并且字符串的值恰好是受 CMP0054 行为影响的变量名。

逻辑运算符

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) 将评估为真。相比之下,如果缓存变量 someName 存在,则表达式 if(DEFINED CACHE{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(IS_READABLE) 来检查文件可读性。if(EXISTS) 将来可能会更改为仅检查文件是否存在。

if(IS_READABLE <path-to-file-or-directory>)

在 3.29 版本中添加。

如果命名的文件或目录可读,则为真。行为仅对显式完整路径定义良好(前导 ~/ 不会展开为主目录,并且被视为相对路径)。解析符号链接,即,如果命名的文件或目录是符号链接,则如果符号链接的目标可读,则返回真。

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

if(IS_WRITABLE <path-to-file-or-directory>)

在 3.29 版本中添加。

如果命名的文件或目录可写,则为真。行为仅对显式完整路径定义良好(前导 ~/ 不会展开为主目录,并且被视为相对路径)。解析符号链接,即,如果命名的文件或目录是符号链接,则如果符号链接的目标可写,则返回真。

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

if(IS_EXECUTABLE <path-to-file-or-directory>)

在 3.29 版本中添加。

如果命名的文件或目录可执行,则为真。行为仅对显式完整路径定义良好(前导 ~/ 不会展开为主目录,并且被视为相对路径)。解析符号链接,即,如果命名的文件或目录是符号链接,则如果符号链接的目标可执行,则返回真。

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

if(<file1> IS_NEWER_THAN <file2>)

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

if(IS_DIRECTORY <path>)

如果 path 是目录,则为真。行为仅对完整路径定义良好。

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

如果给定路径是符号链接,则为真。行为仅对完整路径定义良好。

if(IS_ABSOLUTE <path>)

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

  • path 评估为假。

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

  • 在非 Windows 主机上,任何以波浪号 (~) 开头的 path 都将评估为真。

比较

if(<variable|string> MATCHES <regex>)

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

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

if(<variable|string> LESS <variable|string>)

如果给定的字符串或变量的值解析为实数(如 C double),并且小于右侧的值,则为真。

if(<variable|string> GREATER <variable|string>)

如果给定的字符串或变量的值解析为实数(如 C double),并且大于右侧的值,则为真。

if(<variable|string> EQUAL <variable|string>)

如果给定的字符串或变量的值解析为实数(如 C double),并且等于右侧的值,则为真。

if(<variable|string> LESS_EQUAL <variable|string>)

在 3.7 版本中添加。

如果给定的字符串或变量的值解析为实数(如 C double),并且小于或等于右侧的值,则为真。

if(<variable|string> GREATER_EQUAL <variable|string>)

在 3.7 版本中添加。

如果给定的字符串或变量的值解析为实数(如 C double),并且大于或等于右侧的值,则为真。

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>)

在 3.7 版本中添加。

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

if(<variable|string> STRGREATER_EQUAL <variable|string>)

在 3.7 版本中添加。

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

版本比较

if(<variable|string> VERSION_LESS <variable|string>)

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

if(<variable|string> VERSION_GREATER <variable|string>)

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

if(<variable|string> VERSION_EQUAL <variable|string>)

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

if(<variable|string> VERSION_LESS_EQUAL <variable|string>)

在 3.7 版本中添加。

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

if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)

在 3.7 版本中添加。

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

路径比较

if(<variable|string> PATH_EQUAL <variable|string>)

版本 3.24 中新增。

逐个组件地按字典顺序比较两个 CMake 路径,无需访问文件系统。仅当两个路径的每个组件都匹配时,这两个路径才被视为相等。多个路径分隔符有效地折叠为单个分隔符,但请注意,反斜杠不会转换为正斜杠。不执行其他路径规范化。保留尾部斜杠,因此 /a/b/a/b/ 不相等。

由于处理多个路径分隔符,组件级比较优于基于字符串的比较。在以下示例中,使用 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()

有关更多详细信息,请参阅 cmake_path(COMPARE)

变量展开

if 命令在 CMake 历史的早期编写,早于 ${} 变量求值语法,并且为了方便起见,会如上文签名所示的那样对由其参数命名的变量进行求值。请注意,使用 ${} 的正常变量求值在 if 命令甚至接收到参数之前就已应用。因此,如下代码:

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

对于 if 命令来说,看起来像是:

if(var1)

并根据上面记录的 if(<variable>) 情况进行求值。结果是 OFF,即为假。但是,如果我们从示例中删除 ${},则该命令会看到:

if(var2)

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

只要上述文档化的条件语法接受 <variable|string>,自动求值就适用于其他情况

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

  • 如果 MATCHES 的左侧参数缺失,则返回 false 而不报错

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

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

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

  • IN_LIST 的左侧参数会被测试,以查看它是否是已定义的变量。如果是,则使用该变量的值,否则使用原始值。

  • NOT 的右侧参数会被测试,以查看它是否是布尔常量。如果是,则使用该值,否则假定它是一个变量并被解引用。

  • ANDOR 的左侧和右侧参数都会被独立测试,以查看它们是否是布尔常量。如果是,则将它们用作布尔常量,否则假定它们是变量并被解引用。

在版本 3.1 中更改:为了防止歧义,潜在的变量或关键字名称可以在带引号的参数方括号参数中指定。带引号或带方括号的变量或关键字将被解释为字符串,而不会被解引用或解释。请参阅策略 CMP0054

对于环境或缓存变量引用,没有自动求值。无论上述文档化的条件语法在何处接受 <variable|string>,它们的值都必须以 $ENV{<name>}$CACHE{<name>} 的形式引用。

另请参阅