第55章:Qt项目——用find_package搞定Qt5/Qt6构建

Qt项目构建,说白了就是让CMake找到Qt的库和头文件。很多新手一上来就手动设置路径,结果换个机器就崩。我个人习惯用find_package,这是最正统的做法。

为什么非要用find_package?

你想想看,Qt的安装路径五花八门——Windows可能在C:\Qt\5.15.2,Linux可能在/usr/lib/x86_64-linux-gnu/cmake。手动写死路径?那项目基本就废了。

find_package会自动搜索系统里注册的Qt路径。我在项目中遇到过好几次,同事把Qt装到D盘,结果CMake死活找不到。其实就是没设CMAKE_PREFIX_PATH

核心命令:

find_package(Qt5 COMPONENTS Widgets Core Gui REQUIRED)

或者Qt6版本:

find_package(Qt6 REQUIRED COMPONENTS Widgets Core Gui)

Qt5 vs Qt6,怎么选?

嗯,这里要注意。Qt6和Qt5的模块名有些变化。比如Qt5的Qt5WebEngineWidgets在Qt6里变成了Qt6WebEngineWidgets。我建议你直接写一个兼容两者的CMake脚本。

模块 Qt5名称 Qt6名称
基础控件 Qt5::Widgets Qt6::Widgets
网络模块 Qt5::Network Qt6::Network
OpenGL Qt5::OpenGL Qt6::OpenGL
QML Qt5::Qml Qt6::Qml

实战:一个完整的Qt项目CMakeLists.txt

直接上代码。这是我常用的模板,兼容Qt5和Qt6:

cmake_minimum_required(VERSION 3.16)
project(MyQtApp LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 自动检测Qt版本
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Core Gui)

# 如果你需要网络模块
# find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Network)

add_executable(${PROJECT_NAME}
    main.cpp
    mainwindow.cpp
    mainwindow.h
)

target_link_libraries(${PROJECT_NAME} PRIVATE
    Qt${QT_VERSION_MAJOR}::Widgets
    Qt${QT_VERSION_MAJOR}::Core
    Qt${QT_VERSION_MAJOR}::Gui
)

# 自动处理MOC、UIC、RCC
set_target_properties(${PROJECT_NAME} PROPERTIES
    AUTOMOC ON
    AUTOUIC ON
    AUTORCC ON
)

这里有个小技巧:find_package(QT NAMES Qt6 Qt5)会先找Qt6,找不到再找Qt5。变量QT_VERSION_MAJOR会自动设为6或5。这样你写一次CMake,两个版本都能用。

避坑指南:我曾经在Windows上遇到find_package找不到Qt,折腾了半天。后来发现是没设CMAKE_PREFIX_PATH。你可以在CMake命令行加:

cmake -DCMAKE_PREFIX_PATH=C:/Qt/6.5.0/msvc2019_64 ..

或者在CMakeLists.txt里加:

set(CMAKE_PREFIX_PATH "C:/Qt/6.5.0/msvc2019_64")

MOC、UIC、RCC——Qt的三驾马车

Qt项目里,头文件里经常有Q_OBJECT宏,这玩意儿需要MOC(元对象编译器)处理。还有.ui文件需要UIC处理,.qrc资源文件需要RCC处理。

手动调用这些工具?太累了。CMake提供了三个开关:

  • AUTOMOC ON:自动扫描头文件,发现有Q_OBJECT就调用moc
  • AUTOUIC ON:自动处理.ui文件
  • AUTORCC ON:自动编译.qrc资源文件

我个人习惯全部打开。省心。但要注意,如果你的头文件不在add_executable里列出,AUTOMOC可能找不到。所以头文件也要加进去。

SVG:find_package构建Qt项目的完整流程

find_package构建Qt项目流程图 CMakeLists.txt find_package(Qt5/Qt6) 搜索路径: CMAKE_PREFIX_PATH / 系统注册表 / 环境变量 找到 QtConfig.cmake target_link_libraries 关键变量: QT_VERSION_MAJOR Qt5_DIR / Qt6_DIR CMAKE_PREFIX_PATH 常见模块: Widgets、Core、Gui Network、OpenGL Qml、Quick 自动工具: AUTOMOC AUTOUIC AUTORCC

常见问题与避坑

问题1:找不到Qt

我曾经在Linux上遇到find_package说找不到Qt5,但明明装了。后来发现是没装qtbase5-dev这个包。Ubuntu上要装:

sudo apt install qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools

Qt6的话:

sudo apt install qt6-base-dev

问题2:版本冲突

如果你系统里同时装了Qt5和Qt6,find_package可能会找到你不想用的版本。解决办法:

# 强制使用Qt5
find_package(Qt5 REQUIRED COMPONENTS Widgets)

# 或者强制使用Qt6
find_package(Qt6 REQUIRED COMPONENTS Widgets)

问题3:链接错误

有时候find_package成功了,但链接时报错说找不到某个符号。这通常是因为你忘了链接某个模块。比如用了QNetworkAccessManager但没链接Network模块。

我的经验是:用到了哪个Qt类,就去查它属于哪个模块。比如QJsonDocument属于CoreQWebEngineView属于WebEngineWidgets

总结一下

find_package构建Qt项目,说白了就是三步:

  1. 调用find_package找到Qt
  2. add_executable添加源文件
  3. target_link_libraries链接Qt模块

再加上AUTOMOCAUTOUICAUTORCC三个开关,基本就齐活了。嗯,就这么简单。

对了,如果你在Windows上用MSVC,记得用cmake -G "Visual Studio 17 2022"指定生成器。不然CMake可能默认用Ninja,而Ninja不一定能找到Qt的DLL路径。我踩过这个坑,编译通过了,运行时报错说找不到Qt5Core.dll……后来老老实实设了PATH环境变量才搞定。

公众号:蓝海资料掘金营,微信deep3321