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

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

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

  • 在 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) 将评估为真。相比之下,表达式 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,后者不是假常量。

在上述记录的条件语法接受 <variable|string> 的其他情况下,会自动应用求值。

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

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

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

另请参阅