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. 一元测试,例如 COMMANDPOLICYTARGETTESTEXISTSIS_READABLEIS_WRITABLEIS_EXECUTABLEIS_DIRECTORYIS_SYMLINKIS_ABSOLUTEDEFINED

  3. 二元测试,例如 EQUALLESSLESS_EQUALGREATERGREATER_EQUALSTREQUALSTRLESSSTRLESS_EQUALSTRGREATERSTRGREATER_EQUALVERSION_EQUALVERSION_LESSVERSION_LESS_EQUALVERSION_GREATERVERSION_GREATER_EQUALPATH_EQUALIN_LISTIS_NEWER_THANMATCHES

  4. 一元逻辑运算符 NOT

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

基本表达式

if(<constant>)

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

if(<variable>)

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

if(<string>)

除非字符串的值是真常量之一,否则带引号的字符串始终评估为假,或者

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

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

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

在版本 2.6 中添加: () 组被捕获在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>}

另请参阅