美文网首页
Cmake命令之cmake_path

Cmake命令之cmake_path

作者: Domibaba | 来源:发表于2023-08-23 22:48 被阅读0次

    一、命令简介

    该命令用来操作路径,仅仅是语义概念上的处理,并不会在文件系统上执行任何交互。路径可以不存在,甚至是当前系统不允许的路径。如果想要了解与文件系统交互的命令,参考file()

    注意:cmake_path会将路径以CMake所运行的构建系统(例如,主机平台)的格式处理,而不是目标系统。在交叉编译过程中,如果路径包含的元素在CMake运行的系统上无法表示(例如路径是C:\\,但是系统并不是Windows),那么结果不可预测。

    cmake_path分为以下几个子命令:分解、查询、修改、生成、转换、哈希。

    该命令有如下约定:
    • <path-var>:变量名,如果作为命令中的输入,该变量必须存在并且是单个路径。

    • <input>:字符串字面值,可以包含一个路径、路径的一部分、以分号分割的多个路径。

    • <input>...0或多个字符串字面的参数。

    • <out-var>:存储命令的结果。

    路径结构和术语:

    一个路径的组成如下(都是可选的,但是可能存在某些限制):

    root-name root-directory-separator (item-name directory-separator)\* filename

    • root-name:支持多个根路径的系统的(例如Windows)根路径名称,可选。例如C:或者//myserver等。

    • root-directory-separator:目录分隔符,如果存在表明路径是绝对路径,如果确实该分隔符,并且第一个部分不是root-name,是item-name,那么它是一个相对路径。

    • item-name:一个字符组成的序列,不能是目录分隔符,该名称可能标识一个文件、或一个目录,或软连接,或硬链接,有连个特殊的情况: 1)包含单个点.,表示当前目录 2)包含两个点..,表示父目录 (item-name directory-separator)*表示0个或多个item-name,以目录分隔符分割,()*不是路径的一部分。

    • directory-separator:目录分隔符,即/,连续的多个/会被当成一个/处理,例如/usr/////lib/usr/lib相同。

    • filename:文件名。如果路径不是以/结束,路径中的最后一个item-name就是文件名,它可以是文件、软硬链接、目录。文件名还可以包含扩展,默认情况下,扩展是从最左边的.分隔符开始,例如file.dat1.dat2,那么.dat1.dat2就是扩展名。filename除去扩展部分被称为stem,因此默认情况下file.dat1.dat2stem就是file。可以使用LAST_ONLY关键字来指定扩展从filename最右边的.开始。例外情况是:1)如果第一个字符就是.,那么解析为无扩展,例如.profile;或2)如果是...同样认为没有扩展。

    创建一个路径变量

    可以使用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>中。

    规范化

    一些子命令支持规范化一个路径,规范一个路径的算法如下:

    1. 如果路径为空,命令终止(即空路径规范化后仍是空路径)

    2. 替换多个连续的/分隔符为单个/分隔符,例如//a/b///c规范化后为/a/b/c

    3. 移除在分隔符后的单个.,例如/a/./b/c/.规范化后为/a/b/c

    4. 如果item-name后面紧跟着是..,那么删除该item-name..以及跟在他们之后的分隔符/,例如/a/b/../c规范化后为/a/c

    5. 如果路径包含根路径,并且根路径后面紧跟的是..,那么移除..和跟在它后面的/,因为根目录的父路径仍是它自己。例如/../a规范化后为/a.

    6. 如果最后一个item-name..,那么移除..之后的分隔符/,例如../规范化后为..

    7. 经过上述规范化后的路径仍为空,那么规范化后的路径为.(./的规范化路径也是.).

    二、子命令详解

    2.1 分解

    cmake_path(GET)子命令从一个路径中获取不同的部分。如果待获取的部分在路径中不存在,那么该子命令会将空字符串结果存于<out-var>中,例如只有在Windows中才存在root-name的概念,因此,如果CMake运行的系统非Windows,获取ROOT_NAME会得到一个空字符串。如果HAS_RELATIVE_PART子命令结果为false,那么获取PARENT_NAME的结果就是<path-var>,由于根路径的父路径是它自己,当HAS_RELATIVE_PART子命令结果为true时,表明<path-var>至少包含一个元素。

    子命令形式为:

    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>)

    • cmake_path(GET <path-var> [ROOT_NAME|ROOT_DIRECTORY|ROOT_PATH] <out-var>):获取根名称、目录、路径,我的系统非Windows,因此ROOT_NAME为空。
    set(path "/usr/bin")
    
    cmake_path(GET path ROOT_NAME rootName)
    cmake_path(GET path ROOT_DIRECTORY rootDirectory)
    cmake_path(GET path ROOT_PATH rootPath)
    
    message("root name is: ${rootName}")
    message("root directory is: ${rootDirectory}")
    message("root path is: ${rootPath}")
    

    运行结果: root name is: root directory is: / root path is: /

    • cmake_path(GET <path-var> FILENAME <out-var>):获取文件名。
    set(path "/usr/bin")
    cmake_path(GET path FILENAME filename)
    message("filename is: ${filename}")
    
    set(path "/a/b/")
    cmake_path(GET path FILENAME filename)
    message("filename is: ${filename}")
    

    运行结果: filename is: bin filename is:

    • cmake_path(GET <path-var> [EXTENSION|STEM] <out-var>):获取扩展或stem信息。默认情况下,扩展是从最左边的.分隔符开始,例如file.dat1.dat2,那么.dat1.dat2就是扩展名。filename除去扩展部分被称为stem,因此默认情况下file.dat1.dat2stem就是file。可以使用LAST_ONLY关键字来指定扩展从filename最右边的.开始。
    set(path "name.ext1.ext2")
    
    # 默认扩展是取最左侧的.到尾部的部分
    cmake_path(GET path EXTENSION fullExt)
    cmake_path(GET path STEM fullStem)
    message("full extension: ${fullExt}")
    message("full stem: ${fullStem}")
    
    # 指定LAST_ONLY后,扩展取的是最右侧的.到尾部的部分
    cmake_path(GET path EXTENSION LAST_ONLY lastExt)
    cmake_path(GET path STEM LAST_ONLY lastStem)
    message("last extension: ${lastExt}")
    message("last stem: ${lastStem}")
    
    set(dotPath "/a/.")
    set(dotDotPath "/a/..")
    set(someMorePath "/a/.some.more")
    
    # filename是.的特例:扩展为空
    cmake_path(GET dotPath EXTENSION dotExt)
    cmake_path(GET dotPath STEM dotStem)
    
    # filename是..的特例:扩展为空
    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: .ext1.ext2 full stem: name last extension: .ext2 last stem: 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

    • cmake_path(GET <path-var> RELATIVE_PART <out-var>):获取相对路径信息。
    set(path "/usr/local/bin")
    cmake_path(GET path RELATIVE_PART relativePath)
    message("relative path: ${relativePath}")
    
    set(path "usr/local/bin") # 如果本身就是相对路径,那么RELATIVE_PART子命令获取到的就是它本身
    cmake_path(GET path RELATIVE_PART relativePath)
    message("relative path: ${relativePath}")
    
    set(path "/")
    cmake_path(GET path RELATIVE_PART relativePath)
    message("relative path: \"${relativePath}\"")
    

    运行于macOS下的结果 relative path: usr/local/bin relative path: usr/local/bin relative path: ""

    • cmake_path(GET <path-var> PARENT_PATH <out-var>):获取父目录。
    set(path "/usr/local/bin")
    cmake_path(GET path PARENT_PATH parentPath)
    message("parent path: ${parentPath}")
    
    set(path "usr/local/bin")
    cmake_path(GET path PARENT_PATH parentPath)
    message("parent path: ${parentPath}")
    
    set(path "usr/local/bin/") # 如果filename为空,则父目录就是自身
    cmake_path(GET path PARENT_PATH parentPath)
    message("parent path: ${parentPath}")
    
    set(path "/")
    cmake_path(GET path PARENT_PATH parentPath)
    message("parent path: ${parentPath}")
    

    运行结果 parent path: /usr/local parent path: usr/local parent path: usr/local/bin parent path: /

    2.2 查询

    查询分为三大类,形式分别为HAS_XXXIS_XXXCOMPARE

    1、HAS_XXX查询子命令

    每一个cmake_path(GET)子命令都对应一个HAS_XXX子命令,以便判定GET子命令获取的路径信息是否存在。HAS_XXX的子命令格式如下:

    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,两个特例为:

    1. 对于HAS_ROOT_PATH子命令,只有当root-nameroot-directory其中一个为非空时返回true

    2. 对于HAS_PARENT_PATH子命令,根目录的父目录是根目录自身,因此除非路径仅包含filename,否则该子命令返回true

    set(path "/usr/local/bin/myfile.ext1.ext2")
    cmake_path(HAS_ROOT_NAME path hrn)
    cmake_path(HAS_ROOT_DIRECTORY path hrd)
    cmake_path(HAS_ROOT_PATH path hrp)
    cmake_path(HAS_FILENAME path hfn)
    cmake_path(HAS_EXTENSION path hext)
    cmake_path(HAS_STEM path hstem)
    cmake_path(HAS_RELATIVE_PART path hrelative)
    cmake_path(HAS_PARENT_PATH path hpp)
    
    message("${path} has root name? --- ${hrn}")
    message("${path} has root directory? --- ${hrd}")
    message("${path} has root path? --- ${hrp}")
    message("${path} has filename? --- ${hfn}")
    message("${path} has extension? --- ${hext}")
    message("${path} has stem? --- ${hstem}")
    message("${path} has relative part? --- ${hrelative}")
    message("${path} has parent path? --- ${hpp}")
    

    运行结果 /usr/local/bin/myfile.ext1.ext2 has root name? --- OFF /usr/local/bin/myfile.ext1.ext2 has root directory? --- ON /usr/local/bin/myfile.ext1.ext2 has root path? --- ON /usr/local/bin/myfile.ext1.ext2 has filename? --- ON /usr/local/bin/myfile.ext1.ext2 has extension? --- ON /usr/local/bin/myfile.ext1.ext2 has stem? --- ON /usr/local/bin/myfile.ext1.ext2 has relative part? --- ON /usr/local/bin/myfile.ext1.ext2 has parent path? --- ON

    2、IS_XXX查询子命令

    IS_XXX查询子命令的格式如下:

    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(IS_ABSOLUTE <path-var> <out-var>):如果是绝对路径,<out-var>结果为true。绝对路径唯一标识一个文件的位置。在Windows下,绝对路径必须包含root-name和目录分隔符(例如C:/)。其他平台下,只需要目录分隔符即可(例如Linux下的/)。
    set(path "/usr/local/bin")
    cmake_path(IS_ABSOLUTE path result)
    message("${path} is absolute? --- ${result}")
    
    set(path "usr/local/bin")
    cmake_path(IS_ABSOLUTE path result)
    message("${path} is absolute? --- ${result}")
    

    运行结果: /usr/local/bin is absolute? --- ON usr/local/bin is absolute? --- OFF

    • cmake_path(IS_RELATIVE <path-var> <out-var>):判断路径是否是相对路径。
    set(path "/usr/local/bin")
    cmake_path(IS_RELATIVE path result)
    message("${path} is relative? --- ${result}")
    
    set(path "usr/local/bin")
    cmake_path(IS_RELATIVE path result)
    message("${path} is relative? --- ${result}")
    

    运行结果: /usr/local/bin is relative? --- OFF usr/local/bin is relative? --- ON

    • cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>):判断路径<path-var>是否是<input>的前缀,如果指定了NORMALIZE选项,<path-var><input>在比较前会进行路径规范化。
    set(path "/usr/local/bin")
    cmake_path(IS_PREFIX path "/usr/local/bin/myfile" result)
    message("if ${path} is prefix of /usr/local/bin/myfile? --- ${result}")
    cmake_path(IS_PREFIX path "/usr/local" result)
    message("if ${path} is prefix of /usr/local? --- ${result}")
    
    set(path "/usr/../tmp/dir")
    cmake_path(IS_PREFIX path "/tmp/dir/myfile" NORMALIZE result)
    message("if ${path} is prefix of /tmp/dir/myfil? --- ${result}")
    

    运行结果: if /usr/local/bin is prefix of /usr/local/bin/myfile? --- ON if /usr/local/bin is prefix of /usr/local? --- OFF if /usr/../tmp/dir is prefix of /tmp/dir/myfil? --- ON

    3、COMPARE查询子命令
    • cmake_path(COMPARE <input1> EQUAL <input2> <out-var>) cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>):比较两个路径是否相同或者不同,路径被当做字符串字面值进行比较,注意该子命令的两个输入路径都不会进行路径规范化。
    cmake_path(COMPARE "/usr/local/bin" EQUAL "/usr/local/bin" cmpResult)
    message("CMP result: ${cmpResult}")
    cmake_path(COMPARE "/usr/local/bin/" NOT_EQUAL "/usr/local/bin" cmpResult)
    message("CMP result: ${cmpResult}")
    

    运行结果: CMP result: ON CMP result: ON

    2.3 修改

    修改包含设置、追加、移除、替换等子命令操作,具体格式如下:

    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>])

    1、设置子命令
    • cmake_path(SET <path-var> [NORMALIZE] <input>):将<input>赋值给<input-var>,注意<input>应该是一个变量(用$取变量符号),否则会当成一个字符串。如果指定了NORMALIZE关键字,那么在执行赋值前会先对路径进行规范化。
    set(path "/usr/local/bin")
    cmake_path(SET result ${path}) # 如果此处不是用${path}而是path,那么result的结果是"path"
    message("${path} set to ${result}")
    set(path "/usr/../local////bin/.")
    cmake_path(SET result NORMALIZE ${path})
    message("${path} normalized set to ${result}")
    

    运行结果: /usr/local/bin set to /usr/local/bin /usr/../local////bin/. normalized set to /local/bin/

    2、追加子命令
    • cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>]):顺序遍历多个<input>路径,用/拼接后,结果存入<path-var>。在遍历过程中,根据<input>的具体内容,通过前面<input>计算得到的<input-var>可能会被丢弃。规则如下:
    1. 如果当前的<input>是绝对路径,则使用<input>替换<path-var>,拼接过程结束。

    2. <input>存在ROOT_NAME并且与<path-var>ROOT_NAME不相同,那么使用<input>替换<path-var>,拼接过程结束。

    3. 如果<input>ROOT_DIRECTORY存在,那么移除<path-var>任意的ROOT_DIRECTORY和整个相对路径。

    4. 如果<input>不存在ROOT_DIRECTORY<path-var>存在filename,或<path-var>是非绝对路径且不存在ROOT_DIRECTORY,那么将/拼接到<path-var>

    5. <input>拼接到<path-var>,忽略ROOT_NAME

    cmake_path(APPEND result "/usr/local/bin" "test/myfile" "myfile2")
    message("path result is : ${result}")
    cmake_path(APPEND result1 "usr/local" "/tmp/myfile")
    message("path result1 is : ${result1}")
    cmake_path(APPEND result2 "usr/local/" "mydir1" "mydir2")
    message("path result2 is : ${result2}")
    

    运行结果: path result is : /usr/local/bin/test/myfile/myfile2 path result1 is : /tmp/myfile path result2 is : usr/local/mydir1/mydir2

    • cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>]):将<input>拼接到path-var,不会额外添加任何目录分隔符。注意:该命令下<path-var>需要已经定义
    set(rs "")
    cmake_path(APPEND_STRING rs "/usr/" "local" "bin")
    message("APPEND_STRING: ${rs}")
    

    运行结果: APPEND_STRING: /usr/localbin

    • cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>]):将路径中的filename移除(也就是通过GET ... FILENAME获取到的内容),移除后尾部的目录分隔符/会被保留。如果没有定义OUTPUT_VARIABLE,那么执行该子命令后,对<path-var>执行HAS_FILENAME会返回false
    set(path "/usr/local/bin/myfile")
    cmake_path(REMOVE_FILENAME path)
    message("For ${path} remove filename is: ${path}")
    cmake_path(HAS_FILENAME path hfn)
    message("For ${path} has filename? --- ${hfn}")
    
    set(path "/usr/local/bin/myfile")
    cmake_path(REMOVE_FILENAME path OUTPUT_VARIABLE output) # 有OUTPUT_VARIABLE,原始路径path不会被修改
    message("For ${path} remove filename is: ${output}, orignal path is ${path}")
    cmake_path(HAS_FILENAME path hfn)
    message("For ${path} has filename? --- ${hfn}")
    

    运行结果: For /usr/local/bin/ remove filename is: /usr/local/bin/ For /usr/local/bin/ has filename? --- OFF For /usr/local/bin/myfile remove filename is: /usr/local/bin/, orignal path is /usr/local/bin/myfile For /usr/local/bin/myfile has filename? --- ON

    • cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>]):用<input>替代路径<path-var>中的filename,如果<path-var>中没有filename,那么<path-var>不会有任何变化(如果定义了OUTPUT_VARIABLE,也不会修改<path-var>),该命令等价于以下逻辑:
    1. 使用cmake_path(HAS_FILENAME path has_filename)判断是否存在filename

    2. 第一步的has_filename如果为真,那么依次执行cmake_path(REMOVE_FILENAME path)cmake_path(APPEND path input)

    set(path "/usr/local/bin/myfile")
    cmake_path(REPLACE_FILENAME path "replacefile" OUTPUT_VARIABLE output)
    message("After replace ${path}, result is: ${output}")
    
    # 等效的命令如下
    set(path "/usr/local/bin/myfile")
    cmake_path(HAS_FILENAME path has_filename)
    if(has_filename)
        cmake_path(REMOVE_FILENAME path OUTPUT_VARIABLE output)
        cmake_path(APPEND output "replacefile")
        message("After replace ${path} use combine commands, result is: ${output}")
    endif()
    

    运行结果: After replace /usr/local/bin/myfile, result is: /usr/local/bin/replacefile After replace /usr/local/bin/myfile use combine commands, result is: /usr/local/bin/replacefile

    • cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>]):移除扩展名,可以使用LAST_ONLY指定从filename最右边的.开始移除。
    set(path "/usr/local/bin/myfile.ext1.ext2")
    cmake_path(REMOVE_EXTENSION path OUTPUT_VARIABLE output)
    message("remove extersion of ${path} is ${output}")
    cmake_path(REMOVE_EXTENSION path LAST_ONLY OUTPUT_VARIABLE output)
    message("remove LAST_ONLY extersion of ${path} is ${output}")
    

    运行结果: remove extersion of /usr/local/bin/myfile.ext1.ext2 is /usr/local/bin/myfile remove LAST_ONLY extersion of /usr/local/bin/myfile.ext1.ext2 is /usr/local/bin/myfile.ext1

    • cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>]):替换扩展名,可以使用LAST_ONLY指定从filename最右边的.开始替换。
    set(path "/usr/local/bin/myfile.ext1.ext2")
    cmake_path(REPLACE_EXTENSION path "dat1.dat2" OUTPUT_VARIABLE output)
    message("use dat1.dat2 replace extersion of ${path} is ${output}")
    cmake_path(REPLACE_EXTENSION path LAST_ONLY "dat1.dat2" OUTPUT_VARIABLE output)
    message("user dat1.dat2 replace LAST_ONLY extersion of ${path} is ${output}")
    

    运行结果: use dat1.dat2 replace extersion of /usr/local/bin/myfile.ext1.ext2 is /usr/local/bin/myfile.dat1.dat2 user dat1.dat2 replace LAST_ONLY extersion of /usr/local/bin/myfile.ext1.ext2 is /usr/local/bin/myfile.ext1.dat1.dat2

    2.4 生成路径

    分为规范化路径、产生相对路径、产生绝对路径三种。

    • cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>]):规范化一个路径,具体规则参考本文前面索引处。具体例子不再赘述,参考其他例子中的规范化说明。

    • cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>]):将路径<path-var>修改为相对于基路径(由BASE_DIRECTORY指定)的路径,若未指定BASE_DIRECTORY,那么默认的基路径从CMAKE_CURRENT_SOURCE_DIR变量中获取。简而言之,可以理解为从基路径切换到<path-var>路径需要经过的路径。

    set(path "/usr/local/bin/myfile")
    cmake_path(RELATIVE_PATH path BASE_DIRECTORY "/usr/local" OUTPUT_VARIABLE output)
    message("the relative path ${path} for base /usr/local is ${output}")
    
    cmake_path(RELATIVE_PATH path OUTPUT_VARIABLE output) # 未指定基路径,默认基路径为CMAKE_CURRENT_SOURCE_DIR变量存放的路径
    message("the relative path ${path} for base ${CMAKE_CURRENT_SOURCE_DIR} is ${output}")
    

    运行结果 the relative path /usr/local/bin/myfile for base /usr/local is bin/myfile the relative path /usr/local/bin/myfile for base /Users/XX1/XX2/XX3/XX4/XX5 is ../../../../../../usr/local/bin/myfile

    • cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>]):如果<path-var>是绝路径,那么结果就是<path-var>;如果<path-var>是相对路径,效果相当于将<path-var>拼接在基路径之后,当然,如果未指定基路径,则从CMAKE_CURRENT_SOURCE_DIR获取基路径。
    set(path "/usr/local/bin/myfile") # 原路径是绝对路径,结果不变
    cmake_path(ABSOLUTE_PATH path BASE_DIRECTORY "/usr/local" OUTPUT_VARIABLE output)
    message("the absolute path ${path} for base /usr/local is ${output}")
    cmake_path(ABSOLUTE_PATH path OUTPUT_VARIABLE output)
    message("the absolute path ${path} for base ${CMAKE_CURRENT_SOURCE_DIR} is ${output}")
    
    set(path "mydir/myfile") # 原路径是相对路径,拼接
    cmake_path(ABSOLUTE_PATH path BASE_DIRECTORY "/usr/local" OUTPUT_VARIABLE output)
    message("the absolute path ${path} for base /usr/local is ${output}")
    cmake_path(ABSOLUTE_PATH path OUTPUT_VARIABLE output)
    message("the absolute path ${path} for base ${CMAKE_CURRENT_SOURCE_DIR} is ${output}")
    

    运行结果: the absolute path /usr/local/bin/myfile for base /usr/local is /usr/local/bin/myfile the absolute path /usr/local/bin/myfile for base /Users/XX1/XX2/XX3/XX4/XX5 is /usr/local/bin/myfile

    the absolute path mydir/myfile for base /usr/local is /usr/local/mydir/myfile the absolute path mydir/myfile for base /Users/XX1/XX2/XX3/XX4/XX5 is /Users/XX1/XX2/XX3/XX4/XX5/mydir/myfile

    2,5 原生转换

    指的是转换成CMake所在的构建平台路径规范,因此这里的原生指交叉编译的构建平台,而不是目标平台。例如程序在windows下构建,在嵌入式设备上跑,那么原生指的是Windows平台。

    • cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>):将路径转换成平台相关的斜杆(Windows下的右斜杠\,其他平台的左斜杠/),还可以通过NORMALIZE在转换前将路径规范化。
    set(path "/usr/local/bin/myfile")
    cmake_path(NATIVE_PATH path output)
    message("the native path of ${path} is: ${output}")
    

    运行结果(macOS): the native path of /usr/local/bin/myfile is: /usr/local/bin/myfile

    运行结果(Windows): the native path of /usr/local/bin/myfile is: \usr\local\bin\myfile

    • cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE]):将路径转换为cmake风格的路径,cmake风格的路径指的是以左斜杆/作为连接符,多个路径之间以;分隔。特别需要注意的是:CONVERT子命令的输入路径被当成字符串文本值处理,而不是当成一个变量进行解析,因此使用当<input>是多个路径时,不能直接使用${input}变量,而需要使用"${input}"确保得到的是一个字符串文本值
    set(path "/usr/local/bin/myfile" "/tmp/mydir") # cmake的set命令以`;`分隔多个值,${path}=/usr/local/bin/myfile;/tmp/mydir
    cmake_path(CONVERT "${path}" TO_CMAKE_PATH_LIST output) # 注意要使用"${path}"而不是${path}变量
    message("1: the native path ${path} to cmake-style: ${output}")
    
    set(path "/usr/local/bin/myfile:/tmp/mydir") # 模拟以:分隔多个值,${path}="/usr/local/bin/myfile:/tmp/mydir"
    cmake_path(CONVERT "${path}" TO_CMAKE_PATH_LIST output) # ${path}变量已经是一个字符串字面量,因此此处也可以用${path}
    message("2: the native path ${path} to cmake-style: ${output}")
    

    运行结果(macOS)(注意;和:的区别): 1: the native path /usr/local/bin/myfile;/tmp/mydir to cmake-style: /usr/local/bin/myfile;/tmp/mydir 2: the native path /usr/local/bin/myfile:/tmp/mydir to cmake-style: /usr/local/bin/myfile;/tmp/mydir

    运行结果(Windows)(注意;和:的区别): 1: the native path /usr/local/bin/myfile;/tmp/mydir to cmake-style: /usr/local/bin/myfile:/tmp/mydir 2: the native path /usr/local/bin/myfile:/tmp/mydir to cmake-style: /usr/local/bin/myfile:/tmp/mydir

    • cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE]):将cmake风格的路径转换为原生路径,例如Windows下的右斜杠\,其他平台的左斜杠/,当多个路径时候,Windows下的以;分隔,其他平台以:分隔。特别需要注意的是:CONVERT子命令的输入路径被当成字符串文本值处理,而不是当成一个变量进行解析,因此使用当<input>是多个路径时,不能直接使用${input}变量,而需要使用"${input}"确保得到的是一个字符串文本值
    set(path "/usr/local/bin/myfile" "/tmp/mydir") # cmake的set命令以`;`分隔多个值,${path}=/usr/local/bin/myfile;/tmp/mydir
    cmake_path(CONVERT "${path}" TO_NATIVE_PATH_LIST output) # 注意要使用"${path}"而不是${path}变量
    message("the cmake-style path ${path} to native path: ${output}")
    

    运行结果(macOS)(注意;和:的区别): the cmake-style path /usr/local/bin/myfile;/tmp/mydir to native path: /usr/local/bin/myfile:/tmp/mydir

    运行结果(Windows)(注意;和:的区别): the cmake-style path /usr/local/bin/myfile;/tmp/mydir to native path: \usr\local\bin\myfile;\tmp\mydir

    2.6 哈希

    • cmake_path(HASH <path-var> <out-var>):计算路径的哈希值,哈希结果存放在<out-var>中。可用于比较两个路径是否相等(参考子命令COMPARE .. EQUAL,两个路径相等时,其哈希值也相等)。在计算哈希值之前,路径会被规范化。
    set(path "/usr/local/bin/myfile")
    cmake_path(HASH path hash_path)
    cmake_path(APPEND path2 "/usr/local" "bin/myfile")
    cmake_path(HASH path2 hash_path2)
    message("path1:${path}, path1 hash:${hash_path}")
    message("path2:${path2}, path2 hash:${hash_path2}")
    

    运行结果: path1:/usr/local/bin/myfile, path1 hash:5a17be211871fbe path2:/usr/local/bin/myfile, path2 hash:5a17be211871fbe


    附录:参考文档

    1. https://cmake.org/cmake/help/latest/command/cmake_path.html

    相关文章

      网友评论

          本文标题:Cmake命令之cmake_path

          本文链接:https://www.haomeiwen.com/subject/cifpmdtx.html