前言
在开发使用 OpenCV 的项目时,正确配置 CMake 是确保项目顺利构建和运行的关键。开发过程经常存在各种各样的意外和偶然, 是困难也是收获. 比如一直好好的项目, include某个头文件, 编译突然出现:No such file or directory
CmakeTest/test_opencv.h:4: error: opencv2/highgui.hpp: No such file or directory
4 | #include <opencv2/highgui.hpp>
| ^~~~~~~~~~~~~~~~~~~~~
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})