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