如何通过cmake自动拷贝运行所需dll到executable目录

给你的library定义一个带"IMPORTED" 属性的target,同时需要并为此定义lib和dll路径属性,需要区分debug和release。

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的名字即可,这样会自动隐藏背后的不同版本的lib库文件。

target_link_libraries(YourProg sdl2 ...)

在CMakeLists.txt定义一个定制的build step来自动拷贝运行所需的dll文件:

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

通常,当你的项目集成了很多第三方库,以上这么干会把CMakeLists.txt搞得很复杂,因此推荐得方式还是得写FindXXX.cmake, 并在FindXXX.cmake里创建对应的target,关于如何写可以参考这篇文章

有些第三方库提供已编译好的库文件且是多个,这时候上面的target不再能拷贝dll,而且会报错unknwon target,对于这种第三方库的target得如下定义:

add_library(ffmpeg INTERFACE IMPORTED)
set_target_properties(ffmpeg PROPERTIES 
        INTERFACE_INCLUDE_DIRECTORIES "${ffmpeg_INCLUDE_DIRS}"
        INTERFACE_LINK_LIBRARIES "${ffmpeg_LIBRARIES}"
        IMPORTED_LOCATION "${ffmpeg_LIBRARY_DLLS}")

拷贝DLL文件的command得改成如下方式:

get_target_property(DLLS ffmpeg IMPORTED_LOCATION)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${DLLS} $<TARGET_FILE_DIR:${PROJECT_NAME}>)

${DLLS} 即对应所有dll文件路径总和。

其实,Qt打包时候拷贝DLL也是同样这个做法:

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different