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等。
小技巧:如果你需要区分Debug和Release的配置,可以用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。

核心观点:qmake适合小项目、快速原型、Qt-only项目。CMake适合中大型项目、多库依赖、跨平台部署。

3.3 迁移策略

如果你决定从qmake迁移到CMake,别慌。我给你一套我实践过的迁移步骤:

  1. 先评估项目规模:如果项目只有几个文件,手动重写CMakeLists.txt就行。如果项目有上百个文件,建议用工具辅助。
  2. 使用qmake2cmake工具:Qt官方提供了一个叫qmake2cmake的Python脚本,可以自动转换。但别指望它100%完美,转换后需要手动调整。
  3. 手动调整关键配置:比如自定义构建步骤、第三方库路径、平台特定配置等,这些通常需要手动处理。
  4. 逐步验证:不要一次性迁移整个项目。先迁移一个子模块,编译通过后再迁移下一个。

下面是一个简单的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版本。

避坑指南:我曾经在迁移一个老项目时,发现qmake里用了很多$$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。

总结:qmake是过去,CMake是未来。如果你还在用qmake,别焦虑,慢慢迁。如果你刚开始一个新项目,直接上CMake,省得以后折腾。
qmake → CMake 迁移决策流程图 现有qmake项目 项目规模评估 文件数 < 50? 是 手动重写 CMakeLists.txt 否 使用工具 qmake2cmake 手动调整:路径、第三方库、自定义步骤 CMake项目完成
个人建议:迁移过程中,保持qmake和CMake两套构建文件并行。这样万一CMake那边出了问题,你还能切回qmake快速修复。等CMake版本稳定运行一个月后,再删掉.pro文件。

可可精品资料库