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) 將評估為真。相比之下,僅當快取變數 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 主機上,任何以磁碟機代號和冒號(例如 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>)

Added in version 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,即 false。但是,如果我們從範例中移除 ${},則命令會看到:

if(var2)

這是 true,因為 var2 定義為 var1,而 var1 不是 false 常數。

在其他情況下,只要上述記載的條件語法接受 <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

環境或快取變數參照沒有自動評估。它們的值必須參照為 $ENV{<name>}$CACHE{<name>},只要上述記載的條件語法接受 <variable|string> 即可。

另請參閱