一群人手把手其实就是我自己带了很多个刚接触 Qt 的开发者做项目发现最容易劝退新人的往往不是信号槽语法也不是事件循环而是“项目能建出来但编译不过去”这种打击感。明明代码跟例子一模一样点运行却蹦出一堆看不懂的红色错误排查半天连问题出在哪个环节都说不清楚。这篇是“Qt 编程”系列的第一篇核心就讲透一件事Qt 项目是怎么创建、怎么编译、怎么变成可执行程序的。我把从安装配置到构建链路的每一步拆开结合大量实操中踩过的坑来讲适合刚入门 C 想学图形界面开发的人也适合那些平时只点“运行”按钮、但一旦报错就手足无措的开发者。看完这篇你会知道 Creator 替你做了什么、底层发生了什么、出问题该去哪一环找。写之前先说清楚整体思路我写的不是“照着点一遍”的操作手册而是把每个选择背后的“为什么”也讲掉。这样你换一台机器、换一个 Qt 版本甚至换一个构建系统都不会慌。1. Qt项目创建前的软件环境准备很多人喜欢跳过环境准备直接写代码结果第一个坑就踩在装什么、怎么装上。Qt 不是一个小库它的安装包里混合了编译器、调试器、构建工具、GUI 库、平台插件和大量示例配错一个组件后面全盘皆输。1.1 版本选择与安装组件的理性决策打开 Qt 官方下载页面面对“Qt 5.15”“Qt 6.5”“Qt 6.8”这些版本号新人通常不知道怎么选。我的建议很直接如果是纯新手优先选 6.5 以上的 LTS 版本如果是接手老项目跟着项目要求走就好。5.15.2 是 5.x 时代最后一个大版本如今很多存量项目还在维护但新开项目再用它多少有点“新瓶装旧酒”的意思。6.x 相比 5.x 有不少变化最明显的是图形架构变了事件循环内部也有重构。不过对我们这篇讲创建与编译的内容来说qmake 和 CMake 的基本流程几乎一致。你完全不用担心“学了 5 的创建流程到 6 就不适用了”不会的。选好版本后安装器会列出一长串组件。这里有几个关键点需要解释一下编译器组件Qt 是 C 库必须搭配一个编译器才能用。Windows 上最常见的选择是 MSVC即 Visual Studio 里的那个编译器和 MinGW一个 GCC 在 Windows 上的移植版本。Qt 库本体每个编译器只对应一份预编译好的 Qt 库比如“Qt 6.5.3 MSVC 2019 64-bit”和“Qt 6.5.3 MinGW 11.2.0 64-bit”是两份不同的 Qt 二进制包不能混用。构建工具建议勾选“CMake”和“Ninja”因为 Qt 6 默认构建系统就是 CMake Ninja。即使你后面打算用 qmakePre-built 环境里把这些工具备齐也没坏处。实操中发现很多人安装时嫌麻烦只勾了某一个 Qt 库版本没有勾对应的工具链结果进入 Qt Creator 后发现“Kit”列表里全是黄色感叹号编译按钮直接变灰。所以安装时宁可多花费一点磁盘空间也别漏组件。如果在安装器里看到“Qt Creator”和“Qt 工具链”的分区全部展开按需勾选即可。1.2 构建套件Kit的三件套编译器、Qt库、调试器Qt Creator 里的核心概念叫“Kit”构建套件。换句话说一套可用的构建环境至少要有三样东西C 编译器负责把源代码翻译成机器码。Windows 下可能是 MSVC也可能是 MinGW。Qt 版本负责提供 Qt 的头文件、库文件.lib / .dll / .a和界面工具。调试器负责打断点、看变量MinGW 配套的是 GDBMSVC 配套的是 CDB。这三者必须“口径统一”不是说随便拉一个就能拼起来。最典型的坑是你在 Visual Studio 里用 MSVC 写好了静态库结果新项目套了个 MinGW 的 Kit链接的时候报一堆“无法解析的外部符号”。这就是二进制接口不兼容。MSVC 和 MinGW 生成的代码结构和符号修饰规则完全不同Qt 库同样如此你安装的是 MSVC 版就必须用 MSVC 版 Kit。判断一个 Kit 是否正常打开 Creator 的“工具→选项→Kits”就能看到。图标正常、没有黄色警告说明编译器、Qt 版本和调试器识别成功了。注意“Qt 版本”标签页里有一个“qmake 路径”这个路径必须指向 Qt 安装目录下的实际路径比如C:\Qt\6.5.3\mingw_64\bin\qmake.exe。如果路径不对哪怕 Creator 显示有 Kit构建时也会报找不到 Qt 模块。实践经验里还有一个易错点安装路径别带中文和空格。很多人喜欢建一个D:\项目代码\QtDemo这样的目录后面编译时你会发现编译器或者某些工具链对路径里带空格、中文非常敏感可能产生奇奇怪怪的“找不到文件”错误。最好统一放到纯英文路径例如D:\QtWorkspace。2. 从零创建第一个Qt Widgets项目环境准备好以后就可以打开 Qt Creator 新建项目了。我常用的是 Qt Widgets Application 模板因为它最直观有窗口、有按钮、有控件编译完马上能看到东西成就感来得快。2.1 新建项目向导全流程与关键选项进入 Creator 后点击“文件 → New File or Project”左侧分类选择“Application”再选“Qt Widgets Application”。这一步别去选“Qt Quick Application”或者“Empty qmake Project”前者带 QML 概念后者没有向导生成的示例代码新手起步会绕远路。向导会要求填“项目名称”和“创建路径”。项目名称必须用英文全小写风格是社区惯例比如demo_first_qt。路径则选择我们刚建立的干净英文目录。这一步里的“构建系统”有三个选项qmake、CMake、Qbs。我的建议是第一个项目先选 qmake因为 qmake 的工程文件就是一个简单的文本脚本逐行看下来非常容易理解。跑通了整个流程以后再换 CMake 去体会另一种组织方式这样知识结构会比较扎实。接着向导会让你选择“类名”和“基类”。默认会生成一个MainWindow基类是QMainWindow建议保留默认。“Create a .ui file”这个复选框默认是勾选的保留勾选因为我们想用拖拽的形式设计界面。“翻译文件”这一步可以不用选Qt Linguist 是为多语言界面准备的第一个项目里引入反而多余。最后的“Kit Selection”里勾选我们刚才确认过的那个可用 Kit。这里被勾中的 Kit 会决定最终生成 exe 的平台形式如果勾的是“Desktop Qt 6.5.3 MinGW 64-bit”那生成的就是 64 位程序。全部点击完成后Creator 会自动生成一套完整的项目结构和示例代码。你可以直接点左下角的绿色运行按钮马上看到一个有菜单栏和状态栏的空窗口出现在屏幕上。到这一步项目创建的基础流程就已经走通了。2.2 项目文件结构谁负责入口、谁负责界面、谁负责业务新建完的项目会包含几个关键文件很多教程只告诉你“点运行”却不解释这些文件是干嘛的。这里逐个说清楚。目录结构大致是这样demo_first_qt/ ├── demo_first_qt.pro ├── main.cpp ├── mainwindow.cpp ├── mainwindow.h └── mainwindow.uimain.cpp是程序入口里面创建了QApplication创建了MainWindow窗口对象调用show()显示窗口最后进入exec()事件循环。简单说这一段代码负责让界面“转起来”。mainwindow.h是主窗口的类声明。里面有一个很特别的宏Q_OBJECT它标志着这个类要接受 Qt 的元对象系统处理后面会细讲。mainwindow.cpp是主窗口的具体实现构造函数里有一行ui-setupUi(this)它的作用是把.ui文件里拖出来的所有控件实例化并挂到当前窗口上。mainwindow.ui是一个 XML 格式的界面描述文件。你在 Creator 的“设计”模式里拖一个按钮、改一个布局保存后全部写在这个文件里。.ui文件并不会被编译器直接编译。构建时Qt 的工具链会先把它翻译成一个 C 头文件名称类似ui_mainwindow.h里面是具体的布局代码。这个文件是自动生成的不需要你手动维护。很多新手会有疑问我为什么不在代码里手写控件反而要拖一个 XML 文件我的理解是.ui文件和手写代码不是二选一的关系而是一个强调可视化的分工。界面上控件摆得是否整齐、布局嵌套是否合理拖拽编辑往往比盲写代码直观得多清晰的.ui文件也对后续维护很友好。2.3 工程文件逐行解读qmake的pro文件qmake 项目的核心配置文件是.pro文件。Creator 在创建项目时已经帮你写好了基本框架打开看大概是这个样子QT core gui greaterThan(QT_MAJOR_VERSION, 4): QT widgets TARGET demo_first_qt TEMPLATE app SOURCES \ main.cpp \ mainwindow.cpp HEADERS \ mainwindow.h FORMS \ mainwindow.ui这六七个条目非常重要逐行解释QT core gui链接 Qt 基础模块。core 是核心非界面类gui 是图形界面基础类。Qt 5 以后界面控件被挪进了 widgets 模块所以下面需要判断版本再加一次。greaterThan(QT_MAJOR_VERSION, 4)这是 qmake 的版本判断语法。Qt 5 之前 widgets 类还在 gui 模块里Qt 5 之后必须单独链接 widgets所以加这一行保证跨版本兼容。TARGET指定生成的可执行程序名称这里会生成demo_first_qt.exe。TEMPLATE app告诉 qmake 这是一个应用程序项目不是库项目。如果要生成静态库或动态库应该写lib。SOURCES、HEADERS、FORMS三行分别声明项目里有哪些 C 源文件、头文件和界面文件。后面新添加文件时可以用右键项目树里的“添加新文件”Creator 会自动更新这三行。很多职场老手接手别人的 qmake 项目时第一件事就是看.pro文件确认它链接了哪些模块。模块没写全最常见的报错就是“找不到 QMainWindow”“找不到 QWidget 头文件”之类。比如你只是想在窗口里显示一张图片需要用到QAxObject之类的 ActiveX 类那就必须在QT 后面追加axcontainer而如果你用到 OpenGL要追加opengl。.pro文件决定编译器能看到哪些 Qt 头文件和库这是创建项目时就要养成的意识。3. 编译不再是“点一下运行”那么简单很多人在 Qt Creator 里一直点那个绿色三角却从没想过点下去的瞬间到底发生了什么。我建议每个学习 Qt 的人都手动走一遍编译流程只有亲手在命令行敲过 qmake 和 make才能在 Creator 报错时瞬间定位到故障环节。3.1 qmake经典手工编译链路的完整演示在讲解 Creator 的自动化编译前先做一次全手动演示。打开开始菜单里的“Qt 6.5.3 (MinGW 11.2.0) 64-bit”终端这个终端的环境变量是预配好的包含编译器路径和 Qt 工具路径。在终端里进入项目目录cd /d D:\QtWorkspace\demo_first_qt第一步先执行qmake这一步的作用是根据.pro文件生成 Makefile。Makefile 是一个“施工图”里面规定了要用哪些规则来编译所有源文件、哪些文件先生成、哪些文件后链接。第二步执行mingw32-make -j8mingw32-make是 GNU make 的 Windows 版本-j8表示用 8 个线程并行编译编译速度会有明显提升。这里的底层逻辑是make 工具按照刚才生成的 Makefile逐条执行 g 编译指令和链接指令最终生成目标 exe。编译完成后当前目录会多出若干中间产物和一个可执行文件Debug 模式下会有debug文件夹。输入程序名直接运行就能看到那个窗口弹出来debug\demo_first_qt.exe这套流程看似绕远路它的价值在于你知道了 Creator 的“运行”按钮本质上是先调用了类似qmake的工具生成构建规则再调用make或jom来完成编译链接。理解了这一步当构建报错时就能判断它到底是在qmake阶段失败工程文件的配置问题还是在make阶段失败源码语法问题或链接问题。如果还想指定编译类型可以在 qmake 时追加CONFIGreleaseqmake CONFIGrelease mingw32-make -j8这时 exe 会生成在release目录下。Debug 和 Release 的应用场景不同Debug 版体积大、速度慢但带调试信息方便打断点排查问题Release 版做了优化适合最终交付。日常练习时两边都可以正式发布优先 Release。3.2 用CMake构建Qt项目新主流的配置方式Qt 6 已经把官方推荐构建系统切换到了 CMake。如果你新建项目时选择了 CMake生成的内容不再是.pro文件而是一个CMakeLists.txt。它长这样cmake_minimum_required(VERSION 3.16) project(DemoFirstQt VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(Qt6 REQUIRED COMPONENTS Widgets) qt_standard_project_setup() qt_add_executable(DemoFirstQt main.cpp mainwindow.cpp mainwindow.h mainwindow.ui ) target_link_libraries(DemoFirstQt PRIVATE Qt6::Widgets)这段代码的作用和 qmake 的.pro文件大同小异但思路有些不同find_package(Qt6 REQUIRED COMPONENTS Widgets)CMake 会在系统里寻找 Qt6 的安装位置找到头文件和库的路径。qt_add_executable(...)声明要生成一个可执行程序明确包含哪些源文件和头文件。target_link_libraries(... PRIVATE Qt6::Widgets)告诉链接器链接时要带上 Qt6 的 Widgets 库。在命令行里也可以手动完成 CMake 构建流程是两条命令cmake -S . -B build cmake --build build第一条命令会创建build目录并在这目录里完成配置生成构建规则第二条命令按规则真正编译。这个build目录就是下一步要讲的“影子构建”产物。CMake 相比 qmake 的优势之一是生态通用性好你如果用 CMake 组织 Qt 项目以后想在这个项目里集成一些别的 C 库像 JSON 解析、图像处理库会顺滑得多因为那些库通常也提供了 CMake 的支持。qmake 更偏向 Qt 自家封闭生态简单够用但扩展外部依赖时略显吃力。3.3 Shadow Build为什么源码目录旁边会多一个奇怪文件夹用 Qt Creator 构建项目后你经常会发现工作目录里凭空多出一个像build-demo_first_qt-Desktop_Qt_6_5_3_MinGW_64_bit-Debug的文件夹。很多新手会困惑我明明没有创建这个文件夹它是什么这个机制叫“影子构建”翻译成英文是 Shadow Build。含义是构建生成的中间文件、Makefile、.o 目标文件、最终的 exe全部放到源码目录之外的一个独立目录里避免污染漂亮的源码结构。好处很明显可以同时构建 Debug 和 Release 两种配置互不干扰。源码目录永远是干净整洁的状态版本管理时不用排除一堆中间产物。想清理所有编译产物直接把 build 文件夹删掉即可不影响任何源码。代价也客观存在如果你不小心把项目拷到新位置或者改了.pro/CMakeLists.txt后没有重新跑构建某些旧缓存可能导致“找不到ui_mainwindow.h”“轮不到的 Makefile”之类的诡异错误。这时候别去怀疑代码逻辑先做一次“清理项目”或直接把 build 目录删掉重新构建九成问题会消失。3.4 moc编译器与信号槽机制的关系Qt 项目特有的一个流程新手一定要知道它不然遇到一堆vtable报错时完全摸不着头脑。C 本身没有“信号槽”这种东西。Qt 为了让对象之间能够方便地通信在 C 基础上做了一层元对象系统扩展。也就是说你的类如果声明了Q_OBJECT宏这个类的名称、信号、槽、属性等信息就会被额外记录成一张元信息表。Qt 的强大的connect、emit能力全都依赖这张表。而生成这张表的过程就需要一个叫mocMeta-Object Compiler元对象编译器的工具。在编译链路里moc被插入在正式编译之前。它扫描所有头文件找到含有Q_OBJECT的类自动生成一个moc_xxx.cpp文件然后在链接阶段把这个生成的文件一起编译并链接进程序。关键点在于这个moc_xxx.cpp是自动生成的你不要手动加到SOURCES里编译器工具链会自动处理。如果你在.pro文件里添加了一个新头文件但忘了把它放进HEADERS变量或者你的类声明了Q_OBJECT却没被列为头文件输出端就会看到恶心的链接错误比如undefined reference to vtable for MainWindow遇到这种错误不要慌沿着构建系统配置去排查头文件有没有加进工程、类里是否写了Q_OBJECT、刚才修改后有没有正确调用 qmake/cmake 重新生成构建规则。理解了moc的原理类似的元对象错误基本都能解决。4. 编译运行中的高频问题与排查经验最后把我在实际带人过程中最常见的几类问题整理出来基本覆盖了项目创建与编译这条链路上会踩的高频坑。每一条背后都有一段真实踩坑经历。4.1 中文乱码的正确处理姿势Windows 下用 MSVC 编译 Qt 项目时源码里写中文在界面上经常显示成乱码。这背后是两个世界打架的问题MSVC 编译器默认把源码按本地代码页通常是 GBK来解释而 Qt 6 内部多种默认编码是 UTF-8两边解读不一致中文自然就乱了。行内最快最稳的方案是在含中文字符串的源文件顶部加一行预处理指令#if defined(_MSC_VER) #pragma execution_character_set(utf-8) #endif但更推荐的做法是从源头养成习惯中文文本用QStringLiteral(你好)写或者直接把所有界面上要用的文案放到.ui文件/资源文件里而不是在代码里裸写字符串。资源文件按 UTF-8 管理Qt 加载时没问题后续做多语言翻译也方便这是一劳永逸的路径。4.2 找不到头文件、链接失败时的排查方向错误形如mainwindow.h: No such file or directory或者cannot find -lQt5Widgets前者多半是头文件路径没包含进来或者源文件里的#include mainwindow.h拼写错了再不然就是构建系统里没声明这个头文件需要检查.pro的HEADERS或CMakeLists.txt列表。后者是链接阶段找不到 Qt 库文件常见原因是构建套件选错或者QT 少加了模块。特别注意如果项目链接了Qt5Widgets但 Kit 里选的是 Qt6 版本路径不匹配链接器自然找不到库。换个思路先用一个新建的空窗口项目测试当前 Kit 是否能正常编译能通过的 Kit 再回过去跑目标项目可以快速排除套件层面的问题。4.3 应用程序无法正常启动0xc000007b与DLL问题Windows 上 Qt 程序最经典的一个报错是“应用程序无法正常启动 0xc000007b”。这个错误码的含义一般是“应用程序的位数与依赖的 DLL 位数不一致”。比如你编译生成了一个 64 位的 exe但运行时加载的Qt6Widgets.dll是 32 位版本系统就会弹这个错。排查思路确认 Creator 的“构建套件”里选的是 64 位。看构建输出中“配置”里的位数标识。确认你生成的构建文件夹和 Qt 库位数一致。64 位 Qt 安装目录名通常带_64后缀。正式发布时用 Qt 提供部署工具把相关 DLL 复制到 exe 目录这个后面讲到具体工具时再展开。还有一个小概率情况是系统缺少 Microsoft Visual C 运行库。MSVC 编译的程序依赖 VC 运行库如果目标电脑没有装也会报这种启动错误。开发机一般没事部署到别的电脑时常出现。4.4 程序运行起来但窗口空白或闪退窗口能弹出来但一片空白大多数时候不是运行问题而是你没给窗口设置中央部件。QMainWindow并不是直接往上面堆控件就行的它有一个“中央部件区”的概念。在构造函数里先这样写就不会空白ui-setupUi(this); setCentralWidget(ui-widget);如果程序一运行就闪退优先检查调试输出窗口里的崩溃信息定位到具体的空指针访问。最常见的原因是访问了尚未初始化的对象或构造函数里触发了某个信号槽而槽对象还没准备好。ui-setupUi一定要放在构造函数里最前面不要在它之前去操作ui指针。还有一个很容易忽略的崩溃原因Debug 和 Release 混用。比如你的主程序是 Debug 编译却链接了一个 Release 版的库或者反过来都会造成运行时奇奇怪怪的崩溃。保持队列统一是一个铁律一整套构建环境都要保持一致。4.5 常见问题速查表现象可能原因解决思路Kit 里有黄色感叹号没安装对应编译组件或 Qt 版本重新运行安装器补齐组件找不到ui_xxx.h.ui文件未编译或影子构建缓存异常清理构建目录重新构建undefined reference to vtableQ_OBJECT宏缺失或头文件未加入工程检查类声明检查 HEADERS/CMakeLists程序乱码编码问题MSVC 默认代码页与 Qt 不一致用 UTF-8BOM 或QStringLiteral双击 exe 提示缺 DLL未使用部署工具或 Qt 库没拷贝运行时把 Qt 的 bin 目录加入 PATH或做部署构建成功但点运行没反应Debug 与 Release 混用或启动目录不对确认构建套件配置检查运行目录下的依赖排查时有一个很实用的习惯看构建输出窗口的最上面和最下面。最上面那几行通常能看出 Creator 正在调用的命令到底是qmake还是cmake最下面那几行是错误摘要。中间那一大堆红色的字因为编译体系压缩输出的原因未必精准对应到代码行反而会误导新手。如果你能快速确认“qmake 这一步过了make 这一步没过”问题范围就会缩小一半。写在最后环境是软件工程的另一半我自己带新人时最喜欢看他们第一次成功弹出一个带菜单栏的窗口时的表情。那个窗口虽然什么都没有但它背后走通了编译器、元对象系统、事件循环这一整条链路。从那时起他们就建立起了一种信心“以后不管报什么错我至少知道它发生在哪个环节。”如果你打算系统地学 Qt我会建议把这篇“创建与编译”当成地基反复练习到闭着眼都能搭出一套干净环境。然后下一篇文章我会顺着信号槽机制展开聊那也是 Qt 最有魅力的部分之一。期望读者看完后能带着自己的小项目来我们一起把这块硬骨头啃完。