3、qmake与CMake对比:qmake项目文件详解、qmake与CMake的优劣分析、迁移策略
说到Qt项目的构建工具,绕不开两个名字:qmake和CMake。我最早接触Qt时,用的就是qmake。那时候觉得它挺方便,写个.pro文件,几行代码就能把项目跑起来。但随着项目越做越大,跨平台需求越来越多,我慢慢发现qmake有些力不从心了。
后来Qt官方也开始推CMake,从Qt6开始,CMake成了默认构建系统。嗯,这里有个问题:我们到底该选哪个?
我个人习惯是:新项目直接用CMake,老项目如果维护成本不高,继续用qmake也没问题。但如果你问我迁移策略,我会说——迟早要迁,早迁早省心。
3.1 qmake项目文件详解
先说说qmake的项目文件,也就是.pro文件。它的语法其实很简单,说白了就是一套键值对配置。
一个典型的.pro文件长这样:
QT += core gui widgets
TARGET = MyApp
TEMPLATE = app
CONFIG += c++17
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
RESOURCES += \
resources.qrc
这里我解释几个关键点:
- QT模块声明:
QT += core gui widgets,你用了哪些模块就加哪些。我见过有人把所有模块都加进去,结果编译慢得要命。别这么干。 - TARGET:生成的可执行文件名。注意,在Windows上会自动加
.exe,Linux和macOS不会。 - TEMPLATE:项目模板。常见的有
app(应用程序)、lib(库)、subdirs(子项目)。 - CONFIG:编译配置。比如
c++17、debug、release、static等。
CONFIG(debug, debug|release)来做条件判断。我在项目中经常用这个来设置不同的输出路径。
qmake还支持一些高级功能,比如自定义构建步骤:
# 在编译前执行某个脚本
QMAKE_PRE_BUILD = my_script.sh
# 在链接后执行某个命令
QMAKE_POST_LINK = copy /Y $$OUT_PWD/MyApp.exe C:/deploy/
不过说实话,qmake的脚本能力比较弱。你要是想搞复杂的构建逻辑,写起来会很痛苦。我曾经在一个项目里试图用qmake实现自动版本号生成,折腾了半天,最后还是换成了CMake。
3.2 qmake与CMake的优劣分析
咱们来做个对比。我直接说结论:
| 对比维度 | qmake | CMake |
|---|---|---|
| 学习曲线 | 低,语法简单 | 中等,但功能强大 |
| 跨平台能力 | 一般,依赖Qt | 强,原生支持多平台 |
| 第三方库支持 | 弱,需要手动配置 | 强,有find_package机制 |
| IDE集成 | Qt Creator原生支持 | 所有主流IDE都支持 |
| 大型项目管理 | 吃力,subdirs模式有限 | 强,支持嵌套和模块化 |
| Qt版本支持 | Qt5及之前是默认 | Qt6开始是默认 |
| 社区生态 | 逐渐萎缩 | 活跃,资源丰富 |
你想想看,qmake最大的问题是什么?是它和Qt绑得太死了。你一旦用了qmake,整个项目的构建逻辑就离不开Qt。而CMake是通用的,你可以在同一个项目里混用Qt、Boost、OpenCV等各种库,CMake都能搞定。
我记得有一次,一个客户要求把Qt项目集成到他们已有的CMake构建体系里。我花了整整两天才把qmake的.pro文件翻译成CMakeLists.txt。从那以后,我新项目一律用CMake。
3.3 迁移策略
如果你决定从qmake迁移到CMake,别慌。我给你一套我实践过的迁移步骤:
- 先评估项目规模:如果项目只有几个文件,手动重写CMakeLists.txt就行。如果项目有上百个文件,建议用工具辅助。
- 使用qmake2cmake工具:Qt官方提供了一个叫
qmake2cmake的Python脚本,可以自动转换。但别指望它100%完美,转换后需要手动调整。 - 手动调整关键配置:比如自定义构建步骤、第三方库路径、平台特定配置等,这些通常需要手动处理。
- 逐步验证:不要一次性迁移整个项目。先迁移一个子模块,编译通过后再迁移下一个。
下面是一个简单的CMakeLists.txt示例,对应前面那个.pro文件:
cmake_minimum_required(VERSION 3.16)
project(MyApp VERSION 1.0.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_add_executable(MyApp
main.cpp
mainwindow.cpp
mainwindow.h
mainwindow.ui
resources.qrc
)
target_link_libraries(MyApp PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Widgets
)
你看,CMake的写法其实也不复杂。而且它有一个巨大的优势:find_package机制。你不需要手动指定Qt的路径,CMake会自动找到系统上安装的Qt版本。
$$PWD和$$OUT_PWD的路径引用。这些在CMake里没有直接对应,需要用CMAKE_CURRENT_SOURCE_DIR和CMAKE_CURRENT_BINARY_DIR来替代。千万别漏了,否则编译会报找不到文件。
还有一个常见问题:qmake里的CONFIG += static,在CMake里对应的是set(CMAKE_BUILD_TYPE Static)或者通过target_compile_definitions来设置。嗯,这里要注意,静态编译还需要链接Qt的静态库,这个在CMake里要额外配置。
最后说一句:迁移不是一蹴而就的事。我建议你先把项目的构建逻辑理清楚,再动手。如果项目还在活跃开发中,可以先用CMake和qmake并行维护一段时间,等稳定了再彻底切掉qmake。
.pro文件。
可可精品资料库