如何使用CMake将DLL文件复制到与可执行文件相同的文件夹中?


98

我们使用CMake在SVN中生成源代码的Visual Studio文件。现在,我的工具要求某些DLL文件与可执行文件位于同一文件夹中。DLL文件位于源旁边的文件夹中。

如何更改我的名称CMakeLists.txt,以使生成的Visual Studio项目在release / debug文件夹中已经具有特定的DLL文件,或者在编译时将其复制?

Answers:


122

我会add_custom_command用来实现这一点cmake -E copy_if_different...。有关完整的信息运行

cmake --help-command add_custom_command
cmake -E


因此,就您而言,如果您具有以下目录结构:

/CMakeLists.txt
/src
/libs/test.dll

并且命令适用的CMake目标是MyTest,则可以将以下内容添加到CMakeLists.txt:

add_custom_command(TARGET MyTest POST_BUILD        # Adds a post-build event to MyTest
    COMMAND ${CMAKE_COMMAND} -E copy_if_different  # which executes "cmake - E copy_if_different..."
        "${PROJECT_SOURCE_DIR}/libs/test.dll"      # <--this is in-file
        $<TARGET_FILE_DIR:MyTest>)                 # <--this is out-file path


如果只想/libs/复制目录的全部内容,请使用cmake -E copy_directory

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs"
        $<TARGET_FILE_DIR:MyTest>)


如果您需要根据配置(例如发布,调试)复制不同的dll,则可以将它们放在以相应配置命名的子目录中:/libs/Release/libs/Debug。然后,您需要将配置类型注入到add_custom_command调用中dll的路径中,如下所示:

add_custom_command(TARGET MyTest POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_directory
        "${PROJECT_SOURCE_DIR}/libs/$<CONFIGURATION>"
        $<TARGET_FILE_DIR:MyTest>)

3
对于在将来对其他人有帮助的情况,对我的情况起作用的简要说明:我有一个静态库项目,主要可执行文件可以有针对性地链接到该库,并且如果添加该库,则需要复制DLL。因此,在该库的CMakeLists.txt文件中,我将其用作${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>目标位置。否则它将复制到库构建路径,这是没有用的。
AberrantWolf

cmake install()指令的目标不是汇编二进制文件吗?还是cmake LIBRARY东西?我真的不知道工具链。
桑德堡

1
$<TARGET_FILE_DIR:MyTest>- 它是什么?如何打印信息,这是什么意思
ilw

除非在集成命令时错过任何内容,否则此方法不适用于添加了的库IMPORTED_LIBRARIES。它抱怨说什么也没建好就不能运行后建命令。
Tzalumen

2
经过测试并提出建议后:如果您正在使用IMPORTED库,并且需要重新定位DLL,则需要使用一个变体命令。如果您已经添加了使用IMPORTED库,MyImportedLibCOMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:MyImportedLib> $<TARGET_FILE_DIR:MyTest>注意,要运行多个后期构建命令,您需要将它们全部绑定到一个自定义命令中,例如add_custom_command(TARGET MyTest POST_BUILD COMMAND #your first command# COMMAND #Your second command#)
Tzalumen

24

我将这些行放在我的顶级CMakeLists.txt文件中。CMake编译的所有库和可执行文件都将放置在build目录的顶层,以便可执行文件可以找到这些库,并且很容易运行所有内容。

set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})

请注意,这不能解决OP从项目源目录复制预编译二进制文件的问题。


7

今天,当我尝试制作程序的Windows版本时遇到了这个问题。我最终自己做了一些研究,因为所有这些答案都使我不满意。存在三个主要问题:

  • 我希望调试版本与库的调试版本链接,发行版本与库的发行版本链接。

  • 除此之外,我希望将正确版本的DLL文件(调试/发布)复制到输出目录。

  • 我想在不编写复杂而脆弱的脚本的情况下实现所有这些目标。

在github上浏览了一些CMake手册和一些多平台项目之后,我找到了这个解决方案:

使用“导入”属性将您的库声明为目标,引用其调试并释放.lib和.dll文件。

add_library(sdl2 SHARED IMPORTED GLOBAL)
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_RELEASE "${SDL_ROOT_PATH}/lib/SDL2.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_RELEASE "${SDL_ROOT_PATH}/bin/SDL2.dll")
set_property(TARGET sdl2 PROPERTY IMPORTED_IMPLIB_DEBUG "${SDL_ROOT_PATH}/lib/SDL2d.lib")
set_property(TARGET sdl2 PROPERTY IMPORTED_LOCATION_DEBUG "${SDL_ROOT_PATH}/bin/SDL2d.dll")

照常将此目标与您的项目链接

target_link_libraries(YourProg sdl2 ...)

如果自上次构建以来已对其进行了更改,请进行自定义构建步骤以将dll文件复制到其目标位置

add_custom_command ( TARGET YourProg POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
    $<TARGET_FILE:sdl2> $<TARGET_FILE_DIR:YourProg>
)

5

接受的答案的附录,作为单独的答案添加,因此我得到了代码格式:

如果要在同一项目中构建dll,则它们通常位于Release,Debug等目录中。您必须使用Visual Studio环境变量来正确地复制它们。例如:

"${PROJECT_BINARY_DIR}/your_library/\$\(Configuration\)/your_library.dll"

对于源和

"${CMAKE_CURRENT_BINARY_DIR}/\$\(Configuration\)/your_library.dll"

为目的地。注意转义!

您不能将CMake CMAKE_BUILD_TYPE变量用于配置,因为它是在VS项目生成时解析的,并且始终是默认值。


8
接受答案的最后一部分,在清洁CMake的使用方式解决了这个$<CONFIGURATION>
查Claunch

4

您还可以使用命令find_library:

find_library(<some_var> NAMES <name_of_lib> PATHS "<path/to/lib>")

例如,使用已定义的EXECUTABLE_PATH:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)

您可以移动可执行文件所需的.dll文件,

file(COPY ${<some_var>}
    DESTINATION ${EXECUTABLE_OUTPUT_PATH})

2

这对其中一个有用

SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
    ${PROJECT_SOURCE_DIR}/lib CACHE
    PATH "Directory where all the .lib files are dumped." FORCE)
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY
    ${PROJECT_SOURCE_DIR}/bin CACHE
    PATH "Directory where .exe and .dll files are dumped." FORCE)

1

您可能需要添加自定义目标,并使它依赖于您的可执行目标之一。

要使用上述功能复制文件,请使用:

COMMAND ${CMAKE_PROGRAM} -E copy_if_different ${CMAKE_BINARY_DIR}/path/to/file.dll ${CMAKE_BINARY_DIR}/where/to/put/file.dll`

0

我是CMake的初学者,但我仍然想分享自己的经验。就我而言,我需要安装后的副本,以便所有二进制文件都可以放入。对于可以在CMake中导入的第三方二进制文件,以下对我有用:

find_package( dependency REQUIRED )
if( MSVC ) 
    # If done properly and if the dependency has a correct config file, IMPORTED_LOCATION_RELEASE should be defined
    get_target_property( DEP_SHARED_LIB_PATH dependency IMPORTED_LOCATION_RELEASE )
    # Create a bin directory in the install folder
    add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory  ${CMAKE_INSTALL_PREFIX}/bin/)
    # Copy the shared lib file
    add_custom_command(TARGET BGS POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${DEP_SHARED_LIB_PATH} ${CMAKE_INSTALL_PREFIX}/bin/)
endif()

显然,IMPORTED_LOCATION_RELEASE可以具有变体,具体取决于构建/安装共享库的方式。可能是IMPORTED_LOCATION_DEBUG。

我不知道,也许有一种更好的方法来获取该属性名称。


0

在构建过程中使用 install

我在尝试按照步骤9的CMake官方教程进行操作时遇到了这个问题。这是我要移动的文件的位置:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

这是我希望文件所在的位置:

src
 |_build
    |_install
         |_bin
             - `MathFunctions.dll`

由于此DLL是作为共享库生成的,所以我要做的就是将此行包含在包含该库源代码CMakeLists.txt子目录src/Mathfunctions/CMakeLists.txt

install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll
DESTINATION bin)

感谢您的回答,我可以考虑这一点。只是一行而已,所以我认为还可以。将$<CONFIG>有两个值调试发布根据项目是如何建成的要求,原来的问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.