windows使用cmake開發C++注意事項記錄
一,庫引用
如引用OpenCV,最快捷的方式是在官網下載如opencv-3.4.10-vc14_vc15.exe的exe程式,執行後即可獲得編譯後的opencv。
在CMakeLists.txt中配置opencv的標頭檔案目錄和lib檔案即include_directories和target_link_libraries即可完成引用。
include_directories和target_link_libraries可都使用絕對路徑,避免出錯。用OpenCV_DIR,${OpenCV_LIBRARIES} ,${OpenCV_INCLUDE_DIRS}等來配置可能會出錯。
其他庫的引用同樣,只需在include_directories
二,多個包相互依賴
比如下圖目錄結構:
base包和sock包都是作為共享庫,sock依賴base,dcm包依賴base和sock。
1)在根目錄的CMakeLists.txt中配置
ADD_SUBDIRECTORY(src/package/base)
ADD_SUBDIRECTORY(src/package/sock)
ADD_SUBDIRECTORY(src/package/dcm)
理解:ADD_SUBDIRECTORY相當於將子目錄CMakeLists.txt中的指令碼匯入到根目錄的CMakeLists.txt,在根目錄的build資料夾下執行cmake ..
此時無論是在子目錄的CMakeLists.txt中還是Findxxx.cmake檔案中引用全域性變數CMAKE_SOURCE_DIR,其值都是根目錄的路徑。而PROJECT_SOURCE_DIR所指的是所在的CMakeLists.txt的路徑。
2)配置Findxxx.cmake檔案的路徑,在執行find_package時cmake會去CMAKE_MODULE_PATH中的路徑中尋找包的cmake檔案
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
3)編寫Findxxx.cmake
該檔案最基本的作用時定義包xxx的標頭檔案目錄變數和lib檔案路徑變數,最簡單如下
message("==================start find base package=================")
if(NOT DEFINED base_DIR)
message("not define package dir ")
else()
message("package dir is ${base_DIR} ")
endif()
message("cmake src dir is ${CMAKE_SOURCE_DIR} ")
set(base_LIB_DIR "${CMAKE_SOURCE_DIR}/install/lib")
set(base_INC_DIR "${base_DIR}/include")
if((NOT EXISTS "${base_INC_DIR}") OR (NOT EXISTS "${base_LIB_DIR}"))
message("this module include or lib path not exsit")
endif()
FIND_LIBRARY(base_LIBS NAMES base PATHS "${base_LIB_DIR}")
if(base_LIBS)
set(base_FOUND TRUE)
set(base_INCLUDE_DIRS ${base_INC_DIR})
set(base_LIBRARIES ${base_LIBS})
# mark_as_advanced(base_FOUND base_INCLUDE_DIRS base_LIBRARIES)
else()
message("can not found lib")
endif()
上面時base包的cmake檔案,在dcm包的CMakeLists.txt中就可以使用下面命令來引用base包
find_package(base)
include_directories(${base_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME}_lib PUBLIC
${base_LIBRARIES}
}
4)配置lib和exe安裝目錄,在根目錄CMakeLists.txt中設定CMAKE_INSTALL_PREFIX包含的路徑
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR}/install)
5)在子專案的CMakeLists.txt配置targets的安裝路徑,如下
INSTALL(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION lib
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
因為根目錄CMakeLists.txt配置了CMAKE_INSTALL_PREFIX,這裡的資料夾lib是在CMAKE_INSTALL_PREFIX目錄下的,所以該子專案的targets會被安裝到MedicalApp/install/lib目錄下。
TARGETS 可指定多個。
三,共享庫匯出
base和sock作為共享庫供dcm包使用,在base和sock的標頭檔案中,對於所有匯出函式,在函式前加_declspec(dllexport),如下:
對於所有匯出類,在類名前加上
#ifdef OS_WIN
_declspec(dllexport)
#endif
如下:
以上對類和函式的新增都是在標頭檔案中,原始檔中不需要新增
四,包編譯
由於sock依賴base,dcm依賴base和sock,所以在用vs2019編譯及安裝時,順序依次是base,sock,dcm
1)在vs2019中,選擇"檢視"->"終端",執行如下
cd build
cmake ..
2)在MedicalApp\build\src\package\base目錄下開啟base.sln,選擇"INSTALL"右鍵"生成",結束後會生成base.dll和base.lib,並且已經拷貝到MedicalApp\install\lib目錄下
3)接下來對sock包和dcm包依次執行上面步驟,最終在MedicalApp\install\lib目錄下,如下圖:
其中opencv_world3410d.dll是手動拷貝過來的,exe執行時需要