cmake配置VS工程配置使用dll

cmake配置VS工程配置使用dll

Author: ChrisZZ
Time: 2024-06-01 16:17:04

1. 目的

使用 CMake 生成 Visual Studio 的 .sln 解决方案文件后, 可执行目标如果依赖了 dll 文件, 在 VS 中运行或调试程序时,需要能找到这些 dll。 有这个几个问题:

  • 如果找不到 dll, 会发生什么?
  • 需要找到哪些 dll?
  • 找到 dll 后放到哪里?

2. 如果找不到 dll, 会发生什么?

可能会弹窗提示, xxx.dll 没找到。 此时程序无法继续运行。 这种比较直观友好。

也可能没有弹窗提示, 黑框框控制台里可能有一句提示, 但打印太多被你忽略了。 程序能继续运行, 但结果不符合预期。 典型情况是 opencv_videoio490_ffmpeg.dll 文件, 获取到的视频帧数为-1.

3. 需要找到哪些 dll?

用到哪些 dll, 就找哪些。 如何确定用到了哪些 dll 文件?

3.1 “就那么几个文件,手动拷贝“

“我的工程很简单, 就需要4个dll, 分别是 protobuf 的一个, opencv 的两个, ncnn 的一个”

这种想法可以临时解决问题, 也带来新的问题:

  • 原始的 dll 文件在哪里, 如何找到?
  • 如果原始的 protobuf/opencv/ncnn 版本升级, dll 文件如何处理?
  • 如果本机和另一台机器的 dll 版本不同, 导致运行结果有问题, 是不是在给自己找麻烦?
  • 找到的 dll 文件, 应该拷贝到哪里?
    • 放系统 PATH 环境变量吗?
    • 放当前 VS 工程目录吗?
      • 为什么 debug 和 release 模式要分别拷贝一次?

3.2 从依赖树递归查询

“我的项目使用 modern cmake 的方式标注依赖关系, 依赖关系是一棵树, 根节点是可执行目标, 从根节点遍历整个依赖树, 扫描出 dll 文件”

这种想法是通用的, 是 scalable 的。 查找 dll 的递归过程, 如果你会写 leetcode 就应该能用 cmake 写出。

具体的依赖写法, 可以是手动的、逐 target 标注依赖关系,也可以基于包管理器, 这里略过。

3.3 额外的 dll 文件

VS2022 从 17.7 版本开始, 无论是 MT(d) 还是 MD(d), 开启 Address Sanitizer 的编译链接选项 /fsanitize=address后, 都只需要一个对应的 ASAN 的 dll 文件。

这个 dll 算是链接选项隐式引入的。 在配置找到其他 dll 文件时, 如果处理不当, 可能会把这一 dll 文件变得不再能被找到。

4. 找到 dll 后放到哪里?

如果打算拷贝 dll 到 VS 的工程路径, 那么或多或少要经历“失败“:

  • VS 的运行路径是什么?
  • exe 文件的所在路径是什么?
  • 工作路径(workding directory)是什么?

也有人觉得,放 PATH 里最省事, 比如经典的配置 OpenCV, 把 d:/pkgs/opencv/4.8.0/build/x64/vc16/bin 目录放到 PATH 环境变量中。 这种做法, 一旦遇到系统需要有多份同名 dll 文件时, 就容易冲突。

其实, 只要让 VS 的运行或调试阶段找到 dll 文件就行了, 其他时候不需要找到。 那么只要关心,如何在 VS 工程中, 临时设定 dll 的查询路径即可。 也就是临时修改可执行文件的 PATH 环境变量。

4.1 VS 工程属性中的调试环境设定

从 VS 工程属性角度来讲, 工程 -> 属性 -> 调试 -> 环境, 设定 PATH 的取值为 “包含所需的 dll 的路径” 即可。

例如默认是 PATH=$(VC_Executable_x64);%PATH%.

可以改为 PATH=$(VC_Executable_x64);%PATH%;D:/pkgs/opencv/4.8.0/build/x64/vc16/bin.

4.2 通过 cmake 设置

可以逐个 target 设置 VS_DEBUGGER_ENVIRONMENT 属性:

set_target_properties(demo PROPERTIES
    VS_DEBUGGER_ENVIRONMENT "PATH=D:/pkgs/opencv/4.8.0/build/x64/vc16/bin;%PATH%"
)

也可以设置 CMAKE_VS_DEBUGGER_ENVIRONMENT 这一全局属性, 它用来初始化 VS_DEBUGGER_ENVIRONMENT 取值。

set(CMAKE_VS_DEBUGGER_ENVIRONMENT "D:/pkgs/opencv/4.8.0/build/x64/vc16/bin")

上述两个写法, 在没有开启 ASAN 的时候都是可以正常使用的。

4.3 cmake 设置 - 处理 ASAN

VS2022 通常使用 ASAN 的 dll 文件, 也就是动态库。 在前一节设定的方式写法下, 会把临时设置的 PATH 中原本继承的 $(VC_Executable_x64) 这一 VS 工程宏(取值为 cl.exe 所在目录)删除。 这导致了 ASAN 的 dll 文件找不到。

我的解决方法是, 在引入 ASAN 选项的时候,设定 CMAKE_VS_DEBUGGER_ENVIRONMENT$(VC_Executable_x64). 这个全局的cmake变量, 会被追加到每个target的 VS_DEBUGGER_ENVIRONMENT 属性上, 每个 target 只需要增加设置需要的 dll 路径即可。

posted @ 2024-06-01 16:59  ChrisZZ  阅读(303)  评论(0编辑  收藏  举报