cmake_path¶
於版本 3.20 新增。
此命令用於操作路徑。僅處理路徑的語法方面,不與任何底層檔案系統進行任何互動。路徑可以表示不存在的路徑,甚至是當前檔案系統或平台上不允許存在的路徑。對於與檔案系統互動的操作,請參閱 file()
命令。
注意
cmake_path
命令處理的路徑格式為建置系統的格式(即主機平台),而非目標系統。當進行交叉編譯時,如果路徑包含在主機平台上無法表示的元素(例如,當主機不是 Windows 時的磁碟機代號),則結果將不可預測。
概要¶
Conventions Path Structure And Terminology Normalization Decomposition cmake_path(GET <path-var> ROOT_NAME <out-var>) cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>) cmake_path(GET <path-var> ROOT_PATH <out-var>) cmake_path(GET <path-var> FILENAME <out-var>) cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>) cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>) cmake_path(GET <path-var> RELATIVE_PART <out-var>) cmake_path(GET <path-var> PARENT_PATH <out-var>) Query cmake_path(HAS_ROOT_NAME <path-var> <out-var>) cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>) cmake_path(HAS_ROOT_PATH <path-var> <out-var>) cmake_path(HAS_FILENAME <path-var> <out-var>) cmake_path(HAS_EXTENSION <path-var> <out-var>) cmake_path(HAS_STEM <path-var> <out-var>) cmake_path(HAS_RELATIVE_PART <path-var> <out-var>) cmake_path(HAS_PARENT_PATH <path-var> <out-var>) cmake_path(IS_ABSOLUTE <path-var> <out-var>) cmake_path(IS_RELATIVE <path-var> <out-var>) cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>) cmake_path(COMPARE <input1> <OP> <input2> <out-var>) Modification cmake_path(SET <path-var> [NORMALIZE] <input>) cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>]) cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>]) cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>]) cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>]) cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>]) cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>]) Generation cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>]) cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>]) cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>]) Native Conversion cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>) cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE]) cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE]) Hashing cmake_path(HASH <path-var> <out-var>)
慣例¶
以下慣例用於此命令的文件中
<path-var>
始終為變數的名稱。對於期望
<path-var>
作為輸入的命令,該變數必須存在,並且應包含單一路徑。<input>
字串文字,可能包含路徑、路徑片段,或根據命令具有特殊分隔符的多個路徑。請參閱每個命令的說明,以了解其如何被解讀。
<input>...
零或多個字串文字參數。
<out-var>
變數的名稱,命令的結果將寫入其中。
路徑結構與術語¶
路徑具有以下結構(所有組件都是可選的,但有一些限制)
root-name root-directory-separator (item-name directory-separator)* filename
根名稱 (root-name)
在具有多個根目錄的檔案系統上識別根目錄(例如
"C:"
或"//myserver"
)。它是可選的。根目錄分隔符 (root-directory-separator)
如果存在,則表示此路徑為絕對路徑的目錄分隔符。如果缺少,並且
root-name
以外的第一個元素是item-name
,則路徑是相對路徑。項目名稱 (item-name)
非目錄分隔符的一系列字元。此名稱可以識別檔案、硬連結、符號連結或目錄。會識別兩種特殊情況
由單個點字元
.
組成的項目名稱是一個目錄名稱,指代當前目錄。由兩個點字元
..
組成的項目名稱是一個目錄名稱,指代父目錄。
上面顯示的
(...)*
模式表示可以有零個或多個項目名稱,多個項目由directory-separator
分隔。()*
字元不是路徑的一部分。目錄分隔符 (directory-separator)
唯一可識別的目錄分隔符是正斜線字元
/
。如果重複此字元,則將其視為單個目錄分隔符。換句話說,/usr///////lib
與/usr/lib
相同。
檔名 (filename)
如果路徑不以
directory-separator
結尾,則它具有filename
。filename
實際上是路徑的最後一個item-name
,因此它也可以是硬連結、符號連結或目錄。filename
可以具有*副檔名*。預設情況下,副檔名定義為從最左邊的句點(包括句點)開始到filename
結尾的子字串。在接受LAST_ONLY
關鍵字的命令中,LAST_ONLY
會將解釋更改為從最右邊的句點開始的子字串。以下例外情況適用於上述解釋
如果
filename
中的第一個字元是句點,則忽略該句點(即,像".profile"
這樣的filename
被視為沒有副檔名)。如果
filename
是.
或..
,則它沒有副檔名。
*詞幹*是
filename
中副檔名之前的部分。
某些命令會參考 root-path
。這是 root-name
和 root-directory-separator
的串聯,其中任何一個或兩個都可以為空。relative-part
指的是刪除所有 root-path
的完整路徑。
建立路徑變數¶
雖然可以使用普通的 set()
命令小心地建立路徑,但建議改用 cmake_path(SET),因為它會在需要時自動將路徑轉換為所需的格式。cmake_path(APPEND) 子命令可能是另一個合適的替代方案,其中需要透過聯結片段來建構路徑。以下範例比較了三種建構相同路徑的方法
set(path1 "${CMAKE_CURRENT_SOURCE_DIR}/data")
cmake_path(SET path2 "${CMAKE_CURRENT_SOURCE_DIR}/data")
cmake_path(APPEND path3 "${CMAKE_CURRENT_SOURCE_DIR}" "data")
修改和 產生子命令可以就地儲存結果,也可以儲存在以 OUTPUT_VARIABLE
關鍵字命名的單獨變數中。所有其他子命令都將結果儲存在強制性的 <out-var>
變數中。
正規化¶
某些子命令支援*正規化*路徑。用於正規化路徑的演算法如下
如果路徑為空,則停止(空路徑的正規化形式也是空路徑)。
將每個
directory-separator
(可能由多個分隔符組成)替換為單個/
(/a///b --> /a/b
)。移除每個單獨的句點 (
.
) 和任何緊接其後的directory-separator
(/a/./b/. --> /a/b
)。移除每個緊接其後跟著
directory-separator
和..
的item-name
(..
除外),以及任何緊接其後的directory-separator
(/a/b/../c --> a/c
)。如果存在
root-directory
,則移除任何..
和任何緊接其後的directory-separators
。根目錄的父目錄仍被視為根目錄(/../a --> /a
)。如果最後一個
item-name
是..
,則移除任何尾隨的directory-separator
(../ --> ..
)。如果此階段路徑為空,則加入一個
dot
(./
的正規形式是.
)。
分解¶
GET
子命令的以下形式分別從路徑中檢索不同的元件或元件組。請參閱 路徑結構與術語,以了解每個路徑元件的含義。
cmake_path(GET <path-var> ROOT_NAME <out-var>)
cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
cmake_path(GET <path-var> ROOT_PATH <out-var>)
cmake_path(GET <path-var> FILENAME <out-var>)
cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> RELATIVE_PART <out-var>)
cmake_path(GET <path-var> PARENT_PATH <out-var>)
如果請求的元件未出現在路徑中,則會在 <out-var>
中儲存空字串。例如,只有 Windows 系統具有 root-name
的概念,因此當主機是非 Windows 時,ROOT_NAME
子命令將始終返回空字串。
對於 PARENT_PATH
,如果 HAS_RELATIVE_PART 子命令返回 false,則結果是 <path-var>
的副本。請注意,這表示根目錄被視為具有父目錄,而該父目錄是它本身。如果 HAS_RELATIVE_PART 返回 true,則結果本質上是 <path-var>
減少一個元素。
根目錄範例¶
set(path "c:/a")
cmake_path(GET path ROOT_NAME rootName)
cmake_path(GET path ROOT_DIRECTORY rootDir)
cmake_path(GET path ROOT_PATH rootPath)
message("Root name is \"${rootName}\"")
message("Root directory is \"${rootDir}\"")
message("Root path is \"${rootPath}\"")
Root name is "c:"
Root directory is "/"
Root path is "c:/"
檔名範例¶
set(path "/a/b")
cmake_path(GET path FILENAME filename)
message("First filename is \"${filename}\"")
# Trailing slash means filename is empty
set(path "/a/b/")
cmake_path(GET path FILENAME filename)
message("Second filename is \"${filename}\"")
First filename is "b"
Second filename is ""
副檔名和詞幹範例¶
set(path "name.ext1.ext2")
cmake_path(GET path EXTENSION fullExt)
cmake_path(GET path STEM fullStem)
message("Full extension is \"${fullExt}\"")
message("Full stem is \"${fullStem}\"")
# Effect of LAST_ONLY
cmake_path(GET path EXTENSION LAST_ONLY lastExt)
cmake_path(GET path STEM LAST_ONLY lastStem)
message("Last extension is \"${lastExt}\"")
message("Last stem is \"${lastStem}\"")
# Special cases
set(dotPath "/a/.")
set(dotDotPath "/a/..")
set(someMorePath "/a/.some.more")
cmake_path(GET dotPath EXTENSION dotExt)
cmake_path(GET dotPath STEM dotStem)
cmake_path(GET dotDotPath EXTENSION dotDotExt)
cmake_path(GET dotDotPath STEM dotDotStem)
cmake_path(GET dotMorePath EXTENSION someMoreExt)
cmake_path(GET dotMorePath STEM someMoreStem)
message("Dot extension is \"${dotExt}\"")
message("Dot stem is \"${dotStem}\"")
message("Dot-dot extension is \"${dotDotExt}\"")
message("Dot-dot stem is \"${dotDotStem}\"")
message(".some.more extension is \"${someMoreExt}\"")
message(".some.more stem is \"${someMoreStem}\"")
Full extension is ".ext1.ext2"
Full stem is "name"
Last extension is ".ext2"
Last stem is "name.ext1"
Dot extension is ""
Dot stem is "."
Dot-dot extension is ""
Dot-dot stem is ".."
.some.more extension is ".more"
.some.more stem is ".some"
相對部分範例¶
set(path "c:/a/b")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")
set(path "c/d")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")
set(path "/")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")
Relative part is "a/b"
Relative part is "c/d"
Relative part is ""
路徑遍歷範例¶
set(path "c:/a/b")
cmake_path(GET path PARENT_PATH result)
message("Parent path is \"${result}\"")
set(path "c:/")
cmake_path(GET path PARENT_PATH result)
message("Parent path is \"${result}\"")
Parent path is "c:/a"
Parent path is "c:/"
查詢¶
每個 GET
子命令都有一個對應的 HAS_...
子命令,可用於發現是否存在特定的路徑元件。請參閱 路徑結構與術語,以了解每個路徑元件的含義。
cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
cmake_path(HAS_FILENAME <path-var> <out-var>)
cmake_path(HAS_EXTENSION <path-var> <out-var>)
cmake_path(HAS_STEM <path-var> <out-var>)
cmake_path(HAS_RELATIVE_PART <path-var> <out-var>)
cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
上述每個操作都遵循可預測的模式,如果路徑具有相關的組件,則將 <out-var>
設定為 true,否則為 false。請注意以下特殊情況:
對於
HAS_ROOT_PATH
,只有當root-name
或root-directory
至少有一個非空時,才會返回 true 的結果。對於
HAS_PARENT_PATH
,根目錄也被視為具有父目錄,即它自己。除非路徑僅由 檔案名稱 組成,否則結果為 true。
cmake_path(IS_ABSOLUTE <path-var> <out-var>)
如果 <path-var>
是絕對路徑,則將 <out-var>
設定為 true。絕對路徑是指明確識別檔案位置的路徑,而無需參考額外的起始位置。在 Windows 上,這表示路徑必須同時具有 root-name
和 root-directory-separator
才能被視為絕對路徑。在其他平台上,僅需要 root-directory-separator
就足夠了。請注意,這表示在 Windows 上,IS_ABSOLUTE
可以為 false,而 HAS_ROOT_DIRECTORY
可以為 true。
cmake_path(IS_RELATIVE <path-var> <out-var>)
這將在 <out-var>
中儲存與 IS_ABSOLUTE
相反的值。
cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
檢查 <path-var>
是否為 <input>
的前綴。
當指定 NORMALIZE
選項時,<path-var>
和 <input>
會在檢查之前進行正規化。
set(path "/a/b/c")
cmake_path(IS_PREFIX path "/a/b/c/d" result) # result = true
cmake_path(IS_PREFIX path "/a/b" result) # result = false
cmake_path(IS_PREFIX path "/x/y/z" result) # result = false
set(path "/a/b")
cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE result) # result = true
cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
比較以字串常值提供的兩個路徑的詞彙表示。除了將多個連續的目錄分隔符號有效地摺疊成單個分隔符號之外,不會對任何路徑執行正規化。根據以下虛擬碼邏輯確定相等性:
if(NOT <input1>.root_name() STREQUAL <input2>.root_name())
return FALSE
if(<input1>.has_root_directory() XOR <input2>.has_root_directory())
return FALSE
Return FALSE if a relative portion of <input1> is not lexicographically
equal to the relative portion of <input2>. This comparison is performed path
component-wise. If all of the components compare equal, then return TRUE.
注意
與大多數其他 cmake_path()
子命令不同,COMPARE
子命令將字串常值作為輸入,而不是變數的名稱。
修改¶
cmake_path(SET <path-var> [NORMALIZE] <input>)
將 <input>
路徑指定給 <path-var>
。如果 <input>
是原生路徑,則會將其轉換為使用正斜線 (/
) 的 cmake 樣式路徑。在 Windows 上,會考慮長檔名標記。
當指定 NORMALIZE
選項時,路徑在轉換後會被正規化。
例如
set(native_path "c:\\a\\b/..\\c")
cmake_path(SET path "${native_path}")
message("CMake path is \"${path}\"")
cmake_path(SET path NORMALIZE "${native_path}")
message("Normalized CMake path is \"${path}\"")
輸出
CMake path is "c:/a/b/../c"
Normalized CMake path is "c:/a/c"
cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
使用 /
作為 directory-separator
,將所有 <input>
引數附加到 <path-var>
。根據 <input>
,可能會捨棄 <path-var>
先前的内容。對於每個 <input>
引數,會應用以下演算法(虛擬碼):
# <path> is the contents of <path-var>
if(<input>.is_absolute() OR
(<input>.has_root_name() AND
NOT <input>.root_name() STREQUAL <path>.root_name()))
replace <path> with <input>
return()
endif()
if(<input>.has_root_directory())
remove any root-directory and the entire relative path from <path>
elseif(<path>.has_filename() OR
(NOT <path-var>.has_root_directory() OR <path>.is_absolute()))
append directory-separator to <path>
endif()
append <input> omitting any root-name to <path>
cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
將所有 <input>
引數附加到 <path-var>
,而不新增任何 directory-separator
。
cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
從 <path-var>
中移除 檔案名稱 組件(由 GET ... FILENAME 返回)。移除後,任何尾部的 directory-separator
(如果存在)都會保留。
如果未指定 OUTPUT_VARIABLE
,則在此函式返回後,HAS_FILENAME 會針對 <path-var>
返回 false。
例如
set(path "/a/b")
cmake_path(REMOVE_FILENAME path)
message("First path is \"${path}\"")
# filename is now already empty, the following removes nothing
cmake_path(REMOVE_FILENAME path)
message("Second path is \"${path}\"")
輸出
First path is "/a/"
Second path is "/a/"
cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
使用 <input>
替換 <path-var>
中的 檔案名稱 組件。如果 <path-var>
沒有檔案名稱組件(即 HAS_FILENAME 返回 false),則路徑不會變更。此操作等效於以下操作:
cmake_path(HAS_FILENAME path has_filename)
if(has_filename)
cmake_path(REMOVE_FILENAME path)
cmake_path(APPEND path input);
endif()
cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY]
[OUTPUT_VARIABLE <out-var>])
從 <path-var>
中移除 副檔名(如果有的話)。
cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input>
[OUTPUT_VARIABLE <out-var>])
使用 <input>
替換 副檔名。其效果等同於以下操作:
cmake_path(REMOVE_EXTENSION path)
if(NOT "input" MATCHES "^\\.")
cmake_path(APPEND_STRING path ".")
endif()
cmake_path(APPEND_STRING path "input")
生成¶
cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
根據正規化中描述的步驟,正規化 <path-var>
。
cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>]
[OUTPUT_VARIABLE <out-var>])
修改 <path-var>
,使其相對於 BASE_DIRECTORY
引數。如果未指定 BASE_DIRECTORY
,則預設基本目錄將為 CMAKE_CURRENT_SOURCE_DIR
。
作為參考,用於計算相對路徑的演算法與 C++ std::filesystem::path::lexically_relative 使用的演算法相同。
cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE]
[OUTPUT_VARIABLE <out-var>])
如果 <path-var>
是相對路徑(IS_RELATIVE 為 true),則會相對於由 BASE_DIRECTORY
選項指定的給定基本目錄進行評估。如果未指定 BASE_DIRECTORY
,則預設基本目錄將為 CMAKE_CURRENT_SOURCE_DIR
。
當指定 NORMALIZE
選項時,路徑會在路徑計算後被正規化。
由於 cmake_path()
不會存取檔案系統,因此不會解析符號連結,並且不會展開任何前導波浪號。若要計算已解析符號連結並展開前導波浪號的實際路徑,請改用 file(REAL_PATH)
命令。
原生轉換¶
對於本節中的命令,原生 指的是主機平台,而不是跨編譯時的目標平台。
cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
將 cmake 樣式的 <path-var>
轉換為具有平台特定斜線的原生路徑(在 Windows 主機上為 \
,在其他位置為 /
)。
當指定 NORMALIZE
選項時,路徑會在轉換之前被正規化。
cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
將原生 <input>
路徑轉換為具有正斜線 (/
) 的 cmake 樣式路徑。在 Windows 主機上,會考慮長檔名標記。輸入可以是單一路徑或系統搜尋路徑,如 $ENV{PATH}
。搜尋路徑將轉換為由 ;
字元分隔的 cmake 樣式清單(在非 Windows 平台上,這基本上表示 :
分隔符號會取代為 ;
)。轉換的結果會儲存在 <out-var>
變數中。
當指定 NORMALIZE
選項時,路徑會在轉換之前被正規化。
注意
與大多數其他 cmake_path()
子命令不同,CONVERT
子命令將字串常值作為輸入,而不是變數的名稱。
cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])
將 cmake 樣式的 <input>
路徑轉換為具有平台特定斜線的原生路徑(在 Windows 主機上為 \
,在其他位置為 /
)。輸入可以是單一路徑或 cmake 樣式清單。清單將轉換為原生搜尋路徑(在 Windows 上以 ;
分隔,在其他平台上以 :
分隔)。轉換的結果會儲存在 <out-var>
變數中。
當指定 NORMALIZE
選項時,路徑會在轉換之前被正規化。
注意
與大多數其他 cmake_path()
子命令不同,CONVERT
子命令將字串常值作為輸入,而不是變數的名稱。
例如
set(paths "/a/b/c" "/x/y/z")
cmake_path(CONVERT "${paths}" TO_NATIVE_PATH_LIST native_paths)
message("Native path list is \"${native_paths}\"")
在 Windows 上的輸出
Native path list is "\a\b\c;\x\y\z"
在所有其他平台上的輸出
Native path list is "/a/b/c:/x/y/z"
雜湊¶
cmake_path(HASH <path-var> <out-var>)
計算 <path-var>
的雜湊值,以便對於兩個比較相等的路徑 p1
和 p2
(COMPARE ... EQUAL),p1
的雜湊值等於 p2
的雜湊值。路徑始終會在計算雜湊之前進行正規化。