cmake-language(7)¶
組織¶
CMake 輸入檔是以「CMake 語言」撰寫,並儲存在名為 CMakeLists.txt
或以 .cmake
副檔名結尾的原始檔中。
專案中的 CMake 語言原始檔會組織成
目錄¶
當 CMake 處理專案原始碼樹狀結構時,進入點是位於最上層原始碼目錄中名為 CMakeLists.txt
的原始檔。此檔案可以包含整個建置規範,或使用 add_subdirectory()
命令來將子目錄新增至建置。此命令新增的每個子目錄也必須包含一個 CMakeLists.txt
檔案作為該目錄的進入點。對於每個處理過其 CMakeLists.txt
檔案的原始碼目錄,CMake 會在建置樹狀結構中產生一個對應的目錄,作為預設的工作和輸出目錄。
腳本¶
可以使用帶有 -P
選項的 cmake(1)
命令列工具,以腳本模式處理個別的 <script>.cmake
原始檔。腳本模式只會執行指定的 CMake 語言原始檔中的命令,而不會產生建置系統。它不允許使用定義建置目標或動作的 CMake 命令。
模組¶
目錄或腳本中的 CMake 語言程式碼可以使用 include()
命令,在包含的內容範圍內載入 <module>.cmake
原始檔。如需 CMake 發行版中包含的模組文件,請參閱 cmake-modules(7)
手冊頁面。專案原始碼樹狀結構也可以提供自己的模組,並在 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、carriage return 或換行字元。在任何變數引用之外的 \;
會編碼成自身,但可以在未加引號的參數中使用,以編碼 ;
而不會因此分割參數值。\;
在變數引用內部會編碼成字面上的 ;
字元。(另請參閱政策 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()
指令會明確地設定或取消設定變數,但其他指令也有修改變數的語意。變數名稱區分大小寫,而且可以使用幾乎任何文字,但我們建議只使用由字母數字字元加上 _
和 -
組成的名稱。
變數具有動態範圍。每次「設定」或「取消設定」變數都會在目前範圍中建立繫結。
- 區塊範圍
block()
指令可以為變數繫結建立新的範圍。- 函式範圍
由
function()
指令建立的 指令定義,在被調用時,會在新的變數繫結範圍中處理已記錄的指令。變數的「設定」或「取消設定」會繫結在此範圍中,且對於目前的函式和其中的任何巢狀呼叫可見,但在函式返回後則不可見。- 目錄範圍
來源樹中的每個 目錄 都有自己的變數繫結。在處理目錄的
CMakeLists.txt
檔案之前,CMake 會複製父目錄中目前定義的所有變數繫結(如果有的話),以初始化新的目錄範圍。使用cmake -P
處理的 CMake 指令碼,會在一個「目錄」範圍中繫結變數。不在函式呼叫中的變數「設定」或「取消設定」會繫結到目前的目錄範圍。
- 持久快取
CMake 會儲存一組獨立的「快取」變數,或稱為「快取條目」,其值會在專案建置樹狀結構中的多次執行之間持續存在。快取條目具有隔離的繫結範圍,只有在明確請求時才會修改,例如透過
set()
和unset()
指令的CACHE
選項。
在評估 變數參考 時,CMake 會先搜尋函式呼叫堆疊(如果有的話)尋找繫結,然後回溯到目前目錄範圍中的繫結(如果有的話)。如果找到「設定」繫結,則會使用其值。如果找到「取消設定」繫結,或找不到繫結,CMake 則會搜尋快取條目。如果找到快取條目,則會使用其值。否則,變數參考會評估為空字串。可以使用 $CACHE{VAR}
語法來進行直接快取條目查詢。
cmake-variables(7)
手冊記錄了 CMake 提供的許多變數,或是由專案程式碼設定時對 CMake 具有意義的變數。
請注意
CMake 保留以下開頭的識別符號:
以
CMAKE_
開頭(大寫、小寫或混合大小寫),或以
_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()
的實作,因為它們使用佔位符而非真實變數來引用引數。
註解¶
註解以
#
字元開頭,該字元不是在括號參數、加引號的參數內部,也不是在未加引號的參數中以\
跳脫。註解有兩種:括號註解和行註解。括號註解¶
緊接在
#
後面的bracket_open
構成一個 括號註解,該註解包含整個括號封閉。例如
請注意
3.0 之前的 CMake 版本不支援括號註解。它們會將開頭的
#
解釋為行註解的開始。行註解¶
緊接在
#
後面不是bracket_open
的情形會構成一個行註解,該註解會持續到該行末尾。例如