CMake 使用 OpenCV:从库中查找包含头文件
CMake 使用 OpenCV:从库中查找包含头文件
在开发使用OpenCV的项目时,正确配置CMake是确保项目顺利构建和运行的关键。本文将详细介绍如何在CMake中查找和使用OpenCV库,以及如何正确包含OpenCV的头文件。
find_package查找OpenCV库
在CMakeLists.txt
文件中,使用find_package(OpenCV REQUIRED)
来查找并引入OpenCV库。这行代码的作用如下:
- 查找OpenCV库:CMake会在系统的标准位置以及环境变量中指定的位置查找OpenCV库。
- 设置相关变量:找到OpenCV后,CMake会设置一些变量,如
OpenCV_INCLUDE_DIRS
(头文件路径)和OpenCV_LIBS
(库文件)。 - 配置编译选项:CMake使用这些变量配置项目,使代码能够包含OpenCV的头文件并链接到OpenCV库。
CMakeLists.txt
文件示例:
cmake_minimum_required(VERSION 3.4.1)
project(CMakeTest)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 配置OpenCV路径
set(OpenCV_DIR /sdk/opencv-linux-aarch64/lib/cmake/opencv4)
# 查找OpenCV库
find_package(OpenCV REQUIRED)
#message(OpenCV_LIBS "=${OpenCV_LIBS}")
# 输出: OpenCV_LIBS=opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio
#message(OpenCV_INCLUDE_DIRS "=${OpenCV_INCLUDE_DIRS}")
# 输出: OpenCV_INCLUDE_DIRS=/sdk/opencv-linux-aarch64/include/opencv4
#target_include_directories(my_executable PRIVATE ${OpenCV_INCLUDE_DIRS})
#include_directories(${CMAKE_SOURCE_DIR}/include2)
# 添加可执行文件
add_executable(test_opencv
test_opencv.cpp)
# 链接OpenCV库
target_link_libraries(test_opencv
${OpenCV_LIBS}
)
在这个示例中,CMake首先查找OpenCV库,然后设置包含路径和库路径,最后将这些路径添加到编译选项中,以便在编译和链接时使用OpenCV库。
包含OpenCV头文件
假设项目目录结构如下:
CMakeTest/
├── CMakeLists.txt
├── test_opencv.cpp
├── main.cpp
└── test_opencv.h
在test_opencv.h
和test_opencv.cpp
文件中,需要正确包含OpenCV的头文件:
test_opencv.h
:
#ifndef _TEST_OPENCV_H_
#define _TEST_OPENCV_H_
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
class ImageUtils{
public:
void init(){
cv::Mat img = cv::imread("/data/test.jpg");
}
};
#endif
test_opencv.cpp
:
#include "test_opencv.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
printf("[%s] start\n", __FUNCTION__);
return 0;
}
通过上述设置,test_opencv.h
和test_opencv.cpp
文件都能正确包含OpenCV的头文件。
通常,在正常情况下,使用外部的动态库时,只需要2步:
- 包含所需的头文件
- 链接所需的库
在前面代码中,并没有显式地使用include_directories
或target_include_directories
包含OpenCV的头文件。
为什么不需要显式设置include_directories
原因是在CMake中,find_package(OpenCV REQUIRED)
会引入OpenCV的目标(targets),这些目标包含了库文件和包含路径信息。当你链接OpenCV目标时,这些包含路径会自动应用于你的目标。
示例项目结构
cmake_minimum_required(VERSION 3.10)
project(MyProject)
# 查找OpenCV库
find_package(OpenCV REQUIRED)
# 添加可执行文件
add_executable(my_executable main.cpp mycpp.cpp)
# 链接OpenCV库
target_link_libraries(my_executable ${OpenCV_LIBS})
在这个配置中,target_link_libraries(my_executable ${OpenCV_LIBS})
会自动将OpenCV的包含路径应用到my_executable
目标的所有源文件(main.cpp
和mycpp.cpp
)。
全局范围与目标范围的include_directories
虽然在现代CMake中不需要显式调用include_directories(${OpenCV_INCLUDE_DIRS})
,但为了确保兼容性和避免潜在问题,明确设置包含路径仍然是个好习惯:
全局范围:在项目的顶部调用
include_directories
,会影响整个项目中的所有目标和源文件。include_directories(${OpenCV_INCLUDE_DIRS})
目标范围:使用
target_include_directories
,只会影响特定目标。target_include_directories(my_executable PRIVATE ${OpenCV_INCLUDE_DIRS})
结论
- CMake:依赖目标导入机制,
target_link_libraries
会自动处理包含路径。 - 兼容性:为了避免路径冲突或未找到头文件的问题,显式设置包含路径是个好习惯。
通过正确配置CMake和OpenCV,确保项目顺利构建和运行。
问题解决
首先,关于include某个头文件,编译突然出现:No such file or directory这个问题是如何出现的:
cmake_minimum_required(VERSION 3.4.1)
project(CMakeTest)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 配置OpenCV路径
set(OpenCV_DIR /sdk/opencv-linux-aarch64/lib/cmake/opencv4)
# 查找OpenCV库
find_package(OpenCV REQUIRED)
# 添加可执行文件
add_executable(test_opencv
test_opencv.cpp)
# 链接OpenCV库
target_link_libraries(test_opencv
${OpenCV_LIBS}
)
### 分界线 ###
add_executable(test_main
main.cpp)
配置输出两个可执行文件:test_opencv,test_main
问题就出在test_main
main.cpp
源码内容和test_opencv.cpp
是一样的:
#include "test_opencv.h"
#include "stdio.h"
#include "stdlib.h"
int main()
{
printf("[%s] start\n", __FUNCTION__);
return 0;
}
CmakeTest/main.cpp:1: In file included from CmakeTest/main.cpp:1:
CmakeTest/test_opencv.h:4: error: opencv2/highgui.hpp: No such file or directory
4 | #include <opencv2/highgui.hpp>
| ^~~~~~~~~~~~~~~~~~~~~
因为test_main没有链接OpenCV库,解决方案有:
- 增加:
target_link_libraries(test_main ${OpenCV_LIBS} )
- 全局增加
include_directories(${OpenCV_INCLUDE_DIRS})
- 针对test_main增加
target_include_directories(test_main PRIVATE ${OpenCV_INCLUDE_DIRS})