cmake-language(7)¶
組織¶
CMake 輸入檔以 "CMake 語言" 撰寫,原始檔名為 CMakeLists.txt
或以 .cmake
副檔名結尾。
專案中的 CMake 語言原始檔組織成
目錄¶
當 CMake 處理專案原始碼樹狀結構時,入口點是頂層原始碼目錄中名為 CMakeLists.txt
的原始檔。此檔案可能包含完整的建置規範,或使用 add_subdirectory()
命令將子目錄新增至建置。命令新增的每個子目錄也必須包含一個 CMakeLists.txt
檔案作為該目錄的入口點。對於每個處理其 CMakeLists.txt
檔案的原始碼目錄,CMake 會在建置樹狀結構中產生一個對應的目錄,作為預設的工作和輸出目錄。
腳本¶
可以使用 cmake(1)
命令列工具和 -P
選項,以腳本模式處理個別的 <script>.cmake
原始檔。腳本模式僅執行給定的 CMake 語言原始檔中的命令,而不產生建置系統。它不允許定義建置目標或動作的 CMake 命令。
模組¶
目錄 或 腳本 中的 CMake 語言程式碼可以使用 include()
命令,在包含上下文的範圍內載入 <module>.cmake
原始檔。請參閱 cmake-modules(7)
手冊頁,以取得 CMake 發行版中包含的模組文件。專案原始碼樹狀結構也可以提供自己的模組,並在 CMAKE_MODULE_PATH
變數中指定其位置。
語法¶
編碼¶
CMake 語言原始檔可以使用 7 位元 ASCII 文字撰寫,以在所有支援的平台上達到最大的可攜性。換行符號可以編碼為 \n
或 \r\n
,但在讀取輸入檔時會轉換為 \n
。
請注意,實作是 8 位元乾淨的,因此在具有支援此編碼的系統 API 的平台上,原始檔可以編碼為 UTF-8。此外,CMake 3.2 及更高版本支援 Windows 上以 UTF-8 編碼的原始檔 (使用 UTF-16 呼叫系統 API)。此外,CMake 3.0 及更高版本允許原始檔中具有前導 UTF-8 位元組順序記號。
原始檔¶
CMake 語言原始檔由零或多個 命令調用 組成,以換行符號分隔,並可選擇性地使用空格和 註解
file ::=file_element
* file_element ::=command_invocation
line_ending
| (bracket_comment
|space
)*line_ending
line_ending ::=line_comment
?newline
space ::= <match '[ \t]+'> newline ::= <match '\n'>
命令調用¶
命令調用是一個名稱,後跟以括號括住並以空白分隔的參數
command_invocation ::=space
*identifier
space
* '('arguments
')' identifier ::= <match '[A-Za-z_][A-Za-z0-9_]*'> arguments ::=argument
?separated_arguments
* separated_arguments ::=separation
+argument
? |separation
* '('arguments
')' separation ::=space
|line_ending
例如
add_executable(hello world.c)
命令名稱不區分大小寫。參數中巢狀的無引號括號必須平衡。每個 (
或 )
都會作為常值 無引號參數 提供給命令調用。這可以用於呼叫 if()
命令以括住條件。例如
if(FALSE AND (FALSE OR TRUE)) # evaluates to FALSE
命令參數¶
命令調用 中有三種類型的參數
argument ::=bracket_argument
|quoted_argument
|unquoted_argument
方括號參數¶
方括號參數,靈感來自 Lua 長方括號語法,將內容括在相同長度的開頭和結尾 "方括號" 之間
bracket_argument ::=bracket_open
bracket_content
bracket_close
bracket_open ::= '[' '='* '[' bracket_content ::= <any text not containing abracket_close
with the same number of '=' as thebracket_open
> bracket_close ::= ']' '='* ']'
開頭方括號寫為 [
,後跟零或多個 =
,再後跟 [
。對應的結尾方括號寫為 ]
,後跟相同數量的 =
,再後跟 ]
。方括號不會巢狀。始終可以為開頭和結尾方括號選擇唯一的長度,以包含其他長度的結尾方括號。
方括號參數內容由開頭和結尾方括號之間的所有文字組成,但緊接在開頭方括號之後的一個換行符號 (如果有的話) 會被忽略。不會對括住的內容執行評估,例如 跳脫序列 或 變數參考。方括號參數始終作為一個參數提供給命令調用。
例如
message([=[
This is the first line in a bracket argument with bracket length 1.
No \-escape sequences or ${variable} references are evaluated.
This is always one argument even though it contains a ; character.
The text does not end on a closing bracket of length 0 like ]].
It does end in a closing bracket of length 1.
]=])
注意
3.0 之前的 CMake 版本不支援方括號參數。它們將開頭方括號解釋為 無引號參數 的開始。
引號參數¶
引號參數將內容括在開頭和結尾雙引號字元之間
quoted_argument ::= '"'quoted_element
* '"' quoted_element ::= <any character except '\' or '"'> |escape_sequence
|quoted_continuation
quoted_continuation ::= '\'newline
引號參數內容由開頭和結尾引號之間的所有文字組成。跳脫序列 和 變數參考 都會被評估。引號參數始終作為一個參數提供給命令調用。
例如
message("This is a quoted argument containing multiple lines.
This is always one argument even though it contains a ; character.
Both \\-escape sequences and ${variable} references are evaluated.
The text does not end on an escaped double-quote like \".
It does end in an unescaped double quote.
")
任何以奇數個反斜線結尾的行上的最後一個 \
都會被視為行繼續符號,並與緊隨其後的換行符號一起忽略。例如
message("\
This is the first line of a quoted argument. \
In fact it is the only line but since it is long \
the source code uses line continuation.\
")
注意
3.0 之前的 CMake 版本不支援使用 \
繼續。它們會報告引號參數中包含以奇數個 \
字元結尾的行的錯誤。
無引號參數¶
無引號參數未以任何引號語法括住。除了以反斜線跳脫之外,它可能不包含任何空白、(
、)
、#
、"
或 \
unquoted_argument ::=unquoted_element
+ |unquoted_legacy
unquoted_element ::= <any character except whitespace or one of '()#"\'> |escape_sequence
unquoted_legacy ::= <see note in text>
無引號參數內容由允許或跳脫字元的連續區塊中的所有文字組成。跳脫序列 和 變數參考 都會被評估。結果值以 列表 分割成元素的方式分割。每個非空元素都作為一個參數提供給命令調用。因此,無引號參數可以作為零個或多個參數提供給命令調用。
例如
foreach(arg
NoSpace
Escaped\ Space
This;Divides;Into;Five;Arguments
Escaped\;Semicolon
)
message("${arg}")
endforeach()
注意
為了支援舊版 CMake 程式碼,無引號參數也可能包含雙引號字串 ("..."
,可能括住水平空白) 和 make 樣式變數參考 ($(MAKEVAR)
)。
未跳脫的雙引號必須平衡,不得出現在無引號參數的開頭,並被視為內容的一部分。例如,無引號參數 -Da="b c"
、-Da=$(v)
和 a" "b"c"d
都會按字面意義解釋。它們可以改為寫為引號參數 "-Da=\"b c\""
、"-Da=$(v)"
和 "a\" \"b\"c\"d"
。
Make 樣式參考按字面意義視為內容的一部分,並且不會進行變數展開。它們被視為單個參數的一部分 (而不是作為單獨的 $
、(
、MAKEVAR
和 )
參數)。
上面的 "unquoted_legacy" 產生式代表此類參數。我們不建議在新程式碼中使用舊版無引號參數。而是使用 引號參數 或 方括號參數 來表示內容。
跳脫序列¶
跳脫序列是一個 \
,後跟一個字元
escape_sequence ::=escape_identity
|escape_encoded
|escape_semicolon
escape_identity ::= '\' <match '[^A-Za-z0-9;]'> escape_encoded ::= '\t' | '\r' | '\n' escape_semicolon ::= '\;'
後跟非字母數字字元的 \
只會編碼常值字元,而不會將其解釋為語法。\t
、\r
或 \n
分別編碼 Tab 字元、歸位字元或換行字元。任何 變數參考 外部的 \;
會編碼自身,但可以在 無引號參數 中使用,以編碼 ;
,而不會在其上分割參數值。變數參考 內的 \;
會編碼常值 ;
字元。(另請參閱政策 CMP0053
文件以了解歷史考量。)
變數參考¶
變數參考的格式為 ${<variable>}
,並在 引號參數 或 無引號參數 內評估。變數參考會由指定變數或快取項目的值取代,如果兩者都未設定,則由空字串取代。變數參考可以巢狀,並且從內到外評估,例如 ${outer_${inner_variable}_variable}
。
常值變數參考可以由字母數字字元、字元 /_.+-
和 跳脫序列 組成。巢狀參考可以用於評估任何名稱的變數。另請參閱政策 CMP0053
文件以了解歷史考量以及 $
在技術上也允許但不建議使用的原因。
變數 區段說明了變數名稱的範圍以及如何設定其值。
環境變數參考的格式為 $ENV{<variable>}
。請參閱 環境變數 區段以取得更多資訊。
快取變數參考的格式為 $CACHE{<variable>}
,並由指定快取項目的值取代,而不會檢查是否有名稱相同的普通變數。如果快取項目不存在,則會由空字串取代。請參閱 CACHE
以取得更多資訊。
if()
命令具有特殊的條件語法,允許使用簡短格式 <variable>
而不是 ${<variable>}
的變數參考。但是,環境變數始終需要參考為 $ENV{<variable>}
。
控制結構¶
條件區塊¶
迴圈¶
foreach()
/endforeach()
和 while()
/endwhile()
命令分隔要在迴圈中執行的程式碼區塊。在此類區塊內,可以使用 break()
命令提早終止迴圈,而可以使用 continue()
命令立即開始下一次迭代。
命令定義¶
macro()
/endmacro()
和 function()
/endfunction()
命令分隔要記錄以供稍後作為命令調用的程式碼區塊。
變數¶
變數是 CMake 語言中的基本儲存單位。它們的值始終為字串類型,儘管某些命令可能會將字串解釋為其他類型的值。set()
和 unset()
命令明確設定或取消設定變數,但其他命令也具有修改變數的語意。變數名稱區分大小寫,並且可以由幾乎任何文字組成,但我們建議堅持僅由字母數字字元加上 _
和 -
組成的名稱。
變數具有動態範圍。每個 "set" 或 "unset" 變數都會在目前範圍中建立繫結
- 區塊範圍
block()
命令可以為變數繫結建立新的範圍。- 函式範圍
由
function()
命令建立的 命令定義 會建立命令,這些命令在調用時,會在新的變數繫結範圍中處理記錄的命令。"set" 或 "unset" 變數會在此範圍內繫結,並且對於目前的函式及其中的任何巢狀呼叫都是可見的,但在函式傳回後則不可見。- 目錄範圍
原始碼樹狀結構中的每個 目錄 都有自己的變數繫結。在處理目錄的
CMakeLists.txt
檔案之前,CMake 會複製目前在父目錄中定義的所有變數繫結 (如果有的話),以初始化新的目錄範圍。當使用cmake -P
處理時,CMake 腳本 會在一個 "目錄" 範圍中繫結變數。不在函式呼叫內的 "set" 或 "unset" 變數會繫結到目前的目錄範圍。
- 持久性快取
CMake 儲存一組單獨的 "快取" 變數,或 "快取項目",其值在專案建置樹狀結構中的多次執行中保持不變。快取項目具有隔離的繫結範圍,僅透過明確請求修改,例如透過
set()
和unset()
命令的CACHE
選項。
在評估 變數參考 時,CMake 首先搜尋函式呼叫堆疊 (如果有的話) 以尋找繫結,然後回退到目前目錄範圍中的繫結 (如果有的話)。如果找到 "set" 繫結,則會使用其值。如果找到 "unset" 繫結,或未找到繫結,則 CMake 會搜尋快取項目。如果找到快取項目,則會使用其值。否則,變數參考會評估為空字串。$CACHE{VAR}
語法可用於執行直接快取項目查找。
cmake-variables(7)
手冊說明了 CMake 提供的許多變數,或專案程式碼設定時對 CMake 具有意義的變數。
環境變數¶
環境變數與普通 變數 類似,但有以下差異
- 範圍
環境變數在 CMake 處理程序中具有全域範圍。它們永遠不會被快取。
- 參考
- 初始化
CMake 環境變數的初始值是呼叫處理程序的值。可以使用
set()
和unset()
命令來變更值。這些命令僅影響正在執行的 CMake 處理程序,而不影響整個系統環境。變更的值不會寫回呼叫處理程序,並且後續的建置或測試處理程序看不到它們。請參閱
cmake -E env
命令列工具,以在修改後的環境中執行命令。- 檢查
請參閱
cmake -E environment
命令列工具,以顯示所有目前的環境變數。
cmake-env-variables(7)
手冊說明了對 CMake 具有特殊意義的環境變數。
列表¶
雖然 CMake 中的所有值都儲存為字串,但在某些情況下,例如在評估 無引號參數 期間,字串可以被視為列表。在此類情況下,字串會透過在 ;
字元上分割來分割成列表元素,這些字元不遵循不等數量的 [
和 ]
字元,並且不會緊接在 \
之後。序列 \;
不會分割值,而是在結果元素中由 ;
取代。
元素列表表示為字串,方法是串連以 ;
分隔的元素。例如,set()
命令將多個值儲存到目的地變數中作為列表
set(srcs a.c b.c c.c) # sets "srcs" to "a.c;b.c;c.c"
列表旨在用於簡單的用例,例如原始檔列表,不應用於複雜的資料處理任務。大多數建構列表的命令不會跳脫列表元素中的 ;
字元,因此會展平巢狀列表
set(x a "b;c") # sets "x" to "a;b;c", not "a;b\;c"
一般來說,列表不支援包含 ;
字元的元素。為了避免問題,請考慮以下建議
許多 CMake 命令、變數和屬性的介面接受以分號分隔的列表。除非它們記錄直接支援或某種跳脫或編碼分號的方式,否則請避免將包含分號的元素的列表傳遞到這些介面。
在建構列表時,在元素中將
;
替換為其他未使用的佔位符。然後在處理列表元素時,將佔位符替換為;
。例如,以下程式碼使用|
代替;
字元set(mylist a "b|c") foreach(entry IN LISTS mylist) string(REPLACE "|" ";" entry "${entry}") # use "${entry}" normally endforeach()
ExternalProject
模組的LIST_SEPARATOR
選項是使用此方法建構的介面範例。在
產生器運算式
列表中,請使用$<SEMICOLON>
產生器運算式。在
function()
的實作中,請避免使用ARGV
和ARGN
,因為它們無法區分數值中的分號和分隔數值的分號。請改為偏好使用具名的位置引數以及ARGC
和ARGV#
變數。當使用cmake_parse_arguments()
來解析引數時,請偏好使用其PARSE_ARGV
簽名,它會使用ARGV#
變數。請注意,此方法不適用於
macro()
的實作,因為它們使用佔位符 (placeholders) 而非真實變數來引用引數。
註解¶
註解以
#
字元開頭,該字元不在 方括號參數、引號參數 內,或未在 無引號參數 中以\
跳脫。註解有兩種類型:方括號註解 和 行註解。方括號註解¶
緊接在
bracket_open
之後的#
會形成方括號註解,該註解由整個方括號括住部分組成例如
注意
3.0 之前的 CMake 版本不支援方括號註解。它們將開頭
#
解釋為 行註解 的開始。行註解¶
未緊接在
bracket_open
之後的#
會形成行註解,該註解會執行到行尾例如