我们使用 CMake 在 SVN 中生成源代码的 Visual Studio 文件。现在我的工具需要一些 DLL 文件与可执行文件位于同一文件夹中。DLL 文件位于旁边的文件夹中...
我们使用 CMake 在 SVN 中生成源代码的 Visual Studio 文件。现在我的工具需要一些 DLL 文件与可执行文件位于同一文件夹中。DLL 文件位于源代码旁边的文件夹中。
我怎样才能更改 CMakeLists.txt
以使生成的 Visual Studio 项目已经在发布/调试文件夹中拥有特定的 DLL 文件或者在编译时复制它们?
install(TARGET_RUNTIME_DLLS)
(CMake >= 3.21)
install(FILES $<TARGET_RUNTIME_DLLS:your_exe_here> TYPE BIN)
为了实现这一点,依赖项的 CMake 模块必须编写良好。换句话说,它们使用 CMake 3 目标,并且所有目标属性均已正确设置。如果它们正确设置了所有内容,则会自动收集所有 DLL 并将其与 exe 一起安装。CMake 将自动匹配哪种类型的 DLL(例如发布版还是调试版)以匹配目标 exe。
这是 CMake 未来的发展方向,如果您可以选择的话,这是您应该选择的方式。
您应该更喜欢 install()
直接将文件复制到其中, $CMAKE_RUNTIME_OUTPUT_DIRECTORY
因为 install()
is the official CMake-sanctioned way to put things in $CMAKE_RUNTIME_OUTPUT_DIRECTORY
. install()
之所以命名如此奇怪,是因为 CMake 不仅仅是一个构建工具。它也是一个安装程序生成工具。此安装程序生成功能称为 CPack。在 CMake 看来, $CMAKE_RUNTIME_OUTPUT_DIRECTORY
只是 CPack 的保存区域。 When you install()
a file, you tell CMake that it should be considered a program file, to be copied around wherever the exe goes. If you don't go through install()
, CMake will see it as a random unrecognized file.
install(RUNTIME_DEPENDENCIES)
(CMake >= 3.21)
install(TARGETS your_exe_here
RUNTIME ARCHIVE LIBRARY RUNTIME FRAMEWORK BUNDLE PUBLIC_HEADER RESOURCE)
install(TARGETS your_exe_here
COMPONENT your_exe_here
RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES "api-ms-" "ext-ms-"
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
DIRECTORIES $<TARGET_FILE_DIR:your_exe_here>)
关键在于 RUNTIME_DEPENDENCIES
.
在内部, RUNTIME_DEPENDENCIES
文件 file(GET_RUNTIME_DEPENDENCIES)
,尽力准确复制实际依赖项解析的样子,并记下在此过程中提到的所有 DLL。这些被传回到 install()
.
这意味着,这并不依赖于您的依赖项的 CMake 模块是否正确设置了其目标属性。您的实际可执行二进制文件将被扫描。所有内容都将被拾取。
file(GET_RUNTIME_DEPENDENCIES)
(CMake >= 3.16)
file(GET_RUNTIME_DEPENDENCIES)
是 install(RUNTIME_DEPENDENCIES)
底层调用的,但 file(GET_RUNTIME_DEPENDENCIES)
在较早的 CMake 版本中可用 install(RUNTIME_DEPENDENCIES)
。我们仍然可以在较旧的 CMake 版本中执行相同的操作,只是需要更多样板。
棘手的部分是 file(GET_RUNTIME_DEPENDENCIES)
只能在安装时调用。这意味着我们需要使用 install(CODE)
来运行一个脚本,该脚本反过来调用 file(GET_RUNTIME_DEPENDENCIES)
。有关实现, 请参阅此处 .
install(DIRECTORY)
install(
DIRECTORY "${DIR_CONTAINING_YOUR_DLLS}"
TYPE BIN
FILES_MATCHING REGEX "[^\\\\/.]\\.[dD][lL][lL]$"
)
要使用,请将适合您的构建的 DLL 放入 $DIR_CONTAINING_YOUR_DLLS
.
这里的技巧是,unlike install(FILES)
, install(DIRECTORY)
在安装之前并不关心目录中有哪些特定文件。这意味着现在我们拥有所有的配置时间和编译时间,可以获取 DLL 列表并将它们填充进去 $DIR_CONTAINING_YOUR_DLLS
。只要 DLL 文件 $DIR_CONTAINING_YOUR_DLLS
在安装时存在, install(DIRECTORY)
unlike 就会拾取它们。
如果您选择此方法,则您有责任将 DLL 与构建配置进行匹配。 (考虑:静态与动态、调试与发布、导入库版本与 DLL 版本、具有可选多线程的库、忘记删除不再需要的 DLL。)
如果选择此方法,则可能需要使用类似 vcpkg
applocal.ps1 的
。 (假设,应该可以 vcpkg
使用 重新实现纯 CMake 中 的功能 applocal.ps1
, install(CODE)
但我还没有准备好发布的实现。)
vcpkg
如果您使用 vpckg
启用 VCPKG_APPLOCAL_DEPS
的, vcpkg
它将为您找到并将您的 DLL 复制到您的 $CMAKE_RUNTIME_OUTPUT_DIRECTORY
目录中,但无需经过 install()
。您需要使用 install(DIRECTORY)
技巧让 CMake 拾取它们。
(在内部, vcpkg
使用 dumpbin
, llvm-objdump
和 objdump
扫描您的可执行二进制文件以获取这些文件名。)