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>) Comparison 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是.或..,则它没有扩展名。
stem 是
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")
“修改” (Modification) 和 “生成” (Generation) 子命令可以就地存储结果,或存储在名为 OUTPUT_VARIABLE 关键字的单独变量中。所有其他子命令将结果存储在强制性的 <out-var> 变量中。
标准化¶
一些子命令支持 *标准化* 路径。用于标准化路径的算法如下:
如果路径为空,则停止(空路径的标准化形式也是空路径)。
将每个
directory-separator(可能由多个分隔符组成)替换为单个/(/a///b --> /a/b)。删除每个孤立的点(
.)以及其后紧跟的directory-separator(/a/./b/. --> /a/b)。删除后面紧跟
directory-separator和..的(非..)项名,以及紧随其后的任何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 ""
扩展名和 stem 示例¶
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 someMorePath EXTENSION someMoreExt)
cmake_path(GET someMorePath 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:/"
查询¶
每个 cmake_path(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,除非路径仅由 filename 组成。
- 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>中移除 filename 组件(由GET ... FILENAME返回)。移除后,如果存在,则保留任何尾随的directory-separator。如果未提供
OUTPUT_VARIABLE,则在此函数返回后,<path-var>的HAS_FILENAME返回 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>])¶
将
<path-var>的 filename 组件替换为<input>。如果<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(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的哈希值。在计算哈希值之前,路径总是会被 标准化。