项目实战:编写CMakeLists管理Qt+OpenCV项目

本文详细介绍了将基于Qt和OpenCV的Visual Studio项目迁移到CMake构建系统的完整过程。文章首先展示了原始项目结构,然后逐步讲解了CMakeLists文件的编写方法,包括设置C++17标准、禁用编译器扩展、配置Qt自动处理、引入OpenCV库、添加项目文件等关键步骤。特别说明了如何处理OpenCV动态库的路径问题,以及如何设置UTF-8编码防止乱码。最后提供了完整的CMakeLists文件内容和构建命令,指导读者成功生成可执行文件。该教程可作为将MSBuild项目迁移到CMake的实用参考

作者
WildPointer
发布
2026.04.20
专栏
项目实战
阅读
约 12 分钟 / 525 次原文浏览
项目实战:编写CMakeLists管理Qt+OpenCV项目

前言

本文详细介绍如何将基于Qt和OpenCV的Visual Studio项目(使用MSBuild)迁移到CMake构建系统。通过一个包含第三方库和子模块的完整示例,演示CMakeLists.txt的编写方法。读者可基于此模板扩展更复杂的项目场景。


项目介绍

本文初始项目是使用Visual Studio编写的,项目的结构如下:

bash
项目 ├QtCmakeTest.sln └QtCmakeTest  ├───imgModel  │   ├───imgHandle.h  │   └───imgHandle.cpp  ├───OpenCV  │   ├───include  │   │   └───opencv2  │   └───x64  │       └───vc16  │           ├───bin  │           └───lib  ├───x64  │   ├───Debug  │   └───Release  ├───main.cpp  ├───QtCmakeTest.h  ├───QtCmakeTest.ui  ├───QtCmakeTest.cpp  ├───QtCmakeTest.qrc  ├───QtCmakeTest.vcxproj  ├───QtCmakeTest.vcxproj.filters  └───QtCmakeTest.vcxproj.user

项目所实现的功能也比较简单,具体如图:

图1.项目截图

如果在阅读本篇文章之前,读者并没有了解过CMakeLists相关的语法也没有下载过CMake,那么可以参考以下几篇文章的内容进行了解:高效工具实战指南:CMake构建工具https://blog.csdn.net/weixin_67035108/article/details/155361963?spm=1001.2014.3001.5502高效工具实战指南:从零开始编写CMakeLists文件的编写https://blog.csdn.net/weixin_67035108/article/details/142031902?spm=1001.2014.3001.5502


CMakeLists文件的编写

在我们编写CMakeLists文件的时候,首先都会指定C++的版本以及CMakeLists文件支持的CMake版本,所以当前项目也是如此,具体如下。
1.在CMakeLists文件中添加指定版本命令:

bash
# 设置CMake所需的最低版本cmake_minimum_required(VERSION 3.21)# 定义项目名称和使用的编程语言# QtCmakeTest是项目名称,CXX表示使用C++语言project(QtCmakeTest LANGUAGES CXX)# 设置C++标准为C++17set(CMAKE_CXX_STANDARD 17)# 要求必须支持C++17标准set(CMAKE_CXX_STANDARD_REQUIRED ON)

在添加了版本命令以后,我们考虑到项目可能需要跨平台,所以还需要将编译器的扩展禁用,保证项目整体的可移植性,具体如下。
2.在CMakeLists文件中添加禁用编译器扩展命令:

bash
# 禁用编译器特定的扩展,确保代码可移植性set(CMAKE_CXX_EXTENSIONS OFF)

除此之外我们的项目使用到了Qt来构建可视化界面,而Qt中包含了ui文件和qrc资源文件等文件,为了让编译器认识到这些文件并且合理的编译,我们还需要启用对Qt的一些处理,具体如下。
3.在CMakeLists文件中添加启用Qt处理命令:

bash
# 启用Qt的自动元对象编译器(MOC)处理# MOC用于处理Qt的信号槽机制set(CMAKE_AUTOMOC ON)# 启用Qt的用户界面编译器(UIC)自动处理# UIC用于编译.ui文件set(CMAKE_AUTOUIC ON)# 启用Qt的资源编译器(RCC)自动处理# RCC用于编译.qrc资源文件set(CMAKE_AUTORCC ON)

在项目中我们导入了第三方库OpenCV,该库放到项目中的OpenCV文件夹下,里面包含了头文件,动态链接库和静态链接库,所以我们在CMakeLists中需要把这个路径引用进来。具体如下。
4.在CMakeLists文件中添加引用OpenCV命令:

bash
# 使用随项目提供的OpenCV CMake配置文件。set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/QtCmakeTest/OpenCV/x64/vc16/lib")find_package(OpenCV REQUIRED CONFIG COMPONENTS world)message(STATUS "OpenCV 头文件目录: ${OpenCV_INCLUDE_DIRS}")message(STATUS "OpenCV 配置目录: ${OpenCV_DIR}")

由于项目中使用QWidget实现的可视化界面,所以我们还需要导入Qt中的Widget模块,具体如下。

5.在CMakeLists文件中添加导入Widget模块命令:

bash
# 查找并加载Qt6库,必须包含Widgets组件find_package(Qt6 REQUIRED COMPONENTS Widgets)

然后我们还需要开启一些关于CMake的Qt设置,具体如下。

6.在CMakeLists文件中添加应用Qt设置命令:

bash
# 应用Qt的标准项目设置# 这会自动设置一些与Qt相关的CMake变量和策略qt_standard_project_setup()

在设置好这些基础操作以后,我们要把项目中所包含的头文件,源文件以及各种与项目有关的文件添加到路径里,具体如下:

7.在CMakeLists文件中添加项目包含文件:

bash
# 定义项目的源文件列表# 包括:主程序文件、Qt类文件、头文件、UI文件、资源文件、自定义模型文件set(PROJECT_SOURCES    QtCmakeTest/main.cpp              # 程序入口文件    QtCmakeTest/QtCmakeTest.cpp       # 主窗口实现文件    QtCmakeTest/QtCmakeTest.h         # 主窗口头文件    QtCmakeTest/QtCmakeTest.ui        # Qt Designer 设计的界面文件    QtCmakeTest/QtCmakeTest.qrc       # Qt 资源文件(包含图标、图片等)    QtCmakeTest/imgModel/imgHandle.cpp # 图像处理模型实现文件    QtCmakeTest/imgModel/imgHandle.h   # 图像处理模型头文件)

接下来我们需要添加生成的可执行文件,并且把可执行文件所需要的头文件添加到目标的包含目录,如下:
8.添加可执行文件和头文件:

bash
# 添加可执行目标# WIN32 参数表示创建 Windows GUI 应用程序(不显示控制台窗口)qt_add_executable(QtCmakeTest    WIN32    ${PROJECT_SOURCES})# 设置目标的包含目录# PRIVATE 表示这些目录仅用于此目标的编译target_include_directories(QtCmakeTest    PRIVATE        ${CMAKE_CURRENT_SOURCE_DIR}/QtCmakeTest  # 项目自身的头文件目录        ${OpenCV_INCLUDE_DIRS}                   # OpenCV 的头文件目录)

写好这些命令以后我们需要指定OpenCV的动态链接库路径,并且把动态链接库复制到生成的可执行文件路径下,防止可执行文件找不到动态链接库,如下:
9.使用命令复制动态链接库至可执行文件路径下:

bash
# 设置 OpenCV 动态库(DLL)所在的目录路径set(OPENCV_BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/QtCmakeTest/OpenCV/x64/vc16/bin")# 如果 OpenCV 的 bin 目录存在,则在构建后自动复制所需的 DLL 文件# 这解决了运行时依赖问题,避免"缺少 DLL"的错误if(EXISTS "${OPENCV_BIN_DIR}")    # 添加构建后自定义命令    add_custom_command(TARGET QtCmakeTest POST_BUILD        # 复制 DLL 文件到可执行文件所在目录        COMMAND ${CMAKE_COMMAND} -E copy_if_different            # 源文件:根据构建配置选择 Debug 或 Release 版本的 DLL            # $<CONFIG:Debug> 是生成器表达式,Debug 配置时为 1,否则为 0            # Debug 版本使用 opencv_world490d.dll,Release 版本使用 opencv_world490.dll            "${OPENCV_BIN_DIR}/$<IF:$<CONFIG:Debug>,opencv_world490d.dll,opencv_world490.dll>"            # 目标目录:可执行文件所在的目录            "$<TARGET_FILE_DIR:QtCmakeTest>"        VERBATIM  # 确保参数被正确传递,不进行转义    )endif()

为了防止生成的可执行文件乱码,我们可以指定源代码使用UTF-8编码,如下:

10.使用命令指定使用UTF-8编码:

bash
# 如果是 Microsoft Visual Studio 编译器,设置编译选项# /utf-8 选项确保源代码使用 UTF-8 编码if(MSVC)    target_compile_options(QtCmakeTest PRIVATE /utf-8)endif()

使用CMake生成项目

按步骤编写好CMakeLists文件以后,文件内容应该如下:

bash
# 设置 CMake 所需的最低版本cmake_minimum_required(VERSION 3.21)# 定义项目名称和使用的编程语言# QtCmakeTest 是项目名称,CXX 表示使用 C++ 语言project(QtCmakeTest LANGUAGES CXX)# 设置 C++ 标准为 C++17set(CMAKE_CXX_STANDARD 17)# 要求必须支持 C++17 标准set(CMAKE_CXX_STANDARD_REQUIRED ON)# 禁用编译器特定的扩展,确保代码可移植性set(CMAKE_CXX_EXTENSIONS OFF)# 启用 Qt 的自动元对象编译器(MOC)处理# MOC 用于处理 Qt 的信号槽机制set(CMAKE_AUTOMOC ON)# 启用 Qt 的用户界面编译器(UIC)自动处理# UIC 用于编译 .ui 文件set(CMAKE_AUTOUIC ON)# 启用 Qt 的资源编译器(RCC)自动处理# RCC 用于编译 .qrc 资源文件set(CMAKE_AUTORCC ON)# 使用随项目提供的 OpenCV CMake 配置文件。set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/QtCmakeTest/OpenCV/x64/vc16/lib")find_package(OpenCV REQUIRED CONFIG COMPONENTS world)message(STATUS "OpenCV 头文件目录: ${OpenCV_INCLUDE_DIRS}")message(STATUS "OpenCV 配置目录: ${OpenCV_DIR}")# 查找并加载 Qt6 库,必须包含 Widgets 组件find_package(Qt6 REQUIRED COMPONENTS Widgets)# 应用 Qt 的标准项目设置# 这会自动设置一些与 Qt 相关的 CMake 变量和策略qt_standard_project_setup()# 定义项目的源文件列表# 包括:主程序文件、Qt 类文件、头文件、UI 文件、资源文件、自定义模型文件set(PROJECT_SOURCES    QtCmakeTest/main.cpp              # 程序入口文件    QtCmakeTest/QtCmakeTest.cpp       # 主窗口实现文件    QtCmakeTest/QtCmakeTest.h         # 主窗口头文件    QtCmakeTest/QtCmakeTest.ui        # Qt Designer 设计的界面文件    QtCmakeTest/QtCmakeTest.qrc       # Qt 资源文件(包含图标、图片等)    QtCmakeTest/imgModel/imgHandle.cpp # 图像处理模型实现文件    QtCmakeTest/imgModel/imgHandle.h   # 图像处理模型头文件)# 添加可执行目标# WIN32 参数表示创建 Windows GUI 应用程序(不显示控制台窗口)qt_add_executable(QtCmakeTest    WIN32    ${PROJECT_SOURCES})# 设置目标的包含目录# PRIVATE 表示这些目录仅用于此目标的编译target_include_directories(QtCmakeTest    PRIVATE        ${CMAKE_CURRENT_SOURCE_DIR}/QtCmakeTest  # 项目自身的头文件目录        ${OpenCV_INCLUDE_DIRS}                   # OpenCV 的头文件目录)# 链接库到目标# PRIVATE 表示这些库仅用于此目标的链接target_link_libraries(QtCmakeTest    PRIVATE        Qt6::Widgets    # Qt6 Widgets 模块        opencv_world    # OpenCV 库)# 如果是 Microsoft Visual Studio 编译器,设置编译选项# /utf-8 选项确保源代码使用 UTF-8 编码if(MSVC)    target_compile_options(QtCmakeTest PRIVATE /utf-8)endif()# 设置 OpenCV 动态库(DLL)所在的目录路径set(OPENCV_BIN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/QtCmakeTest/OpenCV/x64/vc16/bin")# 如果 OpenCV 的 bin 目录存在,则在构建后自动复制所需的 DLL 文件# 这解决了运行时依赖问题,避免"缺少 DLL"的错误if(EXISTS "${OPENCV_BIN_DIR}")    # 添加构建后自定义命令    add_custom_command(TARGET QtCmakeTest POST_BUILD        # 复制 DLL 文件到可执行文件所在目录        COMMAND ${CMAKE_COMMAND} -E copy_if_different            # 源文件:根据构建配置选择 Debug 或 Release 版本的 DLL            # $<CONFIG:Debug> 是生成器表达式,Debug 配置时为 1,否则为 0            # Debug 版本使用 opencv_world490d.dll,Release 版本使用 opencv_world490.dll            "${OPENCV_BIN_DIR}/$<IF:$<CONFIG:Debug>,opencv_world490d.dll,opencv_world490.dll>"            # 目标目录:可执行文件所在的目录            "$<TARGET_FILE_DIR:QtCmakeTest>"        VERBATIM  # 确保参数被正确传递,不进行转义    )endif()

接下来我们只需要使用CMake命令来生成可执行文件即可,具体的执行命令如下:

bash
cmake .. cmake --build .

执行完毕,即可生成可执行文件。

图2.生成可执行文件

12次原文点赞;这里的喜欢仅保存在本机
WildPointer

专注系统编程、工程实践与底层技术,记录 C++、Qt、OpenCV 与 VTK 的学习和实践。