使用cmake 文件操作时不可避免需要操作相关文件,比如读取文件内容,创建新文件的等等操作,都需要通过file命令进行操作。

读文件操作

file READ命令

常用的从文件中读取操作为file(READ <filename> <variable>),将filename文件中内容原封不动读取到variable变量中,命令行全部格式为:

file(read <filename> <variable> [OFFSET <offset>] [LIMIT <max-in>] [HEX])

  • filename: 必选项 为要读取的文件,可以带绝对路径
  • variable: 必选项,将文件内容读取到varible变量中。
  • OFFSET <offset>:可选项,从文件中偏移位置offset 开始读取文件内容
  • HEX:可选项,可以将读取文件内容转换成十六进制。

用例

LIMIT <max-in>: 可选项 最多读取<max-in>长度的内容到变量中

以一个例子说明,实验目录下有两个文件,使用tree命令查看:

$ tree
.
├── CMakeLists.txt
└── test.cpp

0 directories, 2 files
$

test.cpp文件内容如下:

#include <stdio.h>
#include <stdlib.h>



int main(){
    printf("hello world!\n");
}

CMakeList.txt文件内容如下:

cmake_minimum_required(VERSION 3.13.4)

project(cmake_read)

message("--------Proj Src Dir: " ${PROJECT_SOURCE_DIR})
file(READ ${PROJECT_SOURCE_DIR}/test.cpp TEST_RESULT)
message("--------TEST RESULT: " ${TEST_RESULT})

使用file(read)命令将文件test.cpp的内容读取到TEST_RESULT变量中,并打印出来,使用cmake运行:

$  /public/home/huozhikun/cmake/cmake-3.17.0/bin/cmake ..
CMake Error: The source directory "/public/home/huozhikun/test/cmake/read" does not appear to contain CMakeLists.txt.
Specify --help for usage, or press the help button on the CMake GUI.
[huozhikun@login09 example]$ cd build/
[huozhikun@login09 build]$  /public/home/huozhikun/cmake/cmake-3.17.0/bin/cmake ..
-- The C compiler identification is GNU 7.3.1
-- The CXX compiler identification is GNU 7.3.1
-- Check for working C compiler: /opt/rh/devtoolset-7/root/usr/bin/cc
-- Check for working C compiler: /opt/rh/devtoolset-7/root/usr/bin/cc - works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /opt/rh/devtoolset-7/root/usr/bin/c++
-- Check for working CXX compiler: /opt/rh/devtoolset-7/root/usr/bin/c++ - works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
--------Proj Src Dir: /public/home/huozhikun/test/cmake/read/example
--------TEST RESULT: #include <stdio.h>
#include <stdlib.h>



int main(){
    printf("hello world!\n")
}

-- Configuring done
-- Generating done
-- Build files have been written to: /public/home/huozhikun/test/cmake/read/example/build

将test.cpp的文件内容原封不动读取到TEST_RESULT变量中。

file STRINGS命令

file STRINGS命令是将文件的内容读取成一串ASCII字符串到变量中,其中二进制文件将会被忽略,在读取文件中 回车及\r将会被忽略:

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

 options支持的可选项有以下:

  • LENGTH_MAXMUN <max-len>: 最多从文件<filename>中读取<max-len>长度字符串到变量<variable>中
  • LENGTH_MINIMUN <min-len>:至少要从文件<filename>读取<min_len>长度的字符串到变量<variable>中
  • LIMIT_COUNT <max-num>: 限制要去读的字符串数量
  • LIMIT_OUTPUT <max-out>:限制读取到<variable>变量总长度单位字节
  • NEWLINE_CONSUME: 读取文件时不忽略换行符(\n,LF),将其视为字符串的内容
  • NO_HEX_CONVERSION:  如果不给出此选项英特尔十六进制和摩托罗拉s记录文件在读取时自动转换为二进制文件。
  • REGX <regex>: 使用正则匹配,只将匹配的结果保存到变量中
  • ENCODING <encoding-type>: 指定字符串的编码格式,目前支持UTF-8, UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE。如果没有指定,按照文件中字节顺序标记。

用例

继续上上述用例cmakelist修改为:

cmake_minimum_required(VERSION 3.13.4)

project(cmake_read)

message("--------Proj Src Dir: " ${PROJECT_SOURCE_DIR})
file(STRINGS ${PROJECT_SOURCE_DIR}/test.cpp TEST_RESULT)
message("--------TEST RESULT: " ${TEST_RESULT})

运行结果如下:

$  /public/home/huozhikun/cmake/cmake-3.17.0/bin/cmake ..
--------Proj Src Dir: /public/home/huozhikun/test/cmake/read/example_2
--------TEST RESULT: #include <stdio.h>#include <stdlib.h>int main(){    printf("hello world!\n");}
-- Configuring done
-- Generating done
-- Build files have been written to: /public/home/huozhikun/test/cmake/read/example_2/build
$

file <HASH>

file <HASH>主要是将文件的字符串内容经过加密读取到变量中,命令格式为:

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

支持的HASH 加密算法 有如下:

  • MD5、SHA!、SHA224、SHA256、SHA384、SHA512、SHA3_224、SHA3_256、SHA3_384、SHA3_512等

 file TIMESTAMP

file TIMESTAMP只读取文件最后修改的时间搓,命令行格式如下:

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

  • UTC:可选项 采用的世界时间,而不是当地时间
  •  <format> :可选项,支持的时间格式:
%%        A literal percent sign (%).
%d        The day of the current month (01-31).
%H        The hour on a 24-hour clock (00-23).
%I        The hour on a 12-hour clock (01-12).
%j        The day of the current year (001-366).
%m        The month of the current year (01-12).
%b        Abbreviated month name (e.g. Oct).
%B        Full month name (e.g. October).
%M        The minute of the current hour (00-59).
%s        Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).
%S        The second of the current minute.
          60 represents a leap second. (00-60)
%U        The week number of the current year (00-53).
%w        The day of the current week. 0 is Sunday. (0-6)
%a        Abbreviated weekday name (e.g. Fri).
%A        Full weekday name (e.g. Friday).
%y        The last two digits of the current year (00-99)
%Y        The current year.

默认情况下格式为:

%Y-%m-%dT%H:%M:%S    当地时间格式
%Y-%m-%dT%H:%M:%SZ   UTC时间时间格式.

用例

 继续上次用例继续修改CMakelist:

cmake_minimum_required(VERSION 3.13.4)

project(cmake_read)

message("--------Proj Src Dir: " ${PROJECT_SOURCE_DIR})
file(TIMESTAMP ${PROJECT_SOURCE_DIR}/test.cpp TEST_RESULT)
message("--------TEST RESULT: " ${TEST_RESULT})

cmake运行结果:

$  /public/home/huozhikun/cmake/cmake-3.17.0/bin/cmake ..
--------Proj Src Dir: /public/home/huozhikun/test/cmake/read/example_4
--------TEST RESULT: 2022-01-18T20:25:12
-- Configuring done
-- Generating done
-- Build files have been written to: /public/home/huozhikun/test/cmake/read/example_4/build
$ 

写文件操作

file WRITE命令

file WRITE命令是常用的写操作命令,命令行格式如下:

file(WRITE <filename> <content> ... )

把<content>内容写入到文件<filename>中,如果文件不存在,则创建该文件将<content>写入到文件中。如果该文件存在则将该文件内容清空并将<content>写入到文件中。

用例 

cmakelist中通过WRITE命令,创建test.cpp文件并向其中写入hello world:

cmake_minimum_required(VERSION 3.13.4)

project(cmake_read)

message("--------Proj Src Dir: " ${PROJECT_SOURCE_DIR})
set(TEST_CONTENT "hello world")
file(WRITE ${PROJECT_SOURCE_DIR}/test.cpp ${TEST_CONTENT})
message("--------TEST_CONTENT: " ${TEST_CONTENT}

cmake ..运行结果 查看生成test.cpp文件,文件内容如下:

hello world

 file APPEND命令

file APPEND用于向文件中追加内容,如果文件不存在,会创建该文件,如果该文件存在不会覆盖文件中的旧内容,将内容<content>追加到文件末尾,命令行格式如下:

file(APPEND  <filename> <content> ... )

用例

继续上一个用例,在文件test.cpp末尾添加 "I am coming":

cmake_minimum_required(VERSION 3.13.4)

project(cmake_read)

message("--------Proj Src Dir: " ${PROJECT_SOURCE_DIR})
set(TEST_CONTENT "\nI am coming")
file(APPEND ${PROJECT_SOURCE_DIR}/test.cpp ${TEST_CONTENT})
message("--------TEST_CONTENT: " ${TEST_CONTENT})

cmake运行完毕之后,test.cpp文件内容, I am coming 追加到文件末尾如下:

hello world
I am coming

file TOUCH命令

file TOUCH命令用于创建一个空文件,命令行格式如下:

file(TOUCH [<files> ...])

 如果文件没有,则创建一个新的空文件,如果文件已经存在,则只是刷新文件最后修改时间。

TOUCH命令还有一个扩展TOUCH_NOCREATE命令:

file(TOUCH_NOCREATE [<files> ...])

 TOUNCH_NOCREATE命令当文件不存在时,不创建新的文件。

file GENERATE命令

file GENARATE命令用于一般用于每次构建时将一些所需要过程信息或者调试变量等信息输出到文件中,与其他命令区是支持cmake generator生成器,而且保证是本次构建生成的内容,命令行格式为:

file(GENERATE OUTPUT output-file <INPUT input-file|CONTENT content> [CONDITION expression])

  • CONTENT <content>:将<content>内容输入到output-file文件中
  • INPUT <input-file>将输入文件<input-file> 作为输入输出到output-file文件中
  • OUTPUT <out-file>:输出文件
  • CONDITION <expression>: 仅在表达式为true/1, 输出到文件中,否则不输出

CONDITION <expression>

cmake 支持的常用逻辑表达式<expression> 格式大概有如下:

  • $<BOOL:...> :bool表达式如果...中结果为true 则为1, 否则结果0
  • $<AND:?[,?]...>:如果所有?都为1 最终结果为1,否则为0。其中?必须是结果为0或者为1的bool表达式
  • $<OR:?[.?]...>:如果?全部为0,结果才为0
  • $<NOT:?>:如果?为1,则结果为0,否则为1
  • $<IF:?,true-value...,false-value...: 如果?为1,则执行true-value,否则执行alse-value
  • $<STREQUAL:a,b>: 如果a和b相等则结果为1(a和b为都是字符串),否则为0
  • $<EQUAL:a,b>: 如果a和b相等则结果为1(a和b都是数字),否则为0
  • $<IN_LIST:a,b>: 如果 a在b列表中即b包含a,结果为1,否则为0
  • $<TARGET_EXISTS:tgt>:如果 tgt是存在的一个target name,结果为1, 否则为0
  • $<CONFIG:cfg>:如果存在<cfg>配置,结果1,否则结果为0,<cfg>名称不区分大小写
  • $<PLATFORM_ID:comp>: 如果平台的cmke-id 与comp匹配,结果为1,否则结果为0
  • $<C_COMPILER_ID:comp>: 如果C编译器的cmake id与comp匹配,结果为1,否则结果为0
  • $<CXX_COMPILER_ID:comp>:如果C++编译器的cmake id与comp匹配,结果为1,否则结果为0
  • $<VERSION_LESS:v1,v2>: 如果v1 版本小于V2 结果为1,否则结果为0
  • $<VERSION_GERTER:v1,v2>: 如果v1版本大于v2结果为1,否则结果为0
  • $<VERSION_EQUAL:v1,v2> 如果v1和v2相等,结果为1,否则结果为0
  • $<VERSION_LESS_EQUAL:v1,v2>:如果v1 版本小于或等于V2 结果为1,否则结果为
  • $<VERSION_GERTER_EQUA:v1,v2>: 如果v1版本大于或等于v2结果为1,否则结果为0
  • $<C_COMPILER_VERSION:ver>: 如果c编译器版本与ver相等,结果为1,否则结果为0
  • $<CXX_COMPILER_VERSION:ver>: 如果c++编译器版本与ver相等,结果为1,否则结果为0
  • $<TARGET_POLICY:pol>: 当创建head targe时,如果pol是一个新的策略,结果为1,否则结果为0
  • $<COMPILE_FEATURES:feature[,feature]...>:如果 列表中所有featured都有用到,结果为1,否则结果为0
  • $<COMPILE_LANGUAGE:lang> 如果编译器与lang匹配结果为1,否则结果为0,该表达式还可以对特定编译器设定特定编译选项:
add_executable(myapp main.cpp foo.c bar.cpp zot.cu)
target_compile_options(myapp
  PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
)
target_compile_definitions(myapp
  PRIVATE $<$<COMPILE_LANGUAGE:CXX>:COMPILING_CXX>
          $<$<COMPILE_LANGUAGE:CUDA>:COMPILING_CUDA>
)
target_include_directories(myapp
  PRIVATE $<$<COMPILE_LANGUAGE:CXX>:/opt/foo/cxx_headers>
)

 用例

下面以一个简单用例说明:

cmake_minimum_required(VERSION 3.13.4)

project(cmake_read)

#message("--------Proj Src Dir: " ${PROJECT_SOURCE_DIR})
set(TEST_CONTENT "hello world")
file(GENERATE OUTPUT ${PROJECT_SOURCE_DIR}/test_2.cpp CONTENT ${TEST_CONTENT} CONDITION $<BOOL:0>)
#message("--------TEST_CONTENT: " ${TEST_CONTENT})

 上述file GENERATE表达式中bool结果为0,不将内容输出到GENERATE中。

Filesystem

file GLOB命令

file GLOB命令主要用于匹配规则在指定的目录内匹配到所需要的文件,命令行格式:

file(GLOB <variable> [LIST_DIRECTORIES true[false] [RELATIVE <path> ] [CONFIGURE_DEPENDS] [<globbing-expression> ...])

  •  LIST_DIRECTORIES true[false]: 如果为false,目录将会被省略,默认情况下返回是带目录
  • RELATIVE <path>: 相对路径<path> 返回的结果将不是绝对路径,而是将绝对路径中的<path>部分去掉,返回相对路径
  • CONFIGURE_DEPENDS:如果该标记位设置,在主构建系统检查目标添加逻辑,必便在构建时重新运行标记的GLOB命令
  • <globbing-expression>:匹配表达式,表达式类似与正则匹配,如下:
*.cxx      - match all files with extension cxx
*.vt?      - match all files with extension vta,...,vtz
f[3-5].txt - match files f3.txt, f4.txt, f5.txt

用例

cmake_minimum_required(VERSION 3.13.4)

project(cmake_filesystem)

message("--------Proj Src Dir: " ${CMAKE_CURRENT_SOURCE_DIR})

file(GLOB TEST_RESULT LIST_DIRECT true RELATIVE /public/home *.cpp)
message("--------TEST_RESULT:  ${TEST_RESULT}")

寻找当前路径下的cpp文件,且返回的结果中为/public/home的相对路径,结果:

$  /public/home/huozhikun/cmake/cmake-3.17.0/bin/cmake ..
... ...
--------Proj Src Dir: /public/home/huozhikun/test/cmake/filesystem/example_3
--------TEST_RESULT:  huozhikun/test/cmake/filesystem/example_3/test_2.cpp
... ...

 file GLOB_RECURSE命令

GLOB_RECURSE命令不仅可以遍历当前路径,还可以遍历路径下面的所有子目录,命令行格式如下:

file(GLOB_RECURSE <variable> [LIST_DIRECTORIES true[false] [RELATIVE <path> ] [CONFIGURE_DEPENDS] [<globbing-expression> ...])

参数同上。 

file RENAME命令

RENAME命令将文件重新命名:

file(RENAME <oldname> <newname>)

将旧文件<oldname>重新命名为新名称newname.

 用例

cmake_minimum_required(VERSION 3.13.4)

project(cmake_filesystem)

file(RENAME test_2.cpp test.cpp)

file  RENAME命令

RENAME命令删除文件:

file(RENAME_RECURES [<files> ...])

file RENAME_RECURSE命令

RENAME_RECURSE 命令不仅可以删除文件还可以删除目录,当目录里面没有包含该文件也会被删除:

file(RENAME_RECURES [<files> ...])

file MAKE_DIRECTORY命令

 MAKE_DIRECTORY创建目录命令:

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

 file COPY命令

file COPY命令用于将文件copy到目标目录中,命令行格式如下:

file(COPY <files> ... DESTINATION <dir>

         [FILE_PERMISSIONS <permissions> ...] 

         [DIRECTORY_PERMISSIONS <permissions> ... ]

         [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]

         [FILES_MATCHING]

         [ [PATTERN <pattern> | REGEX <regex>]

           [EXCLUDE] [PERMISSIONS <permissions> ... ] ]

         [...])

  •  <files>:要拷贝的源文件
  • DESTINATION <dir>: 要将源文件拷贝到目的目录<dir>中
  • FILE_PERMISSIONS <permissions>: 修改源文件权限
  • DIRECTORY_PERMISSIONS <permissions>: 目录权限
  • NO_SOURCE_PERMISSIONS:不使用源文件权限,对文件权限重新指定
  • USE_SOURCE_PERMISSIONS:使用源文件权限,当该选项设置时,不能再使用FILE_PERMISSIONS权限,支持的权限设置有:
  • OWNER_READ

  • OWNER_WRITE

  • OWNER_EXECUTE

  • GROUP_READ

  • GROUP_WRITE

  • GROUP_EXECUTE

  • WORLD_READ

  • WORLD_WRITE

  • WORLD_EXECUTE

  • PATTERN 和REGEX:制定一些匹配规则
  • EXCLUDE: 不包括或排除调一些特殊文件

file INSTALL命令

file INSTALL命令功能与COPY功能类似,与copy功能不同的时 会打印出详细信息,且权限默认时NO_SOURCE_PERMISSION,命令行格式如下:

file(COPY <files> ... DESTINATION <dir>

         [FILE_PERMISSIONS <permissions> ...] 

         [DIRECTORY_PERMISSIONS <permissions> ... ]

         [NO_SOURCE_PERMISSIONS] [USE_SOURCE_PERMISSIONS]

         [FILES_MATCHING]

         [ [PATTERN <pattern> | REGEX <regex>]

           [EXCLUDE] [PERMISSIONS <permissions> ... ] ]

         [...])

COPY和INSTALL用例

COPY和INSTALL 用例如下:

cmake_minimum_required(VERSION 3.13.4)

project(cmake_filesystem)

file(COPY test_2.cpp DESTINATION copy)
file(INSTALL test_2.cpp DESTINATION install)

运行结果结果如下:

$  /public/home/huozhikun/cmake/cmake-3.17.0/bin/cmake ..
... ... 
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Installing: /public/home/huozhikun/test/cmake/filesystem/example_5/build/install/test_2.cpp
-- Configuring done
-- Generating done
... ...

INSTALL命令 有详细输出,分布在copy和install目录有一份test_2.cpp文件。

 路径转换(path conversion)

file  RELATIVE_PATH

file RELATIVE_PATH根据制定的路径和文件推断出其相对路径,命令行格式:

file(RELATIVE_PATH <variable> <directory> <file>

根据指定的<file>文件 推断出该文件相对于<directory>目录的相对路径,并保存到<variable>变量中,其中<file>要带绝对路径。

file TO_CMAKE_PATH

将制定的路径转换成cmake style形式,命令行格式:

file(TO_CMAKE_PATH "<path>" <variable> 

将传入的<path>路径统一转换成cmake目录形式,cmkae目录形式为“/",该命令主要是考虑到不同操作系统平台使用目标分隔符表示方法不一样,如window下为”\"进行区分,使用该命令可以解决不同系统平台目录兼容问题。

用例

cmake_minimum_required(VERSION 3.13.4)

project(cmake_filesystem)


message("--------Proj Src Dir: " ${CMAKE_CURRENT_SOURCE_DIR})
file(TO_CMAKE_PATH "/public/home/test" TEST_RESULT)
message("-----TEST_RESULT:${TEST_RESULT}")
~                                         

 file TO_NATIVE_PATH

方向是相反的,将cmake格式的目录表示方法转换成具体使用的操作系统表示的方法,winods使用“\”表示,其他都是使用“\",命令行格式如下:

file(TO_NATIVE_PATH "<path>" <variable>

传送相关命令(transfer)

传送相关命令如下:

file(DOWNLOAD <url> <file> [<option> ...]

file(UPLOAD <file> <url> [<option> ...]) 

DOWNLOAD用于从指定的<url>中下载指定的<file>文件。

UPLOAD用于向指定的<url>上传<file>文件。

支持的<option>选项如下:

  • INACTIVITY_TIMEOUT <seconds>: 如果在指定的<seconds>时间内 没有响应 旧中断
  • LOG <variable>:将执行的log保存到<variable>变量中
  • SHOW_PROGRESS: 将进度信息打印出来,直到操作完成
  • STATUS <variable>: 将执行结果保存到<variable>变量中,其中是以分隔符":"表示的两个列表,第一个为数字表示的是返回值,第二个是一个字符串,返回的是错误信息字符串。如果返回值为0,表示没有erro信息。
  • TIMEOUT <seconds>:执行的超算时间
  • USERPWD <usrname>:<password>: 设置用户名和密码
  • HTTPHEADER <HTTP-header>: http 头
  • NETRC <level>: 是否指定.netrc文件用于操作,如果不指定默认为使用CMAKE_NETRC变量,<level>级别分别为IGNORED、OPTIONAL、REQUTRED。
  • NETRC <file> 指定.netrc文件。如果不指定NETRC,则默认会检查CMAKE_NETRC和CMAKE_NETRC_FILE变量

 锁

通过LOCK指令对指定的文件进行上锁,指令格式为:

file(LOCK <path> [DIRECTORY] [RELEASE] [GUARD <FUNCTION|FILE|PROCESS>] [RESULT_VARIABLE <variable>] [TIMEOUT <second>])

  • 如果DIRECTORY没有指定,则会在锁定的文件路径《path> 生成一个<path>/cmake.lock.
  • 可以通过GUARD 指定锁定的范围scope.
  • RELEASE选项用于显示解锁
  • 如果TIMEOUT没有指定,cmake会一直等待直到锁定文件成功或者返回一个致命错误。如果TIMEOUT指定,则只会在指定的时间段内尝试锁文件 

参考资料

https://cmake.org/cmake/help/v3.12/manual/cmake-generator-expressions.7.html#manual:cmake-generator-expressions(7)

file — CMake 3.12.4 Documentation

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐