Cmake命令之file

file是文件操作命令,用于文件或路徑的操作,結(jié)果也會(huì)在文件系統(tǒng)上進(jìn)行存儲(chǔ)。因此,與cmake_path命令只是語(yǔ)義概念上對(duì)路徑的處理不同,file會(huì)與文件系統(tǒng)進(jìn)行實(shí)際的交互。

一、命令格式

file命令包含、、文件系統(tǒng)、路徑轉(zhuǎn)換、傳輸、、歸檔七個(gè)子命令,格式如下:

子命令:讀
  file(READ <filename> <out-var> [...])
  file(STRINGS <filename> <out-var> [...])
  file(<HASH> <filename> <out-var>)
  file(TIMESTAMP <filename> <out-var> [...])
  file(GET_RUNTIME_DEPENDENCIES [...])

子命令:寫
  file({WRITE | APPEND} <filename> <content>...)
  file({TOUCH | TOUCH_NOCREATE} [<file>...])
  file(GENERATE OUTPUT <output-file> [...])
  file(CONFIGURE OUTPUT <output-file> CONTENT <content> [...])

子命令:文件系統(tǒng)
  file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])
  file(MAKE_DIRECTORY [<dir>...])
  file({REMOVE | REMOVE_RECURSE } [<files>...])
  file(RENAME <oldname> <newname> [...])
  file(COPY_FILE <oldname> <newname> [...])
  file({COPY | INSTALL} <file>... DESTINATION <dir> [...])
  file(SIZE <filename> <out-var>)
  file(READ_SYMLINK <linkname> <out-var>)
  file(CREATE_LINK <original> <linkname> [...])
  file(CHMOD <files>... <directories>... PERMISSIONS <permissions>... [...])
  file(CHMOD_RECURSE <files>... <directories>... PERMISSIONS <permissions>... [...])

子命令:路徑轉(zhuǎn)換
  file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>] [EXPAND_TILDE])
  file(RELATIVE_PATH <out-var> <directory> <file>)
  file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>)

子命令:傳輸
  file(DOWNLOAD <url> [<file>] [...])
  file(UPLOAD <file> <url> [...])

子命令:鎖
  file(LOCK <path> [...])

子命令:歸檔
  file(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [...])
  file(ARCHIVE_EXTRACT INPUT <archive> [...])

二、命令使用

在開始舉例說(shuō)明前,命令操作的文件/目錄樹說(shuō)明如下:

├── CMakeLists.txt
├── copy                # 該目錄用于演示COPY子命令
│   └── myfile_read     # COPY子命令拷貝的文件結(jié)果
├── myfile_download     # 用于演示DOWNLOAD下載子命令
├── myfile_read         # 用于演示READ子命令
├── myfile_write        # 用于演示W(wǎng)RITE子命令
└── result.tar          # 用于演示歸檔ARCHIVE_CREATE子命令

讀文件內(nèi)容
file(READ myfile_read out_var)
message("Content of myfile_read is: ${out_var}")

運(yùn)行結(jié)果:
Content of myfile_read is: This is a file for test

寫文件:如果文件不存在,會(huì)創(chuàng)建文件。
set(content "Write hello to file.")
file(WRITE myfile_write ${content}) # 文件不存在會(huì)創(chuàng)建,直接覆蓋文件寫
file(READ myfile_write out_var)
message("Content of myfile_write: ${out_var}")
file(APPEND myfile_write "\nAnother line.") # 文件不存在會(huì)創(chuàng)建,在文件末尾追加寫
file(READ myfile_write out_var)
message("Content of myfile_write: ${out_var}")

運(yùn)行結(jié)果:
Content of myfile_write: Write hello to file.
Content of myfile_write: Write hello to file.
Another line.

文件系統(tǒng)操作
file(COPY myfile_read DESTINATION ./copy) # 將文件拷貝到./copy目錄下

運(yùn)行cmake .后,myfile_read會(huì)被復(fù)制一份到./copy目錄下。

路徑轉(zhuǎn)換
file(REAL_PATH "./copy" out_var BASE_DIRECTORY "/bin") # ./copy目錄基于base目錄/bin的路徑
message("./copy relative base /bin result: ${out_var}")

運(yùn)行結(jié)果:
./copy relative base /bin result: /bin/copy

文件傳輸操作
file(DOWNLOAD "https://sh.rustup.rs" myfile_download) # 下載文件

運(yùn)行cmake .命令后,會(huì)將文件下載到本地,并命名為myfile_download

歸檔
file(ARCHIVE_CREATE OUTPUT "result.tar" PATHS myfile_read myfile_write myfile_download FORMAT gnutar) # 將myfile_read myfile_write myfile_download打包成tar文件格式

運(yùn)行cmake .命令后,會(huì)生成一個(gè)result.tar文件,使用tar tvf result.tar命令查看文件內(nèi)容:

-rw-r--r-- 0 XXX YYY 24 5 10 07:42 myfile_read
-rw-r--r-- 0 XXX YYY 34 5 10 08:23 myfile_write
-rw-r--r-- 0 XXX YYY 21102 5 10 08:23 myfile_download

三、子命令詳解

3.1 子命令:讀
  • file(READ <filename> <variable> [OFFSET <offset>] [LIMIT <max-in>] [HEX])

說(shuō)明:從文件<filename>中讀取內(nèi)容,并將結(jié)果存入到<variable>中??梢灾付◤奈募?code><offset>處開始讀,最多讀取字節(jié)數(shù)(bytes)通過(guò)<max-in>參數(shù)指定。HEX選項(xiàng)會(huì)將讀取結(jié)果轉(zhuǎn)換成十六進(jìn)制表示(在讀取二進(jìn)制數(shù)據(jù)的時(shí)候非常有用),且十六進(jìn)制的輸出將按照小寫輸出(也就是或說(shuō)輸出a b c d e f)。

# CMakeLists.txt

# 從myfile_read的第5個(gè)字節(jié)偏移處開始讀,讀取4個(gè)字節(jié)
file(READ myfile_read content OFFSET 8 LIMIT 6)
message("read from myfile_read at offset 8 and read 6 bytes: ${content}")

# 讀取結(jié)果轉(zhuǎn)換成十六進(jìn)制表示,十六進(jìn)制表示中的ABCDEF將按照小寫輸出
file(READ myfile_read content_hex OFFSET 8 LIMIT 6 HEX)
message("read from myfile_read at offset 8 and read 6 bytes (HEX output): ${content_hex}")

myfile_read文件的原始內(nèi)容為:THIS IS A FILE FOR READ TEST.

運(yùn)行結(jié)果:
read from myfile_read at offset 8 and read 6 bytes: A FILE
read from myfile_read at offset 8 and read 6 bytes (HEX output): 412046494c45

  • file(STRINGS <filename> <variable> [<options>...])

說(shuō)明
??按照ASCII編碼從文件中讀取并存儲(chǔ)在<variable>中。換行符會(huì)被忽略,如果是二進(jìn)制數(shù)據(jù),也會(huì)被忽略。默認(rèn)情況下是以換行符對(duì)讀取的內(nèi)容進(jìn)行分割,每一行讀取為輸出結(jié)果序列的一個(gè)子項(xiàng),不同子項(xiàng)以分號(hào)分割(也可以使用長(zhǎng)度進(jìn)行分割等,見(jiàn)下詳解)。該命令的選項(xiàng)詳解如下:

  • LENGTH_MAXIMUM <max-len>:每次讀取不超過(guò)給定長(zhǎng)度的字符串,如果某一行的字符超過(guò)指定長(zhǎng)度,會(huì)以指定長(zhǎng)度對(duì)該行進(jìn)行分割讀取。
  • LENGTH_MINIMUM <min-len>:每次讀取不少于給定長(zhǎng)度的字符串,如果某一行的字符串長(zhǎng)度低于指定長(zhǎng)度,則不會(huì)讀取到結(jié)果中。
  • LIMIT_COUNT <max-num>:限制提取的字符串子項(xiàng)個(gè)數(shù),例如默認(rèn)情況下是以換行分割讀取,假如<max-num>5,如果輸入文件有6行,那么只會(huì)讀取前5行。
  • LIMIT_INPUT <max-in>:限制從輸入文件的讀取的字節(jié)數(shù)。
  • LIMIT_OUTPUT <max-out>:限制存入到<variable>中的總字節(jié)數(shù),當(dāng)解析得到最后一個(gè)字符串子項(xiàng)長(zhǎng)度累加后超過(guò)指定長(zhǎng)度時(shí)候,最后一個(gè)字符串子項(xiàng)會(huì)丟棄。
  • NEWLINE_CONSUME:將換行符作為字符串內(nèi)容的一部分,而不是在換行時(shí)停止讀取。
  • NO_HEX_CONVERSIONIntel十六進(jìn)制和MotorolaS-record文件會(huì)自動(dòng)轉(zhuǎn)換成二進(jìn)制,除非指定了本選項(xiàng)。
  • REGEX <regex>:讀取匹配指定正則表達(dá)式的字符串。
  • ENCODING <encoding-type>3.1版本中引入。按照指定的編碼讀取字符串,當(dāng)前支持的編碼包括:UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE。此外,如果未指定本選項(xiàng)并且文件本身有字節(jié)順序標(biāo)記Byte Order Mark,那么會(huì)按照文件的字節(jié)順序標(biāo)記進(jìn)行解析。
# CMakeLists.txt
file(STRINGS myfile_read content_s) # 默認(rèn)會(huì)以換行將文件的內(nèi)容分割成多個(gè)子項(xiàng),按照分號(hào)序列的方式存儲(chǔ)
message("read myfile_read as STRINGS: ${content_s}")

# 限制每次提取的字符串長(zhǎng)度不超過(guò)10
file(STRINGS myfile_read content_s LENGTH_MAXIMUM 10)
message("read myfile_read as STRINGS - LMax: ${content_s}")

# 限制每次提取的字符串長(zhǎng)度至少為10,小于10會(huì)舍棄
file(STRINGS myfile_read content_s LENGTH_MINIMUM 10)
message("read myfile_read as STRINGS - LMin: ${content_s}")

# 限制提取的字符串子項(xiàng)數(shù)量最多為2個(gè)
file(STRINGS myfile_read content_s LIMIT_COUNT 2)
message("read myfile_read as STRINGS - LCount: ${content_s}")

# 限制只提取文件的前35個(gè)字符
file(STRINGS myfile_read content_s LIMIT_INPUT 35)
message("read myfile_read as STRINGS - LInput: ${content_s}")

# 限制輸出的總長(zhǎng)度為45
file(STRINGS myfile_read content_s LIMIT_OUTPUT 45)
message("read myfile_read as STRINGS - LOutput: ${content_s}")

# 不以換行進(jìn)行分割,輸出結(jié)果包含換行
file(STRINGS myfile_read content_s NEWLINE_CONSUME)
message("read myfile_read as STRINGS - Contain CR: ${content_s}")

myfile_read文件的原始內(nèi)容有三行:
THIS IS A FILE FOR READ TEST.
new line1
new line2

運(yùn)行結(jié)果為:
read myfile_read as STRINGS: THIS IS A FILE FOR READ TEST.;new line1;new line2
read myfile_read as STRINGS - LMax: THIS IS A ;FILE FOR R;EAD TEST.;new line1;new line2
read myfile_read as STRINGS - LMin: THIS IS A FILE FOR READ TEST.
read myfile_read as STRINGS - LCount: THIS IS A FILE FOR READ TEST.;new line1
read myfile_read as STRINGS - LInput: THIS IS A FILE FOR READ TEST.;new l
read myfile_read as STRINGS - LOutput: THIS IS A FILE FOR READ TEST.;new line1
read myfile_read as STRINGS - Contain CR: THIS IS A FILE FOR READ TEST.
new line1
new line2

  • file(<HASH> <filename> <variable>)

說(shuō)明:計(jì)算文件的hash結(jié)果,支持的hash算法可以參考string(<HASH>)。

# CMakeLists.txt
file(MD5 myfile_read content_hash)
message("Hash of myfile_read is: ${content_hash}")

運(yùn)行結(jié)果為:
Hash of myfile_read is: 6a4ff0158d402b69360ee52ba217faf3

  • file(TIMESTAMP <filename> <variable> [<format>] [UTC])

說(shuō)明:將文件的修改時(shí)間轉(zhuǎn)換成字符串表示,并存儲(chǔ)在結(jié)果<variable>中。如果無(wú)法獲得時(shí)間戳,字符串將置為""。<format>UTC選項(xiàng)的詳細(xì)使用方法見(jiàn)string(TIMESTAP)。未使用UTC選項(xiàng)時(shí),返回的時(shí)本地時(shí)間,默認(rèn)的格式為年-月-日T時(shí):分:秒;當(dāng)指定UTC選項(xiàng)時(shí),默認(rèn)格式為年-月-日T時(shí):分:秒Z。

# CMakeLists.txt
file(TIMESTAMP myfile_read time_string)
message("myfile_read modify time is(local time): ${time_string}")

file(TIMESTAMP myfile_read time_string UTC)
message("myfile_read modify time is(UTC): ${time_string}")

file(TIMESTAMP myfile_read time_string "%B.%d %Y-%H:%M:%S-%A")
message("myfile_read modify time is(format: 月.日 年-時(shí):分:秒-周): ${time_string}")

運(yùn)行結(jié)果為:
***myfile_read modify time is(local time): 2022-05-11T08:14:34
myfile_read modify time is(UTC): 2022-05-11T00:14:34Z
myfile_read modify time is(format: 月.日 年-時(shí):分:秒-周): May.11 2022-08:14:34-Wednesday*******

  • file(GET_RUNTIME_DEPENDENCIES[RESOLVED_DEPENDENCIES_VAR <deps_var>] [UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>] [CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>] [EXECUTABLES [<executable_files>...]] [LIBRARIES [<library_files>...]] [MODULES [<module_files>...]] [DIRECTORIES [<directories>...]] [BUNDLE_EXECUTABLE <bundle_executable_file>] [PRE_INCLUDE_REGEXES [<regexes>...]] [PRE_EXCLUDE_REGEXES [<regexes>...]] [POST_INCLUDE_REGEXES [<regexes>...]] [POST_EXCLUDE_REGEXES [<regexes>...]] [POST_INCLUDE_FILES [<files>...]] [POST_EXCLUDE_FILES [<files>...]])

說(shuō)明:這個(gè)命令比較復(fù)雜,且根install命令有關(guān),后續(xù)等install命令完成后返回來(lái)補(bǔ)充。

# CMakeLists.txt

運(yùn)行結(jié)果為:


3.2 子命令:寫
  • file(WRITE|APPEND <filename> <content>...)

說(shuō)明:將內(nèi)容寫入到指定的文件,如果文件不存在則創(chuàng)建文件;如果文件已經(jīng)存在,WRITE選項(xiàng)會(huì)覆蓋原文件,而APPEND則將內(nèi)容添加在原文件的末尾。此外,文件filename路徑中不存在的目錄也會(huì)被創(chuàng)建出來(lái)。

# CMakeLists.txt
file(WRITE myfile_wirte "write one line\n")
file(READ myfile_wirte content)
message("file(user wirte): ${content}")

file(WRITE myfile_wirte "write another line\n")
file(READ myfile_wirte content)
message("file(user wirte): ${content}")

file(APPEND myfile_wirte "append one line\n")
file(READ myfile_wirte content)
message("file(user append): ${content}")

運(yùn)行結(jié)果為:
file(user wirte): write one line

file(user wirte): write another line

file(user append): write another line
append one line

  • file(TOUCH|TOUCH_NOCREATE [<files>...])

說(shuō)明3.12版本引入。

  • TOUCH會(huì)創(chuàng)建一個(gè)內(nèi)容為空的新文件,如果文件已經(jīng)存在,那么該命令不會(huì)對(duì)文件的內(nèi)容有任何影響,只會(huì)將文件的訪問(wèn)或者修改時(shí)間更新為該命令調(diào)用時(shí)間。
  • TOUCH_NOCREATE選項(xiàng)不會(huì)創(chuàng)建新文件,如果文件不存在則會(huì)忽略,如果文件存在,那么則更新文件的訪問(wèn)或者修改時(shí)間為該命令調(diào)用的時(shí)間。

該命令可以指定多個(gè)文件。

# CMakeLists.txt
file(TIMESTAMP myfile_read modify_time)
message("myfile_read modify time is: ${modify_time}")
file(TOUCH_NOCREATE myfile_read) # 如果myfile_read不存在,那么不會(huì)創(chuàng)建文件,如果myfile_read存在,則更新其訪問(wèn)/修改時(shí)間
file(TIMESTAMP myfile_read modify_time)
message("after touch(but not create) myfile_read modify time is: ${modify_time}")
file(TOUCH mynewfile) # 創(chuàng)建新文件
file(TIMESTAMP mynewfile modify_time)
message("create mynewfile time is: ${modify_time}")

運(yùn)行結(jié)果為:
myfile_read modify time is: 2022-05-11T08:14:34
after touch(but not create) myfile_read modify time is: 2022-05-12T22:18:51
create mynewfile time is: 2022-05-12T22:18:51

  • file(GENERATE OUTPUT output-file <INPUT input-file|CONTENT content> [CONDITION expression] [TARGET target] [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS | FILE_PERMISSIONS <permissions>...] [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])

說(shuō)明:該命令跟生成表達(dá)式有關(guān),待完成生成表達(dá)式后補(bǔ)充。

3.3 子命令:文件系統(tǒng)
  • file(GLOB <variable> [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expressions>...])

說(shuō)明
??生成能匹配表達(dá)式<globbing-expressions>的一組文件,并將結(jié)果存入到<variable>中,結(jié)果按照字典序進(jìn)行排列(3.6版本及之后)。Globbing expressions與正則表達(dá)式類似,但是比正則表達(dá)式要簡(jiǎn)單很多。
??在WindowsmacOS系統(tǒng)中,Globbing expressions是大小寫不敏感的(在匹匹配為之前會(huì)將文件名和Globbing expressions轉(zhuǎn)換為小寫);其他系統(tǒng)Globbing expressions是大小寫敏感的。
??具體的選項(xiàng)解析如下:

  • LIST_DIRECTORIES:默認(rèn)情況下,結(jié)果會(huì)將目錄也列出來(lái),如果將LIST_DIRECTORIES設(shè)置為false,那么目錄會(huì)被忽略,只會(huì)列出文件存入結(jié)果中。
  • RELATIVE:指定該選項(xiàng),將返回匹配文件相對(duì)于RELATIVE指定的路徑。RELATIVE必須指定一個(gè)絕對(duì)路徑。
  • CONFIGURE_DEPENDS:指定該選項(xiàng),CMake會(huì)在構(gòu)建時(shí)重新運(yùn)行該命令。
# CMakeLists.txt
file(GLOB result "matches/*") # 列出目錄matches下的所有文件,帶全路徑
message("all files in matches: ${result}")
file(GLOB result "matches/*.txt") # 匹配matches下后綴為txt的文件,帶全路徑
message("match *.txt result: ${result}")
file(GLOB result RELATIVE /XXX/YYY/ZZZ/matches "myfile*")
message("list file: ${result}") # 查找當(dāng)前目錄./下的myfile開頭的文件,返回相對(duì)于./matches路徑的結(jié)果

運(yùn)行結(jié)果:
*all files in ./matches: /XXX/YYY/ZZZ/matches/log1.txt;/XXX/YYY/ZZZ/matches/log2.txt;/XXX/YYY/ZZZ/matches/log3.txt;/XXX/YYY/ZZZ/matches/log4.txt;/XXX/YYY/ZZZ/matches/log5.txt;/XXX/YYY/ZZZ/matches/test1.dat;//XXX/YYY/ZZZ/matches/test2.dat;/XXX/YYY/ZZZ/matches/test3.dat;/XXX/YYY/ZZZ/matches/test4.dat
match .txt result: /XXX/YYY/ZZZ/matches/log1.txt;/XXX/YYY/ZZZ/matches/log2.txt;/XXX/YYY/ZZZ/matches/log3.txt;/XXX/YYY/ZZZ/matches/log4.txt;/XXX/YYY/ZZZ/matches/log5.txt
list file: ../myfile_download;../myfile_read;../myfile_wirte;../myfile_write

  • file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS] [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expressions>...])

說(shuō)明
??與GLOB區(qū)別是,該子命令會(huì)遞歸的遍歷匹配目錄的所有子目錄,然后尋找匹配的文件。

  • file(MAKE_DIRECTORY [<directories>...])

說(shuō)明:創(chuàng)建指定目錄,如果指定的目錄的路徑中有不存在的目錄,也會(huì)一并創(chuàng)建。

file(MAKE_DIRECTORY ./dir1/dir2/dir3/mynewdir) # dir1、dir2、dir3、mynewdir目錄都會(huì)被創(chuàng)建

  • file(REMOVE|REMOVE_RECURSE [<files>...])

說(shuō)明:移除指定的文件,REMOVE_RECURSE模式將會(huì)移除給定的文件和目錄(即使目錄是非空的)。如果給定的文件不存在,也不會(huì)有錯(cuò)誤的信息提示,如果文件是以相對(duì)路徑提供,那么會(huì)以當(dāng)前目錄作為參考。
3.15版本之前,如果是空的文件路徑輸入,會(huì)將空路徑當(dāng)成相對(duì)路徑,以當(dāng)前目錄作為參考,刪除當(dāng)前目錄的內(nèi)容;而3.15及之后的版本,空的文件輸入會(huì)被忽略,并給出一個(gè)提示信息。

# CMakeLists.txt
file(REMOVE "./dir1/dir2/dir3/mynewdir/testfile1") # 刪除指定文件testfile1
file(REMOVE_RECURSE "./dir1/dir2/dir3/mynewdir/testfile2") # 刪除指定文件testfile2
file(REMOVE_RECURSE "./dir1/dir2/dir3/mynewdir") # 刪除指定目錄mynewdir,會(huì)遞歸刪除mynewdir目錄下所有的文件和子目錄,也會(huì)刪除mynewdir目錄本身
file(REMOVE "") # 3.15及之后的版本會(huì)忽略該語(yǔ)句并給出提示,假設(shè)該語(yǔ)句位于CMakeLists.txt文件的第23行,提示信息見(jiàn)下

運(yùn)行結(jié)果:
CMake Warning (dev) at CMakeLists.txt:23 (file):
Ignoring empty file name in REMOVE.
This warning is for project developers. Use -Wno-dev to suppress it.

  • file(RENAME <oldname> <newname> [RESULT <result>] [NO_REPLACE])

說(shuō)明:將指定的文件或者目錄從舊路徑<oldname>移動(dòng)到新路徑<newname>下,如果存在相同的名稱文件或者目錄會(huì)進(jìn)行自動(dòng)替換。

  • RESULT <result>3.21版本引入。如果命令執(zhí)行成功,將<result>變量置為0,否則<result>變量存儲(chǔ)錯(cuò)誤信息(CMake不會(huì)產(chǎn)生錯(cuò)誤)。如果未指定該選項(xiàng),當(dāng)執(zhí)行不成功,CMake會(huì)產(chǎn)生一個(gè)錯(cuò)誤。
  • NO_REPLACE3.21版本引入。默認(rèn)情況下新路徑下已經(jīng)存在文件或目錄,會(huì)自動(dòng)進(jìn)行替換,指定該選項(xiàng)則不會(huì)對(duì)相同的文件或目錄進(jìn)行替換,而是會(huì)產(chǎn)生一個(gè)錯(cuò)誤(如果指定了RESULT選項(xiàng),NO_REPLACE會(huì)存儲(chǔ)到RESULT指定的變量中。)
# CMakeLists.txt
file(RENAME ./rename_test/old/oldfile6 ./rename_test/new/) # 會(huì)提示錯(cuò)誤:No such file or directory
file(RENAME ./rename_test/old/oldfile6 ./rename_test/new/ RESULT info) # 不會(huì)提示錯(cuò)誤,錯(cuò)誤信息No such file or directory會(huì)存儲(chǔ)到info中
message("operation result: ${info}")
file(RENAME ./rename_test/old/oldfile1 ./rename_test/new/newfile1 RESULT info) # 執(zhí)行成功,info結(jié)果為0
message("operation result: ${info}")
file(RENAME ./rename_test/old/olddir1/oldfile4 ./rename_test/new/olddir1/oldfile4 NO_REPLACE RESULT info) # 有NO_REPLACE選項(xiàng),因此無(wú)法進(jìn)行替換操作,info中存儲(chǔ)的是NO_REPLACE
message("operation result: ${info}")
file(RENAME ./rename_test/old/olddir1/oldfile4 ./rename_test/new/olddir1/oldfile4 RESULT info) # 執(zhí)行成功,info結(jié)果為0
message("operation result: ${info}")

上述命令操作的文件樹結(jié)構(gòu)為:

├── CMakeLists.txt
├── rename_test
│   ├── new
│   │   └── olddir1
│   │       └── oldfile4
│   └── old
│   │   └── olddir1
│   │       └── oldfile4
│   |   ├── olddir1
│   |   ├── oldfile2
│   |   └── oldfile3

  • file(COPY_FILE <oldname> <newname> [RESULT <result>] [ONLY_IF_DIFFERENT])

說(shuō)明3.21版本引入。將文件從<oldname>復(fù)制到<newname>,不支持目錄的復(fù)制。如果<oldname>是一個(gè)符號(hào)鏈接,那么會(huì)讀取<oldname>實(shí)際鏈接的內(nèi)容,并將實(shí)際指向的內(nèi)容復(fù)制到<newname>中。該命令支持的幾個(gè)選項(xiàng)解析如下:

  • RESULT <result>:如果執(zhí)行成功,<result>變量?jī)?nèi)容為0,執(zhí)行出錯(cuò)該變量?jī)?nèi)容為具體的錯(cuò)誤信息。如果未指定該選項(xiàng)且命令執(zhí)行出錯(cuò),那么CMake會(huì)拋出錯(cuò)誤并停止構(gòu)建。
  • ONLY_IF_DIFFERENT:如果目標(biāo)文件<newname>已經(jīng)存在,并且<newname>文件的內(nèi)容與<oldname>內(nèi)容一樣,那么不做替換操作,這樣就可以避免更新<newname>的時(shí)間戳。
# CMakeLists.txt
file(COPY_FILE mydir mydir_copy) # 不支持目錄,如果不指定RESULT,CMake構(gòu)建會(huì)提示錯(cuò)誤:file COPY_FILE cannot copy a directory
file(COPY_FILE mydir mydir_copy RESULT result)
message("Copy dir result: ${result}") # 復(fù)制不成功,CMake構(gòu)建不會(huì)提示錯(cuò)誤,錯(cuò)誤信息會(huì)存到result中

file(COPY_FILE myfile myfile_copy RESULT result) # myfile內(nèi)容為"This is a file for testing."
file(TIMESTAMP myfile_copy ts)
message("Copy file result: ${result}, timestamp: ${ts}") # 復(fù)制成功,結(jié)果為0

execute_process(COMMAND sleep 5)
file(COPY_FILE myfile myfile_copy RESULT result) # 復(fù)制相同的內(nèi)容,未指定ONLY_IF_DIFFERENT選項(xiàng),仍會(huì)執(zhí)行賦值操作,注意時(shí)間戳打印不一致
file(TIMESTAMP myfile_copy ts)
message("Copy file for same content result: ${result}, timestamp: ${ts}")

execute_process(COMMAND sleep 5)
file(COPY_FILE myfile myfile_copy RESULT result ONLY_IF_DIFFERENT) # 復(fù)制相同的內(nèi)容,指定ONLY_IF_DIFFERENT選項(xiàng),不會(huì)執(zhí)行復(fù)制動(dòng)作,因此時(shí)間戳沒(méi)有變化
file(TIMESTAMP myfile_copy ts)
message("Copy file for same content result: ${result}, timestamp: ${ts}")

file(WRITE myfile_copy "Rewrite file content.")
execute_process(COMMAND sleep 5)
file(COPY_FILE myfile myfile_copy RESULT result ONLY_IF_DIFFERENT) # 由于目標(biāo)文件內(nèi)容和源文件內(nèi)容不一致了,會(huì)執(zhí)行復(fù)制操作
file(TIMESTAMP myfile_copy ts)
message("Copy file for different content result: ${result}, timestamp: ${ts}")

執(zhí)行結(jié)果為:
CMake Error at CMakeLists.txt:4 (file): file COPY_FILE cannot copy a directory

/XXX/YYY/ZZZ/mydir

Copy dir result: cannot copy a directory
Copy file result: 0, timestamp: 2022-05-15T08:07:51
Copy file for same content result: 0, timestamp: 2022-05-15T08:07:56
Copy file for same content(use ONLY_IF_DIFFEREBT)result: 0, timestamp: 2022-05-15T08:07:56
Copy file for different content result: 0, timestamp: 2022-05-15T08:08:06
-- Configuring incomplete, errors occurred!

  • file(<COPY|INSTALL> <files>... DESTINATION <dir> [NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS] [FILE_PERMISSIONS <permissions>...] [DIRECTORY_PERMISSIONS <permissions>...] [FOLLOW_SYMLINK_CHAIN] [FILES_MATCHING] [[PATTERN <pattern> | REGEX <regex>] [EXCLUDE] [PERMISSIONS <permissions>...]] [...])

說(shuō)明:如果只是簡(jiǎn)單的文件復(fù)制,可以使用前面的file(COPY_FILE)命令。相對(duì)于file(COPY_FILE),本命令是一個(gè)更復(fù)雜的命令,它可以復(fù)制文件、目錄、符號(hào)鏈接等。輸入文件的目錄是相對(duì)于當(dāng)前源文件路徑,目的文件路徑是相對(duì)于當(dāng)前構(gòu)建路徑。

  • COPY子命令會(huì)保存輸入文件的時(shí)間戳,如果目的文件存在,那么會(huì)將目的文件的時(shí)間戳修改成和輸入文件一致。默認(rèn)情況下(USE_SOURCE_PERMISSIONS選項(xiàng))也會(huì)將輸入文件的權(quán)限傳遞給目的文件,除非通過(guò)NO_SOURCE_PERMISSIONS選項(xiàng)顯示禁止。
  • INSTALL子命令與COPY子命令稍微不一樣的地方是:INSTALL子命令會(huì)打印狀態(tài)信息,并且默認(rèn)情況下不會(huì)將輸入文件的權(quán)限傳遞給目的文件(也就是默認(rèn)為NO_SOURCE_PERMISSIONS選項(xiàng))。install()命令就是使用file(INSTALL)命令來(lái)產(chǎn)生安裝腳本文件的。在3.22版本以后,還可以給CMAKE_INSTALL_MODE環(huán)境變量賦值來(lái)改變file(INSTALL)的默認(rèn)復(fù)制行為。
  • FOLLOW_SYMLINK_CHAIN:如果指定了該選項(xiàng),會(huì)遞歸的解析符號(hào)鏈接,直到找到最終的文件,并且每一個(gè)符號(hào)鏈接都會(huì)在指定的目的目錄創(chuàng)建出來(lái),并且都指向同個(gè)目錄下創(chuàng)建的最終文件。這個(gè)選項(xiàng)在類Unix系統(tǒng)下特別有用,在這些系統(tǒng)中,庫(kù)文件都是以版本號(hào)命名的符號(hào)鏈接形式安裝,由不具體的版本指向具體的版本。
  • 對(duì)于權(quán)限,FILES_MACHINGPATTERN、REGEXEXCLUDE請(qǐng)參考install(DIRECTORY)
目錄結(jié)構(gòu)為:
copy_test
├── dest
└── source
    ├── dir_for_copy
    │   └── file1
    └── libs
        ├── mylib.so
        ├── mylib.so.1 -> mylib.so
        ├── mylib.so.1.2 -> mylib.so.1
        └── mylib.so.1.2.3 -> mylib.so.1.2

# CMakeLists.txt
file(COPY copy_test/source/dir_for_copy/file1 DESTINATION copy_test/dest/) # 假定file1的權(quán)限是660,使用COPY,默認(rèn)拷貝后的文件權(quán)限也是660,查看 執(zhí)行結(jié)果1
file(INSTALL copy_test/source/dir_for_copy/file1 DESTINATION copy_test/dest/) # 假定file1的權(quán)限是660,使用INSTALL,默認(rèn)拷貝后的文件權(quán)限是644(系統(tǒng)默認(rèn)文件創(chuàng)建權(quán)限),查看 執(zhí)行結(jié)果2

file(COPY copy_test/source/dir_for_copy DESTINATION copy_test/dest/) # 拷貝dir_for_copy目錄

file(COPY copy_test/source/libs/mylib.so DESTINATION copy_test/dest/libs FOLLOW_SYMLINK_CHAIN) # 遞歸拷貝mylib.so的鏈接并創(chuàng)建,查看 執(zhí)行結(jié)果3
file(COPY copy_test/source/libs/mylib.so DESTINATION copy_test/dest/libs_nosymlink) # 只會(huì)拷貝單個(gè)mylib.so文件,查看 執(zhí)行結(jié)果4

  • 執(zhí)行結(jié)果1:
    復(fù)制前的file1權(quán)限:
    -rw-rw---- copy_test/source/dir_for_copy/file1
    復(fù)制后的file1權(quán)限:
    -rw-rw---- copy_test/dest/file1
  • 執(zhí)行結(jié)果2:
    復(fù)制前的file1權(quán)限:
    -rw-rw---- copy_test/source/dir_for_copy/file1
    復(fù)制后的file1權(quán)限:
    -rw-r--r-- copy_test/dest/file1
    并且使用INSTALL會(huì)打印處中間的執(zhí)行狀態(tài)信息:
    -- Up-to-date: /XXX/YYY/ZZZ/copy_test/dest//file1
  • 執(zhí)行結(jié)果3:
    FOLLOW_SYMLINK_CHAIN選項(xiàng),復(fù)制后的目錄結(jié)構(gòu),會(huì)將整個(gè)鏈接遞歸創(chuàng)建出來(lái):
    copy_test
    ├── dest
    │ ├── libs
    │ │ ├── mylib.so -> mylib.so.1
    │ │ ├── mylib.so.1 -> mylib.so.1.2
    │ │ ├── mylib.so.1.2 -> mylib.so.1.2.3
    │ │ └── mylib.so.1.2.3
    └── source
    ├── dir_for_copy
    │ └── file1
    └── libs
    ├── mylib.so -> mylib.so.1
    ├── mylib.so.1 -> mylib.so.1.2
    ├── mylib.so.1.2 -> mylib.so.1.2.3
    └── mylib.so.1.2.3
  • 執(zhí)行結(jié)果4:
    沒(méi)有FOLLOW_SYMLINK_CHAIN選項(xiàng),只會(huì)將鏈接文件當(dāng)成普通文件復(fù)制:
    copy_test
    ├── dest
    │ └── libs_nosymlink
    │ └── mylib.so -> mylib.so.1
    └── source
    ├── dir_for_copy
    │ └── file1
    └── libs
    ├── mylib.so -> mylib.so.1
    ├── mylib.so.1 -> mylib.so.1.2
    ├── mylib.so.1.2 -> mylib.so.1.2.3
    └── mylib.so.1.2.3
  • file(SIZE <filename> <variable>)

說(shuō)明3.14版本引入,計(jì)算文件的大小,要求指向文件的路徑是合法的路徑,且文件本身是可讀的。

# CMakeLists.txt
set(filename "myfile_read")
file(SIZE ${filename} sz)
message("file ${filename} size is : ${sz} bytes")

執(zhí)行結(jié)果為:
file myfile_read size is : 50 bytes

  • file(READ_SYMLINK <linkname> <variable>)

說(shuō)明3.14版本引入。讀取鏈接文件并將該鏈接文件指向的文件路徑保存到變量<variable>中,如果鏈接文件不存在,CMake會(huì)拋出一個(gè)錯(cuò)誤。需要注意的是,該命令返回的時(shí)候鏈接文件原始指向的文件路徑,并且是相對(duì)路徑。

# CMakeLists.txt
set(linkname "/XXX/YYY/ZZZ/copy_test/source/libs/mylib.so")
file(READ_SYMLINK ${linkname} result) # 復(fù)制的是mylib.so執(zhí)行的mylib.so.1,且不會(huì)遞歸解析
message("Get link result: ${result}")

# 可以通過(guò)如下方法來(lái)獲取絕對(duì)路徑
if (NOT IS_ABSOLUTE "${result}")
    get_filename_component(dir "${linkname}" DIRECTORY)
    set(result "${dir}/${result}")
endif()
message("Get link result after add absolute path: ${result}")

執(zhí)行結(jié)果為:
Get link result: mylib.so.1
Get link result after add absolute path: /XXX/YYY/ZZZ/copy_test/source/libs/mylib.so.1

  • file(CREATE_LINK <original> <linkname> [RESULT <result>] [COPY_ON_ERROR] [SYMBOLIC])

說(shuō)明3.14版本引入,創(chuàng)建一個(gè)指向<original>的鏈接文件<linkname>,如果<linkname>已經(jīng)存在,則會(huì)被覆蓋。默認(rèn)創(chuàng)建的是硬鏈接(硬鏈接要求原始文件存在且不是目錄)。

  • RESULT <result>:如果執(zhí)行成功,<result>變量?jī)?nèi)容為0,執(zhí)行出錯(cuò)該變量?jī)?nèi)容為具體的錯(cuò)誤信息。如果未指定該選項(xiàng)且命令執(zhí)行出錯(cuò),那么CMake會(huì)拋出錯(cuò)誤并停止構(gòu)建。
  • SYMBOLIC:創(chuàng)建軟連接。
  • COPY_ON_ERROR:如果創(chuàng)建鏈接文件失敗,那么復(fù)制文件。主要用于<original><linkname>在不同的驅(qū)動(dòng)器或者掛在點(diǎn)的場(chǎng)景,此時(shí)創(chuàng)建硬鏈接會(huì)失敗,用此選項(xiàng)可以復(fù)制文件。
# CMakeLists.txt
set(original "myfile_read")
file(CREATE_LINK ${original} myfile_read_hardlink)
file(CREATE_LINK ${original} myfile_read_softlink SYMBOLIC)

執(zhí)行結(jié)果為,硬鏈接用ls -l查詢,數(shù)字是2
-rw-r--r-- 2 myfile_read
-rw-r--r-- 2 shengyi staff 50 5 12 22:18 myfile_read_hardlink
lrwxr-xr-x 1 shengyi staff 11 5 17 08:52 myfile_read_softlink -> myfile_read

  • file(CHMOD <files>... <directories>... [PERMISSIONS <permissions>...] [FILE_PERMISSIONS <permissions>...] [DIRECTORY_PERMISSIONS <permissions>...])

說(shuō)明3.19版本引入,修改指定文件或目錄的權(quán)限,合法的權(quán)限設(shè)置選項(xiàng)有:OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, WORLD_READ, WORLD_WRITE, WORLD_EXECUTE, SETUID, SETGID。此外,PERMISSIONS、FILE_PERMISSIONS、DIRECTORY_PERMISSIONS只能單獨(dú)使用或者按照如下方式組合使用:

  • PERMISSIONS:所有指定的文件或目錄的權(quán)限都會(huì)被修改。
  • FILE_PERMISSIONS:只改變指定文件的權(quán)限。
  • DIRECTORY_PERMISSIONS:只改變指定目錄的權(quán)限。
  • 同時(shí)指定PERMISSIONSFILE_PERMISSIONS:文件的權(quán)限會(huì)被FILE_PERMISSIONS指定的權(quán)限覆寫。
  • 同時(shí)指定PERMISSIONSDIRECTORY_PERMISSIONS:目錄的權(quán)限會(huì)被DIRECTORY_PERMISSIONS指定的權(quán)限覆寫。
  • 同時(shí)指定FILE_PERMISSIONSDIRECTORY_PERMISSIONSFILE_PERMISSIONS指定的權(quán)限應(yīng)用于文件,DIRECTORY_PERMISSIONS指定的權(quán)限應(yīng)用于目錄。
# CMakeLists.txt
# 備注:原始權(quán)限 file_test 644; dir_test 755
file(CHMOD file_test PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE WORLD_READ WORLD_WRITE) # 修改權(quán)限為666
#file(CHMOD dir_test PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_WRITE WORLD_EXECUTE) # 修改權(quán)限為777

file(CHMOD file_test PERMISSIONS OWNER_READ GROUP_READ WORLD_READ FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ GROUP_WRITE WORLD_READ) # FILE_PERMISSIONS指定權(quán)限起作用,修改為664
file(CHMOD dir_test PERMISSIONS OWNER_READ GROUP_READ WORLD_READ DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) # DIRECTORY_PERMISSIONS指定的權(quán)限起作用,修改為755

  • file(CHMOD_RECURSE <files>... <directories>... [PERMISSIONS <permissions>...] [FILE_PERMISSIONS <permissions>...] [DIRECTORY_PERMISSIONS <permissions>...])

說(shuō)明3.19版本引入,與CHMOD的區(qū)別就是CHMOD_RECURSE會(huì)遞歸的修改指定目錄下的子目錄和文件權(quán)限,類似于Linux命令chmod -R。

3.4 子命令:路徑轉(zhuǎn)換
  • file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>] [EXPAND_TILDE])

說(shuō)明3.19版本中引入。計(jì)算指定路徑的絕對(duì)路徑。

  • BASE_DIRECTORY <dir>:如果指定了該選項(xiàng),且給定待轉(zhuǎn)換的路徑<path>是一個(gè)相對(duì)路徑,那么計(jì)算<path>相對(duì)于<dir>的路徑。如果未指定該選項(xiàng),那么計(jì)算<path>相對(duì)于CMAKE_CURRENT_SOURCE_DIR環(huán)境變量的路徑。
  • EXPAND_TILDE3.21版本新增。如果<path>~或以~/開頭,那么~會(huì)被替換為用戶的home目錄。home目錄的值是從環(huán)境變量中得到,在Wndows下,首先會(huì)從USERPROFILE環(huán)境變量獲取,如果未指定該環(huán)境變量,則會(huì)從HOME環(huán)境變量中獲?。黄渌到y(tǒng)只會(huì)從HOME環(huán)境變量中獲取。
# CMakeLists.txt
file(REAL_PATH dir_test result BASE_DIRECTORY "/bin")
message("Conversion result: ${result}")

message("Home path is : $ENV{HOME}")
file(REAL_PATH "~/dir_test" result BASE_DIRECTORY "/bin" EXPAND_TILDE) # 此時(shí)會(huì)忽略掉BASE_DIRECTORY指定的值
message("Conversion result: ${result}")

運(yùn)行結(jié)果(macOS系統(tǒng)):
Conversion result: /bin/dir_test
Home path is : /Users/user1
Conversion result: /Users/user1/dir_test

  • file(RELATIVE_PATH <variable> <directory> <file>)

說(shuō)明:計(jì)算<directory><file>的相對(duì)路徑,實(shí)際上就是怎么從<directory>通過(guò).、..等切換到<file>。需要注意的是,<directory><file>都必須是絕對(duì)路徑。

# CMakeLists.txt
file(RELATIVE_PATH result /usr/local /etc/passwd)
message("Conversion result: ${result}")

運(yùn)行結(jié)果(macOS系統(tǒng)):
Conversion result: ../../etc/passwd

  • file(TO_CMAKE_PATH|TO_NATIVE_PATH "<path>" <variable>)

說(shuō)明TO_CMAKE_PATH將系統(tǒng)原生路徑轉(zhuǎn)換為CMake風(fēng)格的路徑。TO_NATIVE_PATH則反過(guò)來(lái),將CMake風(fēng)格的路徑轉(zhuǎn)換為系統(tǒng)原生路徑。

  • CMake風(fēng)格的路徑:路徑以/作為目錄之間的分隔符,且多個(gè)目錄以;分割的序列。
  • 原生系統(tǒng)路徑:在Windows下,以\作為目錄分隔符,多個(gè)路徑以;分隔;而在其他系統(tǒng),以/作為目錄分隔符,多個(gè)路徑以:分隔。例如在我的macOS下,PATH環(huán)境變量(對(duì)應(yīng)系統(tǒng)原生路徑)為:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

注意:子命令RELATIVE_PATH, TO_CMAKE_PATHTO_NATIVE_PATH已經(jīng)分別被cmake_path的子命令RELATIVE_PATH、CONVERT ... TO_CMAKE_PATH_LIST、CONVERT ... TO_NATIVE_PATH_LIST取代。因此直接參考cmake_path的相關(guān)命令。

3.5 子命令:傳輸
  • file(DOWNLOAD <url> [<file>] [<options>...]);file(UPLOAD <file> <url> [<options>...])

說(shuō)明:從<url>指定的地址下載到本地<file>中。從3.19版本開始,如果沒(méi)有指定本地文件<file>,那么不會(huì)保存文件,這樣在檢測(cè)待下載文件是否存在的時(shí)候比較有用。該命令還有許多可選項(xiàng),解析如下:

  • INACTIVITY_TIMEOUT <seconds>:當(dāng)超過(guò)指定時(shí)間沒(méi)有活動(dòng)則終止操作(上傳/下載)。
  • LOG <variable>:將可讀的日志存儲(chǔ)到變量中。
  • SHOW_PROGRESS:打印進(jìn)度信息。
  • STATUS <variable>:存儲(chǔ)命令的操作(上傳/下載)結(jié)果,由長(zhǎng)度為2,以;分隔的序列組成,序列的第一個(gè)元素是一個(gè)以數(shù)字表示的結(jié)果返回值,第二元素是一個(gè)字符串表示錯(cuò)誤的信息。如果沒(méi)有出錯(cuò),則只返回0。
  • TIMEOUT <seconds>:超時(shí)后終止操作(上傳/下載)。
  • USERPWD <username>:<password>3.7新增,為操作(上傳/下載)指定用戶名和密碼。
  • HTTPHEADER <HTTP-header>3.7新增,為操作(上傳/下載)指定http協(xié)議的頭,該選項(xiàng)可以重復(fù)多次使用。
  • NETRC <level>3.11新增,指定操作(上傳/下載)是否使用.netrc文件,如果未指定該選項(xiàng),那么會(huì)從變量CMAKE_NETRC中獲取,有如下幾個(gè)級(jí)別:IGNORED表示忽略.netrc文件,也是選項(xiàng)的默認(rèn)值;OPTIONAL表示.netrc文件可選,會(huì)優(yōu)先從URL中獲取信息,如果未從URL獲取到信息則會(huì)從.netrc文件獲?。?code>REQUIRED表示使用.netrc文件,忽略URL中的信息。
  • NETRC_FILE <file>3.11新增,指定另一個(gè).netrc文件,來(lái)替換home目錄下的.netrc文件。如果未指定該選項(xiàng),則會(huì)從CMAKE_NETRC_FILE變量中獲取。
  • TLS_VERIFY <ON|OFF>:指定是否校驗(yàn)https URL服務(wù)器證書,默認(rèn)是不驗(yàn)證。如果未指定該選項(xiàng),則會(huì)從CMAKE_TLS_VERIFY變量中獲取。3.18版本中增加了對(duì)file(UPLOAD)的支持。
  • TLS_CAINFO <file>:為https URL指定一個(gè)定制的證書鑒權(quán)文件。未指定該選項(xiàng),則會(huì)從CMAKE_TLS_CAINFO變量中獲取。3.18版本中增加了對(duì)file(UPLOAD)的支持。

如下選項(xiàng)只支持DOWNLOAD

  • EXPECTED_HASH ALGO=<value>:驗(yàn)證下載的內(nèi)容的哈希值是否匹配期望的哈希值。ALGO指定file(HASH)支持的HASH算法,如果不匹配下載會(huì)出錯(cuò)。注意,如果未指定本地<file>文件,該命令會(huì)執(zhí)行出錯(cuò)。
  • EXPECTED_MD5 <value>:該選項(xiàng)是為了兼容歷史選項(xiàng),實(shí)際上可以用上面的命令替代。它校驗(yàn)下載內(nèi)容的MD5值和期望的是否匹配。如果不匹配下載會(huì)出錯(cuò)。注意,如果未指定本地<file>文件,該命令會(huì)執(zhí)行出錯(cuò)。
3.6 子命令:鎖
  • file(LOCK <path> [DIRECTORY] [RELEASE] [GUARD <FUNCTION|FILE|PROCESS>] [RESULT_VARIABLE <variable>] [TIMEOUT <seconds>])

說(shuō)明3.2版本新增。鎖定<path>指定的文件。

  • DIRECTORY:指定該選項(xiàng)會(huì)鎖定目錄,并會(huì)創(chuàng)建一個(gè)<path>/cmake.lock文件。
  • GUARD:指定鎖定的范圍,默認(rèn)是PROCESS(進(jìn)程),可選的還有FUNCTION(函數(shù))和FILE(文件)。
  • RELEASE:顯式的釋放鎖。指定該選項(xiàng)時(shí),GUARDTIMEOUT會(huì)被忽略。
  • TIMEOUT:指定等待鎖定的超時(shí)時(shí)間,如果值為0,表示只會(huì)嘗試去鎖定一次,其他非0值則是嘗試鎖定文件的超時(shí)時(shí)間。如果未指定該選項(xiàng),則會(huì)一直嘗試鎖定,直到鎖定成功或者出錯(cuò)。
  • RESULT_VARIABLE:存儲(chǔ)命令執(zhí)行的結(jié)果,如果成功,結(jié)果是0,否則存儲(chǔ)具體的錯(cuò)誤。如果未指定該選項(xiàng),發(fā)生錯(cuò)誤時(shí)候CMake會(huì)終止構(gòu)建并拋出錯(cuò)誤。

鎖只是一個(gè)建議項(xiàng),不能保證鎖定后進(jìn)程也會(huì)遵循。也不能對(duì)一個(gè)文件鎖定2次。

為了驗(yàn)證,我們創(chuàng)建了兩個(gè)CMakeLists.txt文件對(duì)同一個(gè)文件/目錄進(jìn)行鎖定,目錄樹如下:
├── CMakeLists.txt
├── file_lock_test
│ ├── CMakeLists.txt
├── myfile_read
├── myfile_read_dir

# 頂層的CMakeLists.txt:在鎖定文件myfile_read和文件夾myfile_read_dir后,睡眠50秒,目的是讓file_lock_test下的CMakeLists.txt指定
file(LOCK myfile_read_dir DIRECTORY RESULT_VARIABLE result)
message("lock myfile_read_dir result: ${result}")
file(LOCK myfile_read RESULT_VARIABLE result)
message("lock myfile_read result: ${result}")
execute_process(COMMAND sleep 50)

# file_lock_test下的CMakeLists.txt
file(LOCK ../myfile_read_dir DIRECTORY RESULT_VARIABLE result TIMEOUT 0)
message("lock dir myfile_read_dir result: ${result}")
file(LOCK ../myfile_read RESULT_VARIABLE result TIMEOUT 10)
message("lock myfile_read result: ${result}")

運(yùn)行結(jié)果:
首先執(zhí)行頂層的CMakeLists.txt,出現(xiàn)如下打印說(shuō)明鎖定成功
lock myfile_read_dir result: 0
lock myfile_read result: 0

然后執(zhí)行file_lock_test下的CMakeLists.txt,出現(xiàn)如下打印說(shuō)明文件或者目錄已經(jīng)被鎖定,命令超時(shí)退出了
lock dir myfile_read_dir result: Timeout reached
lock myfile_read result: Timeout reached

3.7 子命令:歸檔
  • file(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [FORMAT <format>] [COMPRESSION <compression> [COMPRESSION_LEVEL <compression-level>]] [MTIME <mtime>] [VERBOSE])

說(shuō)明3.18版本新增。將PATHS指定的文件和目錄進(jìn)行歸檔,不支持通配符。

  • FORMAT:指定歸檔的格式,支持7zip, gnutar, pax, paxr, raw, zip,如果未指定該選項(xiàng),默認(rèn)歸檔格式是paxr
  • COMPRESSION:指定壓縮方式,7zipzip歸檔格式已經(jīng)使用壓縮,其他格式默認(rèn)不壓縮,因此需要指定壓縮方式,支持的壓縮方式有None, BZip2, GZip, XZ, Zstd。
  • COMPRESSION_LEVEL3.19版本新增。在指定壓縮方式的前提下,可以指定壓縮級(jí)別,范圍是0-9,默認(rèn)是0
  • VERBOSE:呈現(xiàn)歸檔命令的輸出。
  • MTIME:如果要指定壓縮文件的修改時(shí)間,指定該選項(xiàng)。

待壓縮文件夾的結(jié)構(gòu)為:
archive_test
├── dir1
│ └── file4
├── file1
├── file2
└── file

# CMakeLists.txt
file(ARCHIVE_CREATE OUTPUT result.tar.gz PATHS archive_test FORMAT gnutar COMPRESSION GZip VERBOSE MTIME "2022/5/18 23:59:59")

運(yùn)行結(jié)果,并生成了一個(gè)result.tar.gz的壓縮包:
archive_test
archive_test/file3
archive_test/file2
archive_test/file1
archive_test/dir1
archive_test/dir1/file4

  • file(ARCHIVE_EXTRACT INPUT <archive> [DESTINATION <dir>] [PATTERNS <patterns>...] [LIST_ONLY] [VERBOSE])

說(shuō)明3.18版本新增。提取或者顯示歸檔文件的內(nèi)容。

  • DESTINATION:將歸檔文件提取到指定路徑。
  • PATTERNS:通過(guò)該選項(xiàng),可以從歸檔文件中提取或者顯示指定的文件/目錄,支持通配符。
  • LIST_ONLY:顯示歸檔文件內(nèi)容,不提取。
  • VERBOSE:呈現(xiàn)提取歸檔文件命令的輸出。

以歸檔的result.tar.gz為例:

# CMakeLists.txt
message("====list========")
file(ARCHIVE_EXTRACT INPUT result.tar.gz VERBOSE LIST_ONLY) # 顯示歸檔文件內(nèi)容,不提取
message("====extract dir1/file4========")
file(ARCHIVE_EXTRACT INPUT result.tar.gz DESTINATION extract_dir1 PATTERNS "*dir1/*" VERBOSE) # 提取dir1目錄下文件到extract_dir1目錄
message("====extract all========")
file(ARCHIVE_EXTRACT INPUT result.tar.gz DESTINATION extract_dir2 VERBOSE) # 提取全部?jī)?nèi)容到extract_dir2目錄

運(yùn)行結(jié)果:
====list========
drwxr-xr-x 0 shengyi staff 0 18 May 23:59 archive_test/
-rw-r--r-- 0 shengyi staff 8 18 May 23:59 archive_test/file3
-rw-r--r-- 0 shengyi staff 8 18 May 23:59 archive_test/file2
-rw-r--r-- 0 shengyi staff 6 18 May 23:59 archive_test/file1
drwxr-xr-x 0 shengyi staff 0 18 May 23:59 archive_test/dir1/
-rw-r--r-- 0 shengyi staff 8 18 May 23:59 archive_test/dir1/file4
====extract dir1/file4========
x archive_test/dir1/
x archive_test/dir1/file4
====extract all========
x archive_test/
x archive_test/file3
x archive_test/file2
x archive_test/file1
x archive_test/dir1/
x archive_test/dir1/file4

extract_dir1目錄內(nèi)容:
extract_dir1
└── archive_test
└── dir1
└── file4

extract_dir2目錄內(nèi)容:
extract_dir2
└── archive_test
├── dir1
│ └── file4
├── file1
├── file2
└── file3

附錄:參考目錄

  1. https://cmake.org/cmake/help/latest/command/file.html
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容