一,库引用
如引用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和target_link_libraries命令中分别配置库的绝对路径即可。
二,多个包相互依赖
比如下图目录结构:
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 ..的时候,cmake的source对象是根目录的CMakeLists.txt。
此时无论是在子目录的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运行时需要