cmake 写 findmodule
用过 CMake 的同学应该都知道,cmake 使用 find_package() 命令查找第三方的库。find_package 实际上又是调用了一个 cmake 的脚本文件来获取库的实际信息的。比如我们要查找一个库,名字叫 。那么 find_package 是去找两种文件:
- Find<name>.cmake 这个文件通常是 CMake 自带的。一般在 CMake 安装目录的 Modules 子目录中。
- <name>Config.cmake 这个文件通常是第三方库自己带的。
如果我们使用的第三方的库没有提供<name>Config.cmake,cmake 也没提供 Find<name>.cmake ,这时我们应该怎么办呢?
比较原始的方法就是自己在 CMakeLists.txt使用 find_path() 来查找头文件的位置。用 find_library() 来查找库文件。这个说起来简单,但是如果考虑到编译目标有 x86 和 x64,还要区分 debug 和 release。把这些全都考虑清楚还是要写不少的代码的。如果每个项目都写一遍工作量还是蛮大的。所以更好的方法是写一个 findmodule 文件。以后每次都用这个文件。
下面是练手时写的一个例子,参考了 AI 给出的代码。第三方库是 海康机器人的 MVS。 MVS 是海康机器人为他们自己的工业相机配套的测试程序,同时也带有海康工业相机和图像采集卡的 SDK。这个 SDK 海康没有专门的命令,我们就姑且也叫它为 MVS 吧。 MVS 中其实是提供了两套独立的 SDK 的,一套对应他们的工业相机,我们称之为 MVS_CC,这里 CC表示Camera Control),另一套称之为 MVS_FG,其中 FG 表示 FrameGrabber。
我们的代码分为两个部分,首先先去找 MVS 的安装位置:
# 查找海康 MVS 的 SDK, MVS_CC 是相机的 SDK, MVS_FG 是采集卡的 SDK
# 用户可以设置环境变量 HIK_MVS_ROOT 为 MVS 的安装路径 # 如果成功找到 MVS, 则会设置如下的变量
# 1. MVS_CC_INCLUDE_DIRS
# 2. MVS_FG_INCLUDE_DIRS
# 3. MVS_CC_LIBRARIES
# 4. MVS_FG_LIBRARIES
# 5. MVS_FOUND# MVS_ROOT 是 MVS 的安装路径
if(NOT MVS_ROOT)set(MVS_ROOT "$ENV{HIK_MVS_ROOT}") # 先看有没有对应的环境变量,有的话直接用环境变量的值
endif()if(NOT MVS_ROOT) # 如果没找到环境变量,则在一些特定路径下查找find_path(_MVS_ROOT NAMES Development/Includes/MvCameraControl.hHINTS "C:/Program Files (x86)/MVS" "D:/Program Files (x86)/MVS" "E:/Program Files (x86)/MVS" )
else()set(_MVS_ROOT "${MVS_ROOT}")
endif()
以上代码很简单,MVS 安装路径有三个途径来获取:
- cmake -DMVS_ROOT=“path” 利用 -D 来告诉 cmake MVS 的地址。
- 设置环境变量 HIK_MVS_ROOT
- 如果上面两个都没做,那么就在一些标准位置去查找
上面执行之后,MVS的安装路径就存在 _MVS_ROOT 变量中了。
然后就是查找 头文件和 库文件。头文件和库文件的位置相对 MVS 的安装位置是固定的。但是库文件有两套,分别是 win32 和 win64 的。对于其他一些库,可能还要区分 debug 和 release。那么搭配起来就有 4 个不同的库文件。有多少种都没有关系,我们分别把他们都找到,然后放到合适的变量中。
find_path(MVS_CC_INCLUDE_DIRS NAMES MvCameraControl.h HINTS ${_MVS_ROOT}/Development/Includes)find_path(MVS_FG_INCLUDE_DIRS NAMES MVFGControl.h HINTS ${_MVS_ROOT}/Development/MVFG/Includes)find_library(MVS_CC_LIBRARIES_win32NAMESMvCameraControl.libPATHS"${_MVS_ROOT}/Development/Libraries/win32/")find_library(MVS_CC_LIBRARIES_win64NAMESMvCameraControl.libPATHS"${_MVS_ROOT}/Development/Libraries/win64/")find_library(MVS_FG_LIBRARIES_win32NAMESMVFGControl.libPATHS"${_MVS_ROOT}/Development/MVFG/Libraries/win32/")find_library(MVS_FG_LIBRARIES_win64NAMESMVFGControl.libPATHS"${_MVS_ROOT}/Development/MVFG/Libraries/win64/")
上面的代码很直白,就不过多解释了。下面到了重点内容。我们需要知道当前配置编译出的代码时 x86还是 x64 的,这样我们才能知道我们链接时该链接到哪个库。cmake 的标准做法是检测 CMAKE_SIZEOF_VOID_P 的值,如果这个指针是 8 bytes,难么编译出的代码就是 x64 的。
if(CMAKE_SIZEOF_VOID_P EQUAL 8)set(MVS_FG_LIBRARIES ${MVS_FG_LIBRARIES_win64})set(MVS_CC_LIBRARIES ${MVS_CC_LIBRARIES_win64})message(STATUS "Target is 64 bits")
else()set(MVS_FG_LIBRARIES ${MVS_FG_LIBRARIES_win32})set(MVS_CC_LIBRARIES ${MVS_CC_LIBRARIES_win32})message(STATUS "Target is 32 bits")
endif()
MVS 没有提供 debug 版的库,但是我们还是要讲讲该如何区分 debug 和 release。
if(CMAKE_BUILD_TYPE STREQUAL "Debug")set(...)message(STATUS "Target is in debug mode")
else()set(...)message(STATUS "Target is in release mode")
endif()
最后再设置一下 MVS_FOUND 变量就大功告成了。
find_package_handle_standard_args(MVSFOUND_VARMVS_FOUNDREQUIRED_VARSMVS_CC_INCLUDE_DIRSMVS_FG_INCLUDE_DIRSMVS_CC_LIBRARIESMVS_FG_LIBRARIES)