【Qt】Qt 构建系统详解:qmake 入门到项目实战
Qt 构建系统详解:qmake 入门到项目实战
本文将系统介绍 Qt 构建工具
qmake
的用法,并通过一个完整的项目结构示例,帮助你掌握.pro
文件编写、子项目管理、模块依赖等核心技能。
🧭 一、什么是 qmake?
qmake
是 Qt 提供的跨平台构建系统工具,它能将 .pro
文件(项目描述)转换为对应平台的构建脚本,如 Makefile 或 Visual Studio 工程文件。
✅ 主要作用:
- 自动生成构建脚本,简化项目编译流程
- 跨平台(支持 Windows / Linux / macOS)
- 适用于中小型 Qt 项目,快速上手
🔁 常见使用流程:
qmake myapp.pro # 生成 Makefile
make # 或 mingw32-make / nmake
📘 二、.pro
文件基础语法
1. 基本结构
TEMPLATE = app # 类型:app 或 lib
TARGET = myapp # 输出文件名
QT += core gui # 使用的 Qt 模块
CONFIG += c++11 # 编译配置
SOURCES += main.cpp # 源码文件
HEADERS += mainwindow.h
FORMS += mainwindow.ui # UI 文件
RESOURCES += resources.qrc
2. 常用变量
变量名 | 含义 |
---|---|
QT | 指定使用的 Qt 模块(如 core , gui ) |
CONFIG | 构建配置,如 debug , release , c++11 |
SOURCES | 源文件列表 |
HEADERS | 头文件列表 |
FORMS | Qt Designer 设计的 .ui 文件 |
RESOURCES | Qt 资源文件 .qrc |
INCLUDEPATH | 额外的头文件搜索路径 |
LIBS | 链接外部库,如 -L 和 -l |
DEFINES | 添加宏定义 |
3. 条件语句(平台判断)
unix {LIBS += -lm
}
win32 {CONFIG += console
}
🧩 三、子项目管理(SUBDIRS)
大型项目通常包含多个模块,比如主程序和自定义库。我们可以使用 subdirs
模板组织它们。
🛠️ 四、完整项目结构实战
📁 项目结构
MyProject/
├── MyProject.pro # 顶层项目文件
├── mylib/ # 自定义库
│ ├── mylib.pro
│ ├── mylib.h
│ └── mylib.cpp
└── mainapp/ # 主程序├── mainapp.pro├── main.cpp├── mainwindow.h├── mainwindow.cpp└── mainwindow.ui
🧷 1. 顶层文件 MyProject.pro
TEMPLATE = subdirs
SUBDIRS += mylib mainappmainapp.depends = mylib # 指定构建顺序
🧷 2. mylib/mylib.pro
(静态库)
TEMPLATE = lib
CONFIG += staticlib
TARGET = mylibHEADERS += mylib.h
SOURCES += mylib.cpp
mylib.h
#ifndef MYLIB_H
#define MYLIB_H#include <QString>class MyLib
{
public:static QString getMessage();
};#endif // MYLIB_H
mylib.cpp
#include "mylib.h"QString MyLib::getMessage()
{return "Hello from MyLib!";
}
🧷 3. mainapp/mainapp.pro
(主程序)
TEMPLATE = app
QT += core gui widgets
CONFIG += c++11
TARGET = mainappSOURCES += main.cpp \mainwindow.cpp
HEADERS += mainwindow.h
FORMS += mainwindow.uiINCLUDEPATH += ../mylib
LIBS += -L../mylib -lmylib
main.cpp
#include "mainwindow.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication app(argc, argv);MainWindow w;w.show();return app.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>class QLabel;class MainWindow : public QMainWindow
{Q_OBJECT
public:MainWindow(QWidget *parent = nullptr);~MainWindow();
private:QLabel *label;
};#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QLabel>
#include "mylib.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)
{label = new QLabel(MyLib::getMessage(), this);setCentralWidget(label);
}MainWindow::~MainWindow() {}
mainwindow.ui
你可以使用 Qt Designer 可视化编辑此文件,也可以先跳过(不影响构建)。
🔨 五、构建步骤(命令行)
在项目根目录执行:
qmake MyProject.pro
make # Windows 可用 mingw32-make 或 nmake
🎯 六、qmake 与 CMake 对比
特性 | qmake | CMake(Qt 6 推荐) |
---|---|---|
学习曲线 | 简单 | 较复杂 |
项目规模 | 适合中小型项目 | 更适合大型项目 |
官方支持 | Qt 5 推荐使用 | Qt 6 起默认使用 CMake |
功能扩展性 | 限制多一些 | 更强(模块化、测试集成等) |
✅ 总结
qmake
是 Qt 提供的构建系统,简洁、易上手,是管理 Qt 项目的传统利器。- 熟练使用
.pro
文件可以大大提升项目维护效率。 - 对于大型项目,建议使用
subdirs
管理模块。 - Qt 6 官方已推荐使用 CMake,新项目可考虑迁移。
📎 附加建议
- 可以借助 Qt Creator 编辑
.pro
文件并一键构建,开发体验更佳。 - 如果你正在使用 CMake,也可以对照迁移这套结构,后续我也可以提供 CMake 版本的实现。
📘提问环节
❓TEMPLATE = subdirs 什么意思?
TEMPLATE = subdirs
是 Qt 的构建工具 qmake 中的一种特殊模板,表示:
这个
.pro
文件不是一个可执行程序或库,而是一个“项目集合”,用于组织和管理多个子项目(子模块)的构建。
🧩 它的用途是什么?
当你要管理多个 .pro
项目(比如主程序 + 自定义库),就可以用一个 subdirs
类型的 .pro
文件统一管理它们的构建顺序和依赖关系。
📁 举个例子
项目结构:
MyProject/
├── MyProject.pro ← 这是 subdirs 项目
├── mylib/
│ └── mylib.pro
└── mainapp/└── mainapp.pro
MyProject.pro
内容:
TEMPLATE = subdirs # 告诉 qmake:这是一个子项目集合
SUBDIRS += mylib mainapp # 包含两个子项目mainapp.depends = mylib # 设置依赖顺序(先构建 mylib,再构建 mainapp)
🧠 工作机制
qmake MyProject.pro
会读取所有列出的子项目并为它们分别生成 Makefile。- 构建时会 自动递归编译每一个子项目。
- 通过
xxx.depends = yyy
设置依赖顺序(例如主程序依赖库)。
✅ 常见 TEMPLATE 类型对比
TEMPLATE 类型 | 用途 |
---|---|
app | 构建一个可执行程序 |
lib | 构建一个静态或动态库(.a/.so/.lib/.dll) |
subdirs | 管理多个 .pro 项目的集合 |
📌 总结
TEMPLATE = subdirs
通常出现在项目的顶层,用于组织多个子项目。- 它本身不包含代码,只是构建配置的集合。
- 与 CMake 中的
add_subdirectory()
有相似之处。
❓为什么顶层 .pro
文件中 没有 TARGET
?
这是一个非常关键且容易混淆的问题,下面我来系统解释,因为:
当你使用
TEMPLATE = subdirs
时,顶层.pro
文件本身不是一个编译目标,不会生成可执行文件或库文件,因此不需要也不能设置TARGET
。
✅ 解释:
TEMPLATE = subdirs
表示:这个.pro
文件只是一个项目容器,用来组织和管理子项目的构建流程。- 它的职责是告诉
qmake
:我要构建哪些子项目,它们的依赖关系是什么。 - 子项目才是真正参与构建(生成目标文件)的单元。
🧱 对比不同 TEMPLATE
TEMPLATE 类型 | 是否需要 TARGET | 说明 |
---|---|---|
app | ✅ 是 | 表示要生成一个可执行文件,需要指定名称 |
lib | ✅ 是 | 表示要生成一个静态库或动态库 |
subdirs | ❌ 否 | 不生成实际构建产物,仅组织子项目 |
📁 示例补充
# MyProject.pro
TEMPLATE = subdirs
SUBDIRS += mylib mainapp
mainapp.depends = mylib
你看到这里没有:
TARGET = ...
原因是:MyProject.pro 不是一个“要编译的项目”,而是“告诉 qmake 去编译哪些项目”。
✅ 小结
subdirs
类型的.pro
文件不需要TARGET
。- 它只是一个组织者,控制构建顺序和包含的模块。
- 只有真正的可执行程序或库项目,才需要指定
TARGET
。
❓子项目中为啥TARGET的名称要和文件夹同名?
这是一个非常好的问题,涉及到 qmake
中的 TARGET
变量含义 与 模块组织逻辑,我们来仔细说明:
✅ TARGET
的本质含义
在 .pro
文件中:
TARGET = something
表示 生成的可执行文件名或库文件名,不直接等于目录名。
🔎 示例对比说明
设想我们有如下结构:
MyProject/
├── mylib/
│ ├── mylib.pro ← 这里 TARGET = mylib
├── mainapp/
│ ├── mainapp.pro ← 这里 TARGET = mainapp
虽然子项目文件夹分别叫做 mylib
和 mainapp
,但你可以自由设置 TARGET
为任何你想要的名字,比如:
# mylib.pro
TARGET = my_custom_library_name# mainapp.pro
TARGET = awesome_gui_app
构建完成后:
- 在 Linux:会生成
libmy_custom_library_name.a
(静态库)和awesome_gui_app
(可执行文件) - 在 Windows:生成
my_custom_library_name.lib
和awesome_gui_app.exe
🤔 那为什么很多人让 TARGET = 文件夹名
?
这是因为:
- 文件夹名和
TARGET
保持一致可以 减少认知负担 - 例如
mylib/
→TARGET = mylib
,容易管理产物、日志和代码 - 并非语法规定,而是 一种约定俗成的习惯
📌 总结
项 | 含义 |
---|---|
TARGET | 表示“构建产物的名称”(可执行文件或库名) |
子目录名 | 与 TARGET 可以相同,也可以不同 |
建议做法 | 建议保持一致,利于组织与维护 |
🎯 小技巧
查看帮助文档的时候,需要添加啥,文档中也会给出详细内容。
相关文章:

【Qt】Qt 构建系统详解:qmake 入门到项目实战
Qt 构建系统详解:qmake 入门到项目实战 本文将系统介绍 Qt 构建工具 qmake 的用法,并通过一个完整的项目结构示例,帮助你掌握 .pro 文件编写、子项目管理、模块依赖等核心技能。 🧭 一、什么是 qmake? qmake 是 Qt 提…...
Python实例题:pygame开发打飞机游戏
目录 Python实例题 题目 pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本 代码解释 初始化部分: 游戏主循环: 退出部分: 运行思路 注意事项 Python实例题 题目 pygame开发打飞机游戏 pygame-aircraft-game使用 Pygame 开发…...

《Zabbix Proxy分布式监控实战:从安装到配置全解析》
注意:实验所需的zabbix服务器的搭建可参考博客 zabbix 的docker安装_docker安装zabbix-CSDN博客 1.1 实验介绍 1.1.1 实验目的 本实验旨在搭建一个基于Zabbix的监控系统,通过安装和配置Zabbix Proxy、MySQL数据库以及Zabbix Agent,实现分…...

华为配置篇-RSTP/MSTP实验
MSTP 一、简介二、常用命令总结三、实验 一、简介 RSTP(快速生成树协议) RSTP(Rapid Spanning Tree Protocol)是 STP 的改进版本,基于 IEEE 802.1w 标准,核心目标是解决传统 STP 收敛速度慢的问…...

git如何将本地 dev 分支与远程 dev 分支同步
要让本地 dev 分支与远程 dev 分支完全同步(丢弃本地多余的提交记录),可以按照以下步骤操作: 1. 获取远程最新状态 git fetch origin dev # 拉取远程 dev 分支的最新提交,但不会修改本地代码 IDEA中点击fetc…...
使用Python和OpenCV实现实时人脸检测与识别
前言 在计算机视觉领域,人脸检测与识别是两个非常重要的任务。人脸检测是指在图像中定位人脸的位置,而人脸识别则是进一步识别出人脸的身份。随着深度学习的发展,这些任务的准确性和效率都有了显著提升。OpenCV是一个开源的计算机视觉库&…...

Unity基础学习(九)输入系统全解析:鼠标、键盘与轴控制
目录 一、Input类 1. 鼠标输入 2. 键盘输入 3. 默认轴输入 (1) 基础参数 (2)按键绑定参数 (3)输入响应参数 (4)输入类型与设备参数 (5)不同类型轴的参…...

QT:获取软件界面窗口的尺寸大小2025.5.8
在Windows系统中,获取软件界面窗口的尺寸大小可以通过多种方法实现,以下是基于不同场景的详细解决方案: 方法1:使用Windows API获取窗口尺寸 适用于获取外部应用程序窗口的尺寸(如记事本、计算器等)。 步…...

【ML-Agents】ML-Agents示例项目导入unity报错解决
最近在跑ML-Agents的示例代码,无奈往unity中导入项目后,就出现报错。本文简要描述了各个报错的解决方法。 文章目录 一、error CS0234: The type or namespace name InputSystem does not exist in the namespace UnityEngine (are you missing an assem…...
【网络安全】SQL注入
如果文章不足还请各位师傅批评指正! 想象一下,你经营着一家咖啡店,顾客可以通过店内的点单系统下单。这个系统会根据顾客的输入,向后厨发送指令,比如“为顾客A准备一杯拿铁”。 然而,如果有个不怀好意的顾客…...

Transformer Decoder-Only 参数量计算
Transformer 的 Decoder-Only 架构(如 GPT 系列模型)是当前大语言模型的主流架构,其参数量主要由以下几个部分组成: 嵌入层(Embedding Layer)自注意力层(Self-Attention Layers)前馈…...

uni-app 中的条件编译与跨端兼容
uni-app 为了实现一套代码编译到多个平台(包括小程序,App,H5 等),引入了条件编译机制。 通过条件编译,我们可以针对不同的平台编写特定的代码,从而实现跨端兼容。 一、条件编译的作用 平台差异…...
<C#>log4net 的配置文件配置项详细介绍
log4net 是一个功能强大的日志记录工具,通过配置文件可以灵活地控制日志的输出方式、格式、级别等。以下是对 log4net 配置文件常见配置项的详细介绍: 根元素 <log4net> 这是 log4net 配置文件的根元素,所有配置项都要包含在该元素内…...
excel单元格如果是日期格式,在C#读取的时候会变成45807,怎么处理
excel单元格如果是日期格式,在C#读取的时候会变成45807,怎么处理 excel单元格如果是日期格式,在C#读取的时候会变成45807,怎么处理 在 C# 中,Excel 日期被表示为一个数字,这是因为 Excel 内部将日期存储为…...

Unity接入SDK之修改Unity启动页面
原理就是在Android Studio新建Activity继承UnityPlayerActivity,然后再Unity中修改启动页面。 一,Android Studio篇 首先新建一个项目, 新建完成之后基于新建的项目新建一个module,选择为Android Library类型 新建的Library再目…...

yarn workspace使用指南
作用 Yarn workspace 是 Yarn 包管理工具中的一个功能,主要用于管理多包项目(monorepo)。它的主要作用如下: 支持多包结构:允许在一个仓库中管理多个独立的包或项目。项目间依赖管理:方便地在不同包之间添…...
[学习]RTKLib详解:datum.c、download.c与lambda.c
RTKLib详解: datum.c、download.c 与 lambda.c 本文是 RTKLlib详解 系列文章的一篇,目前该系列文章还在持续总结写作中,以发表的如下,有兴趣的可以翻阅。 [学习] RTKlib详解:功能、工具与源码结构解析 [学习]RTKLib详解ÿ…...

VUE el-select下拉框动态设置禁用,删除后恢复可选择
场景:点击新增添加按钮,列表table会新增一条包含下拉菜单的数据,如果其中任何一个下拉框选择了某个值,那么新增的下拉菜单的选项中该值是禁用状态,只能选择其他未被选中过的值。点击删除按钮后,已禁用的选项…...

FPGA----基于ALINX提供的debian实现TCF
引言:接上问,我们使用自制的image.ub和boot.bin以及ALINX提供的debian8根文件系统,构建了petalinux,但是经测试,该文件系统无法启用TCF服务,即无法与Xilinx SDK建立连接,那么我们应该如何解决? FPGA----基于ZYNQ 7020实现定制化的EPICS通信系统-CSDN博客文章浏览阅读4…...

木马查杀篇—Opcode提取
【前言】 介绍Opcode的提取方法,并探讨多种机器学习算法在Webshell检测中的应用,理解如何在实际项目中应用Opcode进行高效的Webshell检测。 Ⅰ 基本概念 Opcode:计算机指令的一部分,也叫字节码,一个php文件可以抽取出…...
1.7 方向导数
(底层逻辑演进脉络)从"单车道"到"全路网"的导数进化史: 一、偏导数奠基(1.6核心) 诞生背景:多元函数分析需求 当变量间存在耦合关系时(如房价面积单价装修成本)…...
设计模式系列(01):总览与引导
设计模式系列(01):总览与引导 本文为设计模式系列第1篇,定位为总览和引导,系统梳理设计模式的核心思想、分类、UML、设计原则、典型场景、学习建议与常见误区,适合系统学习与团队协作。 目录 1. 前言2. 设计模式简介3. UML与设计模式4. 术语解释5. UML工具与PlantUML6. 面…...

国产化Excel处理控件Spire.XLS系列教程:如何通过 C# 删除 Excel 工作表中的筛选器
在 Excel 文件中,筛选器(Filter)是一个常用的数据处理工具,可以帮助用户快速按条件筛选数据行。但在数据整理完成、导出、共享或打印之前,往往需要 删除 Excel 工作表中的筛选器,移除列标题中的下拉筛选按钮…...
第二篇 客户端脚本安全
同源策略 限制了来自不同的"dociment"或脚本,对当前"dociment"读取或设置一些属性。 不同源:host(域名或ip),子域名,端口,协议。 对于当前页面来说,页面的源…...

[sklearn] 特征工程
一.字典数据抽取 def dictvec():"""字典数据抽取:return: None"""# 实例化# sparse改为True,输出的是每个不为零位置的坐标,稀疏矩阵可以节省存储空间dict DictVectorizer(sparseFalse) #矩阵中存在大量的0,sparse存储只…...

CI/CD与DevOps流程流程简述(提供思路)
一 CI/CD流程详解:代码集成、测试与发布部署 引言 在软件开发的世界里,CI/CD(持续集成/持续交付)就像是一套精密的流水线,确保代码从开发到上线的整个过程高效、稳定。我作为一名资深的软件工程师,接下来…...

S7-1500——零基础入门1、工业编程基本概念
工业编程基本概念 一,数制与基本数据类型二,数字量信号三,模拟量信号一,数制与基本数据类型 本节主要内容 类别内容主题数制与基本数据类型数制讲解十进制、十六进制、二进制及其进位规则;基数、位权概念数据类型介绍PLC 使用的数据类型:未序列数据类型(bit、byte、wor…...

六、快速启动框架:SpringBoot3实战
六、快速启动框架:SpringBoot3实战 目录 一、SpringBoot3介绍 1.1 SpringBoot3简介1.2 系统要求1.3 快速入门1.4 入门总结 二、SpringBoot3配置文件 2.1 统一配置管理概述2.2 属性配置文件使用2.3 YAML配置文件使用2.4 批量配置文件注入2.5 多环境配置和使用 三、…...

万兴PDF-PDFelement v11.4.13.3417
万兴PDF专家(Wondershare PDFelement)是一款国产PDF文档全方位解决方案.万兴PDF编辑器软件万兴PDF中文版,专注于PDF的创建,编辑,转换,签名,压缩,合并,比较等功能.万兴PDF专业版PDF编辑软件,以简约风格及强大的功能在国外名声大噪,除了传统功能外,还提供OCR扫描,表格识别,创建笔…...
LSP里氏替换原则
LSP强调子类必须能够替换父类。即子类应该具有与父类相同的行为和功能,而不仅仅是继承父类的属性和方法。LSP是对继承机制的约束规范、是指导接口与实现的设计原则。 LSP关键点 前置条件不能强化:子类方法的参数类型必须与父类相同或者更为宽松。后置条…...