- 前言
- 引例
- 环境变量
- find_package查询路径
- 设定查询路径
- 默认路径
- 链接库问题
- find_package()命令
很久之前就想写关于CMakeLists相关的学习记录,但当时的重点在数学基础内容上,这一块就搁置了,现在重新记录一下。
首先就是cmake中查找第三方包指令find_package()的原理
引例图像相关的工程中,最常用的第三方包OpenCV需要通过CMakeLists来配置,常见写法如下:
find_package(OpenCV 4 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(main src/main.cpp)
target_link_libraries(main ${OpenCV_LIBRARIES})
上面的配置中,find_package从目录中寻找OpenCV,找到后将头文件目录设置为${OpenCV_INCLUDE_DIRS}
,库文件设为${OpenCV_LIBRARIES}
,然后在工程中包含OpenCV头文件目录,生成可执行文件,最后链接OpenCV库。
首先需要知道本机的环境变量,可以使用export命令显示所有环境变量:
export
也可以使用echo命令显示某个环境变量,比如PATH:
echo $PATH
find_package查询路径
cmake设置第三方包的头文件目录和库文件位置,是通过查询.cmake文件实现的,有两种命名形式,Find.cmake
或者Config.cmake
。
.cmake
文件一般在第三方包编译和安装时会自动安装到$CMAKE_PREFIX_PATH/lib/cmake/
等文件夹中,比如/usr/lib/cmake/
,/usr/local/lib/cmake
等等。
find_package()
的工作就是在特定路径下查找第三方包.cmake
文件。这些路径包括设定查询路径与默认查询路径。
设定查询路径通过cmake中的CMAKE_MODULE_PATH
关键字设置寻找.cmake
的位置:
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
上面的指令把工程根目录下的cmake文件夹添加为.cmake
文件搜索路径,是优先搜索的路径。
另外,还可以直接设置某个包的.cmake
位置:
set(OpenCV_DIR /path_to_opencv)
find_package(OpenCV)
上面的指令使find_package()
寻找OpenCV时,最优先查找/path_to_opencv路径下的.cmake
文件。
如果没有设定查询路径,或者在设定查询路径没有找到合适的.cmake
时,cmake继续在默认查询路径中寻找.cmake
文件,这些默认查询路径有:
PATH
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
如果PATH路径为/bin
或/sbin
文件夹,则从上一级目录查找。
以默认路径为根目录,cmake将检查根目录下的/lib/cmake
,/lib//cmake
,/share/cmake
下寻找.cmake
文件,根据.cmake生成对应的头文件目录和库文件路径。
find_package()后,include_directories()基本上不会出问题,常见问题在链接库。
还是以OpenCV为例:
find_package(OpenCV 4 REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
add_executable(main src/main.cpp)
target_link_libraries(main ${OpenCV_LIBRARIES})
执行cmake
成功,make
编译时没有找到opencv的库是很常见的报错。明明在cmake中target_link_libraries()指定了链接库,那么为什么还是会报ld错误呢?
这是因为,部分第三方包的.cmake
文件提供给cmake的${_LIBRARIES}
只是一个包名,比如OpenCV的就是
libopencv_calib3d
libopencv_core
...
等一大串库文件的名字,而不是路径,编译器不知道库文件的路径在哪,找不到库,自然就会报ld链接错误了。
解决方法就是给出链接库的路径,这里就涉及到一个ld问题。为了以后查询方便,ld将放在ubuntu指令学习中。
还有一个更简单但也更麻烦的链接方法:直接把需要链接的库放在Makefile的根目录下,编译器就能直接看到库文件了。
find_package()命令最后回到find_package命令上,它的常用形式为:
find_package( [version] [EXACT] [QUIET] [REQUIRED])
version: 版本合适(大版本号相同) EXACT: 版本必须一致 QUIET: 没找到包也不会报错 REQUIRED: 必须找到该包,否则停止