我们经常会遇到将第三方库文件复制到项目运行时文件夹,或者将子项目生成的库文件复制到项目运行时文件夹的情况,本文介绍FILE-COPY、add_custom_command、ADD_CUSTOM_TARGET三种方法及CMake COMMAND提供的命令说明。

一、    FILE-COPY

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

COPY将文件,目录和符号链接复制到目标文件夹。相对于当前源目录评估相对输入路径,相对于当前构建目录评估相对目的地。复制会保留输入文件的时间戳,并优化文件(如果该文件存在于具有相同时间戳的目标文件中)。复制将保留输入权限,除非给出明确的权限或NO_SOURCE_PERMISSIONS(默认为USE_SOURCE_PERMISSIONS)。

如果指定了FOLLOW_SYMLINK_CHAIN,则COPY将在给定的路径上递归解析符号链接,直到找到真实文件为止,然后在目标位置为遇到的每个符号链接安装相应的符号链接。对于已安装的每个符号链接,解析都会从目录中剥离,仅保留文件名,这意味着新符号链接指向与符号链接相同目录中的文件。此功能在某些Unix系统上很有用,在这些系统中,库是作为带有符号链接的版本号安装的,而较少特定的版本指向的是特定版本。FOLLOW_SYMLINK_CHAIN会将所有这些符号链接和库本身安装到目标目录中。例如,如果您具有以下目录结构:

  • /opt/foo/lib/libfoo.so.1.2.3
  • /opt/foo/lib/libfoo.so.1.2 -> libfoo.so.1.2.3
  • /opt/foo/lib/libfoo.so.1 -> libfoo.so.1.2
  • /opt/foo/lib/libfoo.so -> libfoo.so.1

你可以:

file(COPY /opt/foo/lib/libfoo.so DESTINATION lib FOLLOW_SYMLINK_CHAIN)

这会将所有符号链接和libfoo.so.1.2.3本身安装到lib中。

请参阅install(DIRECTORY)命令以获取权限,FILES_MATCHING,PATTERN,REGEX和EXCLUDE选项的文档。即使使用选项来选择文件的子集,复制目录也会保留其内容的结构。

INSTALL与COPY略有不同:它打印状态消息(取决于CMAKE_INSTALL_MESSAGE变量),并且默认为NO_SOURCE_PERMISSIONS。 install()命令生成的安装脚本使用此签名(以及一些未记录的内部使用选项)。

二、    ADD_CUSTOM_COMMAND

add_custom_command:

该命令可以为生成的构建系统添加一条自定义的构建规则。这里又包含两种使用方式,一种是通过自定义命令在构建中生成输出文件,另外一种是向构建目标添加自定义命令。命令格式分别为:

(1)生成文件

add_custom_command(OUTPUT output1 [output2 ...]
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[MAIN_DEPENDENCY depend]
[DEPENDS [depends...]]
[BYPRODUCTS [files...]]
[IMPLICIT_DEPENDS <lang1> depend1
[<lang2> depend2] ...]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[DEPFILE depfile]
[JOB_POOL job_pool]
[VERBATIM] [APPEND] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS])

参数介绍:

OUTPUT:

指定命令预期产生的输出文件。如果输出文件的名称是相对路径,即相对于当前的构建的源目录路径。输出文件可以指定多个output1,output2(可选)等。

COMMAND:

指定要在构建时执行的命令行。如果指定多个COMMAND,它们讲按顺心执行。ARGS参数是为了向后兼容,为可选参数。args1和args2为参数,多个参数用空格隔开。

MAIN_DEPENDENCY:

可选命令,指定命令的主要输入源文件。

DEPENDS:

指定命令所依赖的文件。

BYPRODUCTS:

可选命令,指定命令预期产生的文件,但其修改时间可能会比依赖性更新,也可能不会更新。

IMPLICIT_DEPENDS:

可选命令,请求扫描输入文件的隐式依赖关系。给定的语言指定应使用相应的依赖性扫描器的编程语言。目前只支持C和CXX语言扫描器。必须为IMPLICIT_DEPENDS列表中的每个文件指定语言。从扫描中发现的依赖关系在构建时添加到自定义命令的依赖关系。请注意,IMPLICIT_DEPENDS选项目前仅支持Makefile生成器,并且将被其他生成器忽略。

WORKING_DIRECTORY:

可选命令,使用给定的当前工作目录执行命令。如果它是相对路径,它将相对于对应于当前源目录的构建树目录。

COMMENT:

可选命令,在构建时执行命令之前显示给定消息。

DEPFILE:

可选命令,为Ninja生成器指定一个.d depfile。 .d文件保存通常由自定义命令本身发出的依赖关系。对其他生成器使用DEPFILE是一个错误。

COMMAND_EXPAND_LISTS:

将扩展COMMAND参数中的列表,包括使用生成器表达式创建的列表,从而允许COMMAND参数,例如${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc为适当扩展。

VERBATIM:

对于构建工具,将正确转义命令的所有自变量,以便调用的命令不变地接收每个自变量。 请注意,在add_custom_command甚至没有看到参数之前,CMake语言处理器仍使用一种转义。 建议使用VERBATIM,因为它可以使行为正确。 如果未提供VERBATIM,则该行为是特定于平台的,因为没有针对工具的特殊字符的保护。

使用实例:

add_executable(MakeTable MakeTable.cxx)
add_custom_command (
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
DEPENDS MakeTable
COMMENT "This is a test"
)

(2)自定义构建事件

add_custom_command(TARGET <target>
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND command1 [ARGS] [args1...]
[COMMAND command2 [ARGS] [args2...] ...]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[VERBATIM] [USES_TERMINAL])

参数介绍:

TARGET:

定义了与构建指定相关联的新命令。当已经存在是,相应的command将不再执行。

PRE_BUILD:

在目标中执行任何其他规则之前运行。这仅在Visual Studio 7或更高版本上受支持。对于所有其他生成器PRE_BUILD将被视为PRE_LINK。

PRE_LINK:

在编译源之后运行,但在链接二进制文件或运行静态库的库管理器或存档器工具之前运行。

POST_BUILD:

在目标中的所有其他规则都已执行后运行。

示例:将子项目生成的库文件复制到项目运行时文件夹。

#=============Copy Plugins Runtime FILES to Main Project============
#一般将此内容放在lib子项目的CMakelists.txt的最后,该方法采用POST_BUILD,所以需注意要复制的源应该是一个固定字符串,而不能用FILE GLOB的方法,因为在编译前该源为空,在VS中会出现MSB3073错误,提示copy from 为空值。
SET(Plugins_TEST_Debug_DLL_FILE
${CMAKE_CURRENT_BINARY_DIR}/Debug/lib${PROJECT_NAME}.dll
)
SET(Plugins_TEST_Release_DLL_FILE
${CMAKE_CURRENT_BINARY_DIR}/Release/lib${PROJECT_NAME}.dll
) add_custom_command(TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E
copy_if_different
"$<$<CONFIG:Release>:${Plugins_TEST_Release_DLL_FILE}>"
"$<$<CONFIG:Debug>:${Plugins_TEST_Debug_DLL_FILE}>"
"${CMAKE_BINARY_DIR}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/Plugins/org_test_plugins/"
)

三、    ADD_CUSTOM_TARGET

add_custom_target:

该命令可以给指定名称的目标执行指定的命令,该目标没有输出文件,并始终被构建。命令的格式为:

add_custom_target(Name [ALL] [command1 [args1...]]
[COMMAND command2 [args2...] ...]
[DEPENDS depend depend depend ... ]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[JOB_POOL job_pool]
[VERBATIM] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[SOURCES src1 [src2...]])

参数介绍:

Name:

指定目标的名称,单独成为一个子项目。

ALL:

表明此目标应添加到默认构建目标,以便每次都将运行(该命令名称不能为ALL)

SOURCES:

指定要包括在自定义目标中的其他源文件。指定的源文件将被添加到IDE项目文件中,以方便编辑,即使它们没有构建规则。

示例:将第三方库文件复制到项目运行时文件夹

#=============Copy Source files to Build Runtime Dir===============
#该内容一般放在项目顶层CMakelists.txt的最后,
#目的是将项目生成后的执行文件所需的第三方库复制到执行程序目录,
#并区分Debug和Release版本。
#该方法中的COMMAND_EXPAND_LISTS参数值得关注,可以复制列表内所有文件。
FILE(GLOB Plugin_Runtime_Debug_DLL_FILES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/Plugin_Runtime_Dir/Debug/*.*
)
FILE(GLOB Plugin_Runtime_Release_DLL_FILES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/Plugin_Runtime_Dir/Release/*.*
)
FILE(GLOB Plugin_Runtime_Debug_Resources_FILES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/Plugin_Runtime_Dir/Debug/Resources/icos/*.*
)
FILE(GLOB Plugin_Runtime_Release_Resources_FILES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/Plugin_Runtime_Dir/Release/Resources/icos/*.*
) add_custom_target(CopyRuntimeFiles ALL
VERBATIM
COMMAND_EXPAND_LISTS
COMMAND ${CMAKE_COMMAND} -E
make_directory "${PROJECT_BINARY_DIR}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/"
COMMAND ${CMAKE_COMMAND} -E
copy_if_different
"$<$<CONFIG:Release>:${Plugin_Runtime_Release_DLL_FILES}>"
"$<$<CONFIG:Debug>:${Plugin_Runtime_Debug_DLL_FILES}>"
"${PROJECT_BINARY_DIR}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/"
COMMAND ${CMAKE_COMMAND} -E
make_directory "${PROJECT_BINARY_DIR}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/Resources/icos/"
COMMAND ${CMAKE_COMMAND} -E
copy_if_different
"$<$<CONFIG:Release>:${Plugin_Runtime_Release_Resources_FILES}>"
"$<$<CONFIG:Debug>:${Plugin_Runtime_Debug_Resources_FILES}>"
"${PROJECT_BINARY_DIR}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/Resources/icos/"
COMMAND ${CMAKE_COMMAND} -E
make_directory "${PROJECT_BINARY_DIR}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/Plugins/org_test_plugins/"
)

四、    COMMAND

cmake version 3.15.2
Usage: <command> [arguments...]
Available commands:
capabilities - Report capabilities built into cmake in JSON format
chdir dir cmd [args...] - run command in a given directory
compare_files [--ignore-eol] file1 file2 - check if file1 is same as file2
copy <file>... destination - copy files to destination (either file or directory)
copy_directory <dir>... destination - copy content of <dir>... directories to 'destination' directory
copy_if_different <file>... destination - copy files if it has changed
echo [<string>...] - displays arguments as text
echo_append [<string>...] - displays arguments as text but no new line
env [--unset=NAME]... [NAME=VALUE]... COMMAND [ARG]...
- run command in a modified environment
environment - display the current environment
make_directory <dir>... - create parent and <dir> directories
md5sum <file>... - create MD5 checksum of files
sha1sum <file>... - create SHA1 checksum of files
sha224sum <file>... - create SHA224 checksum of files
sha256sum <file>... - create SHA256 checksum of files
sha384sum <file>... - create SHA384 checksum of files
sha512sum <file>... - create SHA512 checksum of files
remove [-f] <file>... - remove the file(s), use -f to force it
remove_directory <dir>... - remove directories and their contents
rename oldname newname - rename a file or directory (on one volume)
server - start cmake in server mode
sleep <number>... - sleep for given number of seconds
tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...] - create or extract a tar or zip archive
time command [args...] - run command and display elapsed time
touch <file>... - touch a <file>.
touch_nocreate <file>... - touch a <file> but do not create it.
create_symlink old new - create a symbolic link new -> old
Available on Windows only:
delete_regv key - delete registry value
env_vs8_wince sdkname - displays a batch file which sets the environment for the provided Windows CE SDK installed in VS2005
env_vs9_wince sdkname - displays a batch file which sets the environment for the provided Windows CE SDK installed in VS2008
write_regv key value - write registry value

++++++++++++++++++++++++

参考:

https://cmake.org/cmake/help/latest/genindex.html

https://yemi.me/2017/10/04/cmake-notes/

https://www.cnblogs.com/alphagl/p/6280061.html

https://stackoverflow.com/questions/14368919/cmake-custom-command-copy-multiple-files/54446162#54446162

CMake 复制文件方法的更多相关文章

  1. java最简单复制文件方法,不依赖任何框架

    java最简单复制文件方法   把java2.txt内容复制到java.txt中 import java.io.File; import java.io.IOException; import jav ...

  2. ADB工具 获取ROOT权限及复制文件方法

    adb push d:\tm3_sqlit.db data/zouhao/tm3_sqlit.dbadb pull data/zouhao/tm3_sqlit.db d:\tm3_sqlit.db a ...

  3. 用Python复制文件的9个方法

    Python 中有许多"开盖即食"的模块(比如 os,subprocess 和 shutil)以支持文件 I/O 操作.在这篇文章中,你将会看到一些用 Python 实现文件复制的 ...

  4. 用Python复制文件的9个方法(转)

    转自:https://zhuanlan.zhihu.com/p/35725217 用Python复制文件的9个方法 Python 中有许多“开盖即食”的模块(比如 os,subprocess 和 sh ...

  5. Java 复制文件的高效方法

    转载自:http://jingyan.baidu.com/article/ff4116259c2d7712e4823780.html 在Java编程中,复制文件的方法有很多,而且经常要用到.我以前一直 ...

  6. 安装程序无法复制文件 convlog.exe的解决方法

    在安装的时候出现一个错误提示“安装程序无法复制文件CONVLOG.EX_”,上网找了很多资料,都说是因为版本问题,考虑到自己的服务器安装的是2003 SP1,后来打了补丁到SP2的,也就认为是版本问题 ...

  7. php不使用copy()函数复制文件的方法

    本文实例讲述了php不使用copy()函数复制文件的方法.分享给大家供大家参考.具体如下:下面的代码不使用php内置的copy函数,直接通过文件读取写入的操作方式复制文件 <?php funct ...

  8. Delphi的移动文件方法(转)/删除文件:/文件的复制

    RenameFile,DeleteFile,MoveFile Delphi的移动文件方法 uses  ShellApi; procedure ShellFileOperation(fromFile: ...

  9. linux使用su切换用户提示 Authentication failure的解决方法& 复制文件时,报cp: omitting directory `XXX'

    linux使用su切换用户提示 Authentication failure的解决方法:这个问题产生的原因是由于ubtun系统默认是没有激活root用户的,需要我们手工进行操作,在命令行界面下,或者在 ...

随机推荐

  1. golang学习笔记(二):流程控制

    欢迎访问我的博客和github! 今天咱们把烦人的事情丢一丢,继续来学习go的基础知识. 这篇文章记录go语言的流程控制和更多类型. 流程控制 for Go 只有一种循环结构:for 循环. 基本的 ...

  2. Goland2019.3.2永久破解

    2019.11.28 jetbrains公司发布了Go的最强编辑器GoLand 2019.3.本次更新软件消耗更少的CPU和更快的性能,增强了对Go Modules的支持,添加了一组新的快速修复程序, ...

  3. POJ_2342_树状dp

    http://poj.org/problem?id=2342 第一道树状dp,入门题,用vector构建有向图. #include<iostream> #include<cstrin ...

  4. Codeforces_512_B

    http://codeforces.com/problemset/problem/512/B dp题,因为状态很多,所以用map保存,注意代码中的那个二层循环不能内外换,因为map会自动排序. #in ...

  5. Why Oracle VIP can not be switched to original node ?

    Oracle RAC is an share everything database architecture. The article is how to check out why virtual ...

  6. The Divide and Conquer Approach - 归并排序

    The divide and conquer approach - 归并排序 归并排序所应用的理论思想叫做分治法. 分治法的思想是: 将问题分解为若干个规模较小,并且类似于原问题的子问题, 然后递归( ...

  7. 07-SpringMVC01

    今日知识 1. SpringMVC入门 2. SpringMVC的注解开发 SpringMVC入门 1. 简介: * Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,S ...

  8. 08-JavaScript基础

    今日知识 1. JavaScript基础 2. 案例 3.总结 JavaScript介绍: * 概念:一门客户端脚本语言 * 运行在客户端浏览器中的,每一个浏览器都有JavaScript的解析引擎 * ...

  9. JS水仙花数

    题目:3位数==个位立方+十位的立方+百位的立方.这个3位数就是水仙花数.要求打印出所有的水仙花数 <body> <div id=d1> </div> <sc ...

  10. 最新版的EF Core对UWP支持的怎么样

    为啥写这篇帖子呢?其实是因为翻微软的文档中心偶然翻到的,于是就出于好奇就试试了,看看用着怎么样. 以前没注意图片,所以我今天发现的时候,显示EF Core3.1支持standard2.0,于是就想试试 ...