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, and 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, and MATCHES

  4. 一元逻辑运算符 NOT

  5. 二元逻辑运算符 ANDOR,从左到右,无短路。

基本表达式

if(<constant>)

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

if(<variable>)

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

if(<string>)

除非满足以下条件,否则带引号的字符串始终评估为 false:

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

  • 在 CMake 4.0 之前的版本中,策略 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> 是否为非缓存变量。表达式 if(DEFINED someName) 如果存在缓存或非缓存变量 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(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 主机上,任何以驱动器盘符和冒号(例如 C:)、正斜杠或反斜杠开头的 path 都将评估为真。这意味着像 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 时表达式评估为 true,但使用 STREQUAL 时评估为 false。

# 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>}

另请参阅