cmake配置VS工程配置使用dll

ChrisZZ發表於2024-06-01

cmake配置VS工程配置使用dll

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

目錄
  • cmake配置VS工程配置使用dll
    • 1. 目的
    • 2. 如果找不到 dll, 會發生什麼?
    • 3. 需要找到哪些 dll?
      • 3.1 “就那麼幾個檔案,手動複製“
      • 3.2 從依賴樹遞迴查詢
      • 3.3 額外的 dll 檔案
    • 4. 找到 dll 後放到哪裡?
      • 4.1 VS 工程屬性中的除錯環境設定
      • 4.2 透過 cmake 設定
      • 4.3 cmake 設定 - 處理 ASAN

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 路徑即可。

相關文章