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

时间:2012-05-20 08:24:11

标签: dll cmake

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

如何更改CMakeLists.txt以使生成的Visual Studio项目在发布/调试文件夹中已经包含特定的DLL文件,或者在编译时将其复制?

10 个答案:

答案 0 :(得分:107)

我会使用add_custom_commandcmake -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>)


如果您需要根据配置(Release,Debug等)复制不同的dll,那么您可以在具有相应配置命名的子目录中使用这些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>)

答案 1 :(得分:17)

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

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

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

答案 2 :(得分: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>
)

答案 3 :(得分:5)

接受答案的附录,作为单独的答案添加,以便我获得代码格式:

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

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

代码来源和

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

目的地。注意逃避!

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

答案 4 :(得分: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)

答案 5 :(得分:1)

您可能需要add custom target并使其依赖于您的某个可执行目标。要使用上述功能复制文件,请使用

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

答案 6 :(得分: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。

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

答案 7 :(得分:0)

在构建期间使用install

移动文件

在尝试遵循Step 9上的CMake官方教程时遇到了这个问题。这是我要移动的文件的位置:

src
 |_build
    |_Debug
       - `MathFunctions.dll`

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

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

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

src/Mathfunctions/CMakeLists.txt

感谢您的回答,我可以考虑一下。只是一行而已,所以我认为还可以。根据项目的构建方式,install(FILES ${PROJECT_BINARY_DIR}/$<CONFIG>/MathFunctions.dll DESTINATION bin) 可以具有两个值 Debug Release ,作为原始问题。

答案 8 :(得分:0)

当前评分最高的答案中的以下命令取决于放入 /libs/ 中的输出。

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

我使用以下命令进行复制,这对我在任何地方都适用。请注意,我在这里只复制了输出 dll,而不是整个目录。另请注意,我正在硬编码一个特定于该项目的目标 /bin/ 目录。但我想分享 $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}> 语法,我认为它很简洁:

add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<TARGET_FILE_DIR:${CMAKE_PROJECT_NAME}>/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>
        ${CMAKE_CURRENT_SOURCE_DIR}/bin/$<TARGET_FILE_NAME:${CMAKE_PROJECT_NAME}>)

答案 9 :(得分:-1)

您还可以使用命令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})