编写工具调用windeployqt+ldd为msys2 Qt应用程序生成完整发布包

news2025/5/15 0:20:37

文章目录

    • 概要
    • 整体架构流程
    • 技术名词解释
    • 技术细节
      • 1. 界面设计
      • 2. 递归枚举文件
      • 3. 运行windeployqt
      • 4. 运行ldd并拷贝文件
      • 5. 驱动流程
    • 小结
    • 完整工程链接

概要

在windows下,动态链接库一直是发布Qt程序最为头痛的问题。在msys2环境下,尤其如此。msys2的windeployqt工具无法递归的发布所有依赖库到目标文件夹,导致需要手工的拷贝很多依赖项,非常繁琐。一种讨巧的方法是一股脑拷贝所有dll:

拷贝所有dll到文件夹
运行程序
删除所有dll
保留下来删不掉的就是必须库

但这个方法易漏掉文件。主要原因是有些dll是延迟加载的。比如QtSQL模块postgresql插件,其实依赖着libpq.dll,而 libpq.dll自身也有一堆依赖。只有在主程序里创建了QPSQL类型的连接,才会短期加载这个dll。如果无法在潜在依赖项完全占用的状态下执行删除,则很可能会删除原本有用的文件。

一旦出现上述情况,就只能通过ldd递归的分析并找到所有依赖。这个工作非常考研耐心。本着爱造工具的猿思维,通过本文开发一个Qt工具,在msys2开发模式下,帮助程序员快速生成一个绿色版的完整发布包。

整体架构流程

我们开发一个工具叫做“msys2qtdeployplus”,也就是帮助msys2发布qt的增强工具。它会遵循如下流程,完成发布:

  1. 开发者把待发布的二进制文件拷贝到一个文件夹下,叫做"target_foler"。
  2. 一些复杂项目,可能依赖很多子文件夹下的其他包,这些文件夹定义为“extra_folders”,用分号分割.
  3. 工具首先递归枚举上述两类文件夹下的所有可执行文件、dll,对每个文件以target_foler为目的文件夹,执行
windeployqt --dir target_foler driver:/path/to/file.exe
  1. 工具多次递归枚举上述文件夹内的所有可执行文件、dll,对每个文件执行 ldd,并捕获其输出。
  2. 对每组ldd输出依赖,工具分析那些位于msys2系统环境下的文件,并拷贝到target_foler。
  3. 如果本轮结束后,发生了新的拷贝动作,说明有新的依赖被发布到target_foler。此时,要转到3继续下一轮枚举。
  4. 结束。

经过这样的方法,等于是递归的把所有dll、exe的依赖都找齐了。

技术名词解释

  1. msys2:是一个独立的软件包管理系统,它提供了一个类似于Linux的shell环境和丰富的软件包库。Qt则是一个跨平台的C++图形用户界面应用程序开发框架,广泛用于开发GUI程序和开发工具。下面将详细介绍使用msys2环境搭配Qt的优势:
    (1) 软件包管理pacman工具:msys2提供了pacman命令行工具,可以方便地安装、升级和管理软件包。该工具是滚动更新,由一系列强大的自动化编译机器人维护,始终向Git最新社区进度看齐。通过pacman可以轻松安装Qt及其IDE Qt Creator,以及其他开发所需工具。不但如此,大量Linux下的GNU软件库都能直接调用,显著强化了windows下的编程体验。
    (2) 优化的性能表现:使用MinGW-w64编译器,可以在Windows平台上获得接近原生的性能。
    (3) Qt5支持静态链接库:msys2支持安装Qt的静态库版本,这对于创建不需要额外依赖的独立可执行文件非常有用。(Qt6暂时缺少完善的静态支持)
    (4) 跨平台一致性开发体验:在Windows上模拟类Unix环境,使得开发者在本地就能享受到接近目标Unix平台的开发体验。

技术细节

1. 界面设计

界面采用Qt原生界面,较为简单:

GUI这个界面上,

  • TargetFolder是发布的文件夹
  • Extra Folders是存放相关其他二进制依赖的文件夹
  • MSYS2指定本地msys2的安装文件夹。
  • PATH的两个控件
    – 第一个用于微调一些第三方依赖,以绕过msys2(如使用了第三方的libfftw)。这些路径会追加到PATH的最前边。
    – 第二个用于为某些二进制提供完整的依赖位置,比如有些dll没有第三方库,ldd会崩溃。

点击:run开始执行,执行的进度在左侧,外部程序的输出在右侧显示。

2. 递归枚举文件

采用一个简单的递归枚举函数枚举所有文件夹下的exe\dll

void DlgQtDeplus::enumAllExes(QString folder,QFileInfoList * pLst)
{
	QDir dir_target(folder);
	QStringList lstExecTypes;
	lstExecTypes << "*.dll";
	lstExecTypes << "*.exe";
	QFileInfoList lstExec = dir_target.entryInfoList(lstExecTypes);
	pLst->append(lstExec);

	lstExecTypes.clear();
	lstExecTypes<<"*";
	lstExecTypes<<"*.*";
	lstExec = dir_target.entryInfoList(lstExecTypes);
	foreach(QFileInfo info, lstExec)
	{
		if (info.isDir())
		{
			if (!info.fileName().startsWith("."))
			{
				enumAllExes(info.absoluteFilePath(),pLst);
			}
		}
	}
}

3. 运行windeployqt

使用QProcess可以方便的运行windeployqt

int DlgQtDeplus::run_deployqt()
{
	//Enum all exe in target folder
	QFileInfoList lstExec;
	enumAllExes(ui->lineEdit_targetFolder->text(),&lstExec);
	foreach(QFileInfo info, lstExec)
	{
		QProcess * call_process = new QProcess(this);
		call_process->setProgram("windeployqt.exe");
		QStringList args;
		args<<"--dir";
		args<<ui->lineEdit_targetFolder->text();
		args<<info.absoluteFilePath();
		call_process->setArguments(args);
		call_process->start();
		call_process->waitForStarted();
		call_process->waitForFinished();
		call_process->deleteLater();
	}

	return 0;
}

4. 运行ldd并拷贝文件

通过分析ldd的输出,可以拷贝msys2的文件到target_folder, 并返回本轮成功拷贝的文件个数。

int DlgQtDeplus::run_ldd()
{
	static QRegularExpression exp("[\\ \\n\\r\\=\\>)()]");
	QFileInfoList lstExec;
	enumAllExes(ui->lineEdit_targetFolder->text(),&lstExec);
	int cp = 0;
	QFileInfo infod(ui->lineEdit_targetFolder->text());
	QString pathM2 = ui->lineEdit_msys2->text();
	foreach(QFileInfo info, lstExec)
	{
		ui->progressBar_bar->setValue(c*1000/lstExec.size());
		QProcess * call_process = new QProcess(this);
		call_process->setProgram("ldd.exe");
		QStringList args;
		args<<info.absoluteFilePath();
		call_process->setArguments(args);
		call_process->start();
		call_process->waitForStarted();
		call_process->waitForFinished();
		if (call_process->bytesAvailable())
		{
			QString str = QString::fromUtf8(call_process->readAllStandardOutput());
			QStringList lstDeps = str.split(exp);
			foreach(QString dep, lstDeps)
			{
				if (dep.startsWith("/ucrt64/")||dep.startsWith("/msys64/"))
				{
					QFileInfo info(pathM2+dep.trimmed());
					QString tar(infod.absoluteFilePath()+"/"+info.fileName());
					QFile file(pathM2+dep.trimmed());
					if (file.copy(tar))
						++cp;
				}
			}
		}
		call_process->deleteLater();
	}
	return cp;
}

5. 驱动流程

在按钮响应函数中,调用上述两个过程,完成功能实现。


void DlgQtDeplus::on_pushButton_run_clicked()
{
	run_deployqt();
	while ((!stopcmd) &&run_ldd())
	{
		QCoreApplication::processEvents();
	}
}

小结

这个工具需要在与待发布的可执行文件相一致的QtCreator环境里执行。 一致的执行环境是指类似msys64,ucrt64这样的环境。代码里目前只支持这两种,当然想支持更多,只要添加一下判断语句即可。执行效果:
deploy可以看到,在sqldrivers下的所有数据库驱动的依赖项也被发布了。imageformats的各种依赖也都存在了。如果不拷贝完整,可能有的图标格式就显示不出来,还有些SQL数据库就连不上。

总之,通过windeployqt可以拷贝Qt直接依赖的所有DLL、文件夹结构到目标文件夹;使用ldd可以递归拷贝上述所有二进制素材的依赖树,从而完成功能。

完整工程链接

请参考 gitcode.com 或者 gitcode.net.

PS. 啥时候上面两个网站先得挂一个。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1830774.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ArcGIS Pro SDK (三)Addin控件 3 事件功能类

22 ArcGIS Pro 放置处理程序 22.1 添加控件 22.2 Code 放置处理程序可以实现文件拖动放置、TreeVIew、ListBox等控件拖动放置功能&#xff0c;此处新建一个停靠窗并添加一个TreeVIew&#xff0c;实现节点拖动事件&#xff1b; TestDropHandlerDockpane.xaml <UserContro…

开源项目推荐

这个资源列表集合了.NET开发领域的优秀工具、库、框架和软件等&#xff0c; 如果您目前研究开源大模型项目&#xff0c;请参考热门开源大模型项目推荐链接如下&#xff1a;https://blog.csdn.net/hefeng_aspnet/article/details/139669116 欢迎各位小伙伴收藏、点赞、留言、评论…

一文学会消息中间件的基础知识

什么是消息队列 队列数据结构 我们都学习过数据结构与算法相关的内容,消息队列从数据结构来看,就是一个由链表或是数组构成的一个先进先出的数据容器。由链表实现还是数组实现都没关系,它只要满足数据项是先进先出的特点,那么就可以认为它是一个队列结构。队列是只允许在…

个人云服务器已经被安全合规等卡脖子 建议不要买 买了必定后悔 安全是个大问题 没有能力维护

我的想法 自己买一个云服务器&#xff0c;先自己边做边学习&#xff0c;向往硅谷精神&#xff0c;财富与自由。如果能赚钱&#xff0c;就开个公司。这次到期就放弃了。 我前前后后6年花6000多元买云服务器。业余花了无数的精力&#xff0c;从2018到现在 &#xff0c;也没有折…

618购物节数码好物到底怎么选?盘点几款可闭眼入的数码好物分享

随着618购物节的热烈氛围逐渐升温&#xff0c;数码产品的选购成为了许多消费者关注的焦点。面对市场上层出不穷的新品和优惠&#xff0c;如何选择一款既符合自己需求又物超所值的数码好物&#xff0c;成为了不少人的难题&#xff0c;今天&#xff0c;我们就为大家带来几款精心挑…

QT Redis 中的实现发布/订阅功能(全网最全的教程)

Redis 介绍 Redis发布/ 订阅系统 是 Web 系统中比较常用的一个功能。简单点说就是 发布者发布消息&#xff0c;订阅者接收消息&#xff0c;这有点类似于我们的报纸/ 杂志社之类的 实现代码 #ifndef MAINWIDGET_H #define MAINWIDGET_H#include <QWidget> #include <…

【C++提高编程-09】----C++ STL之常用排序算法

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

基于单片机的无线遥控自动翻书机械臂设计

摘 要&#xff1a; 本设备的重点控制部件为单片机&#xff0c;充分实现了其自动化的目的。相关研究表明&#xff0c;它操作简单便捷&#xff0c;使残疾人在翻书时提供了较大的便利&#xff0c;使用价值性极高&#xff0c;具有很大的发展空间。 关键词&#xff1a; 机械臂&…

Django后台忘记管理员的账号

使用命令启动项目&#xff1a; python manage.py runserver输入后缀/admin&#xff0c;进入后台管理员&#xff0c;如果此时忘记你先前设置的用户名与密码怎么办&#xff1f; 终端输入&#xff1a; python manage.py shell 输入以下内容&#xff0c;并查看返回结果&#xff…

大跨度气膜综合馆有哪些优势—轻空间

1. 经济高效 材料和施工成本低 气膜综合馆的建设成本相对较低&#xff0c;主要材料为膜材和充气系统&#xff0c;不需要大量的钢筋混凝土和复杂的结构施工&#xff0c;降低了材料和施工成本。 能源消耗低 气膜馆的双层膜结构和充气系统具有良好的保温性能&#xff0c;减少了冬…

【经典爬虫案例】用Python爬取微博热搜榜!

一、爬取目标 本次爬取的是: 微博热搜榜 &#xff08;代码也可直接在下方拿&#xff09;&#xff1a; ​ 分别爬取每条热搜的&#xff1a; 热搜标题、热搜排名、热搜类别、热度、链接地址。 下面&#xff0c;对页面进行分析。 经过分析&#xff0c;此页面没有XHR链接通过&am…

Sping源码(九)—— Bean的初始化(非懒加载)— Bean的创建方式(自定义BeanPostProcessor)

序言 之前文章有介绍采用FactoryBean的方式创建对象&#xff0c;以及使用反射创建对象。 这篇文章继续介绍Spring中创建Bean的形式之一——自定义BeanPostProcessor。 之前在介绍BeanPostProcessor的文章中有提到&#xff0c;BeanPostProcessor接口的实现中有一个Instantiatio…

Proxmox VE 超融合集群扩容后又平稳运行了170多天--不重启的话,488天了

五个节点的Proxmox VE 超融合集群&#xff0c;扩从了存储容量&#xff0c;全NVMe高速盘&#xff0c;单机4条3.7TB容量&#xff08;扩容前是两块NVMe加两块16TB的慢速SATA机械盘&#xff0c;拔掉机械盘&#xff0c;替换成两块NVMe&#xff09;&#xff0c;速度那叫一个快啊。 当…

秋招突击——6/16——复习{(单调队列优化DP)——最大子序和,背包模型——宠物小精灵收服问题}——新作{二叉树的后序遍历}

文章目录 引言复习&#xff08;单调队列优化DP&#xff09;——最大子序和单调队列的基本实现思路——求可移动窗口中的最值总结 背包模型——宠物小精灵收服问题思路分析参考思路分析 新作二叉树的后续遍历加指针调换 总结 引言 复习 &#xff08;单调队列优化DP&#xff09…

Qt实现单例模式:Q_GLOBAL_STATIC和Q_GLOBAL_STATIC_WITH_ARGS

目录 1.引言 2.了解Q_GLOBAL_STATIC 3.了解Q_GLOBAL_STATIC_WITH_ARGS 4.实现原理 4.1.对象的创建 4.2.QGlobalStatic 4.3.宏定义实现 4.4.注意事项 5.总结 1.引言 设计模式之单例模式-CSDN博客 所谓的全局静态对象&#xff0c;大多是在单例类中所见&#xff0c;在之前…

使用ant-design/cssinjs向plasmo浏览器插件的内容脚本content中注入antd的ui组件样式

之前写过一篇文章用来向content内容脚本注入antd的ui&#xff1a;https://xiaoshen.blog.csdn.net/article/details/136418199&#xff0c;但是方法就是比较繁琐&#xff0c;需要将antd的样式拷贝出来&#xff0c;然后贴到一个单独的css样式文件中&#xff0c;然后引入到内容脚…

20个超实用的VS Code扩展(2024年版)

大家好&#xff0c;今天小程给大家带来一篇关于 VS Code 扩展的文章。VS Code 这几年做得是风生水起&#xff0c;可以算得上是微软的良心产品&#xff0c;其最大的优势就是拥有众多高质量的扩展。在本文中&#xff0c;将向大家推荐一些我认为在 2024 年对开发者来说又实用又好用…

分布式技术导论 — 探索分析从起源到现今的巅峰之旅(分布式协议)

探索分析从起源到现今的巅峰之旅2 前提回顾最终一致性Clock时钟机制局限性 CAP协议CAP理论的三要素A和C机制的保障P分区容错性AP机制的保障CP机制的保障 分布式系统方向 分布式系统之ZookeeperZK的作用和职责协调服务命名服务构建高可靠服务 ZK的常见用法ZK基本原理ZK的顺序一致…

将粘贴文本进输入框中时不带有任何格式(包括背景颜色和字体)解决办法

只需要四行代码解决&#xff0c;这里用到vue3里面的事件 paste"" 代码块&#xff1a; <div paste"handlePaste"></div>//粘贴文本时不带有任何格式&#xff08;包括背景颜色和字体&#xff09;function handlePaste(event) {event.preventDef…