if

有条件地执行一组命令。

语法

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

根据下面所述的 条件语法 求值 condition if 子句的参数。如果结果为真,则将执行 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>)

除非满足以下条件,否则引用字符串始终计算为假:

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

  • 策略 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 <路径到文件或目录>)

如果命名文件或目录存在并且可读,则为 True。只有对明确的全路径才定义明确的行为(前导 ~/ 没有作为主目录展开并且被视为相对路径)。解析符号链接,即如果命名文件或目录是符号链接,如果符号链接的目标存在,则返回 true。

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

请注意

首选 if(IS_READABLE) 来检查文件可读性。 if(EXISTS) 今后可能会更改为仅检查文件是否存在。

if(IS_READABLE <路径到文件或目录>)

在 3.29 版本中添加。

如果命名文件或目录可读,则为 True。只有对明确的全路径才定义明确的行为(前导 ~/ 没有作为主目录展开并且被视为相对路径)。解析符号链接,即如果命名文件或目录是符号链接,如果符号链接的目标可读,则返回 true。

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

if(IS_WRITABLE <路径到文件或目录>)

在 3.29 版本中添加。

如果命名文件或目录可写,则为 True。只有对明确的全路径才定义明确的行为(前导 ~/ 没有作为主目录展开并且被视为相对路径)。解析符号链接,即如果命名文件或目录是符号链接,如果符号链接的目标可写,则返回 true。

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

if(IS_EXECUTABLE <路径到文件或目录>)

在 3.29 版本中添加。

如果命名文件或目录可执行,则为 True。只有对明确的全路径才定义明确的行为(前导 ~/ 没有作为主目录展开并且被视为相对路径)。解析符号链接,即如果命名文件或目录是符号链接,如果符号链接的目标可执行,则返回 true。

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

if(<file1> IS_NEWER_THAN <file2>)

如果 file1file2 新,或者两个文件之一不存在,则为 True。只有对全路径才定义明确的行为。如果文件时间戳完全相同,则 IS_NEWER_THAN 比较将返回 true,以便在出现平局时进行任何依赖构建操作。这包括对 file1 和 file2 传递相同文件名的情况。

if(IS_DIRECTORY <path>)

如果 path 是一个目录,则为真。其行为仅对完整路径定义明确。

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

如果给定的路径是一个符号链接,则为真。其行为仅对完整路径定义明确。

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),并且小于右侧,则为 True。

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

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

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

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

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

3.7 版本中添加。

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

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

3.7 版本中添加。

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

if(<变量|字符串> STRLESS <变量|字符串>)

如果给定的字符串或变量的值按字面顺序小于其右边的字符串或变量,则为真。

if(<变量|字符串> STRGREATER <变量|字符串>)

如果给定的字符串或变量的值按字面顺序大于其右边的字符串或变量,则为真。

if(<变量|字符串> STREQUAL <变量|字符串>)

如果给定的字符串或变量的值按字面顺序等于其右边的字符串或变量,则为真。

if(<变量|字符串> STRLESS_EQUAL <变量|字符串>)

3.7 版本中添加。

如果给定的字符串或变量的值按字面顺序小于或等于其右边的字符串或变量,则为真。

if(<变量|字符串> STRGREATER_EQUAL <变量|字符串>)

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 版本当中新增。

逐步比较两个路径的组件。仅当两个路径的每个路径相匹配时,两个路径才能相等。多个路径分隔符有效地折叠成一个分隔符,但请注意,反斜杠尚未转换为正斜杠。没有执行任何其他路径规范化

由于处理多个路径分隔符,组件比较优于基于字符串的比较。在下例中,表达式使用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的左手参数缺失,它将在没有错误的情况下返回 false

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

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

  • VERSION_LESSVERSION_GREATERVERSION_EQUALVERSION_LESS_EQUALVERSION_GREATER_EQUAL 的左右手运算符进行独立测试,以判断它们是否是定义的变量。如果它们是定义的变量,则使用其定义的值,否则使用原始值。

  • IN_LIST 的左手运算符进行测试,以判断它是否是定义的变量。如果它是定义的变量,则使用该变量的值,否则使用原始值。

  • NOT 的右手运算符进行测试,以判断它是否是布尔常量。如果它是一个布尔常量,则使用该值,否则假定它是一个变量,对其进行解除引用处理。

  • ANDOR 的左手和右手运算符进行独立测试,以判断它们是否是布尔常量。如果它们是布尔常量,则以这种方式使用它们,否则假定它们是变量,对其进行解除引用处理。

版本 3.1 中更改:为了防止出现歧义,可以在 带引号的运算符括号运算符 中指定潜在的变量或关键字名称。带引号或括号的变量或关键字将被解释为一个字符串,且不会被解除引用或解释。请参见策略 CMP0054

对于环境或缓存 变量引用 没有任何自动评估。它们的 value 必须以 $ENV{<name>}$CACHE{<name>} 的形式引用,只要上述记录条件语法接受 <variable|string> 即可。

另请参见