[✔️]CMake 在Windows上copy dll

298 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情

file命令在Windows上的目录问题

file(GLOB ffmpeg_shared_libries ${FFMPEG_DEV_ROOT}/bin/*dll)
file(COPY ${ffmpeg_shared_libries} DESTINATION ${EXECUTABLE_OUTPUT_PATH})

以上的逻辑,在mac上,的确会将dll复制到对应的目录,但是在Windows上目录结构会变成这样:

  • EXECUTABLE_OUTPUT_PATH
    • Debug
    • Release
    • *.dll

在Windows上编译工程时,EXECUTABLE_OUTPUT_PATH等目录会自动在后边追加Debug/Release,当我们要copy文件时,因为这一层目录的原因,就会非常麻烦,因为cmake中是无法感知到这个目录的。

当然也可以把DESTINATION写死也能解决问题,但是file命令,无法区分debug、release,必须通过build_type设置,没办法将debug/release关联起来。

解决办法

在Windows上,通过add_custom_commandvs的宏变量巧妙解决,算是取巧:

add_custom_command(TARGET ${APP_NAME} PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${COCOS2DX_ROOT_PATH}/xxx $(outdir)

就是这个$(outdir)(有可能是其他,需要自己查找下合适的环境变量),注意是(),这个目录在vs中是一个宏变量,是指向exe的生成目录的。

再通过COMMADN copyCOMMAND copy-directory,就解决文件copy的问题。

示例:将dll复制到构建目录

 file(GLOB lua51dll ${LUAJIT_DIR}/src/*.dll)
add_custom_command(TARGET luajit PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${lua51dll} $(OutDir))

区分debug、release

有时候我们还希望针对不同的编译模式,COMMAND也不同,最常见的场景就是debug、release。

之前我尝试在CMAKE中使用CMAKE_BUILD_TYPE,其实是没有任何效果的,因为这个cmake生成的vs工程中其实已经自带了debug、release模式,至于CMAKE_BUILD_TYPE和vs编译模式之间的关系,具体我也没搞明白。

这里就要借助CMAKE的生成器表达式,直接看CMAKE代码:

COMMAND "$<$<CONFIG:Release>:${CMAKE_COMMAND}>" "$<$<CONFIG:Release>:-E>" "$<$<CONFIG:Release>:copy_directory>"
"$<$<CONFIG:Release>:${CMAKE_CURRENT_LIST_DIR}/static/dll>" $(outdir)

大概的用法就是$<条件:值>,如果条件成立,那么就采用这个值,如果条件不成立,那么值就会被忽略,会被空字符串代替。生成器表达式也支持嵌套。

举例:

生成器表达式
$<1:foo>foo
$<0:foo>

而上边的CMAKE代码中,$<CONFIG:arg>是用来测试构建类型,如果arg对应的构建类型正在构建,那么它的的值就为TRUE