问题背景:
利用VS2022+Qt6开发关于OpenCV的应用程序后(见另一篇文章),打包成exe可执行文件,并且需要在另一台Windows机器上运行,遇到了一些Bug,在此进行记录,其中有前人的经验,也有自己尝试的解决方法。
问题描述与解决
问题1——在VS中的Debug模式下调试代码无错,切换成Release模式生成项目出错
原因分析
未在项目属性页将Release模式下的设置与Debug模式下的设置同步
如上两张图,分别是Debug模式与Release模式下的项目属性页,如果之前只配置了Release模式,在切换到Debug模式后应该会如第一张图所示一样,所框选区域均为默认宏定义,此时若不手动添加三方头文件与库文件目录,则会编译出错。
解决方法
在项目属性页需要手动配置的地方都要对照着已经配置好的模式检查一下最为妥当。
问题2——使用Qt的windeployqt.exe工具打包exe文件时报错“xxx.exe does not seem to be a Qt executable.”
原因分析
- 需要打包的文件和“QT软件的安装位置”不在一个硬盘中
有博主提到,出现这个报错的原因是需要打包的文件和“Qt软件的安装位置”不在一个硬盘中,比如说Qt安装的硬盘在D盘,而需要打包的项目可执行文件在E盘。
解决方法
将可执行文件移动到与Qt安装位置同一个硬盘中,进行打包。
但是我遇到的情况与这不符,经过测试不论需要打包的可执行文件移动到哪里都不成功。
- 检查一下构建项目的Qt版本与你所使用的Qt打包工具所对应的Qt版本是否一致
经过检查,我发现我在VS中配置Qt相关设置时,使用的是Qt 6.8 版本的MSVC2022,但是在使用windeployqt.exe工具时,使用的是D:\Qt\5.15.2\msvc2019\bin目录下的windeployqt.exe工具。
解决方法
于是我切换到D:\Qt\6.8.0\msvc2022_64\bin,并执行
windeployqt.exe E:\Code\cppHomework\bin\x64\Release\cppHomework.exe
可执行文件便被成功打包了,并且生成了Qt相关的众多动态库等文件(之前还以为是这些动态库没有拷贝到与可执行文件同一目录导致的上述问题)。
怀着好奇心我还讲可执行文件继续移动到其他目录,甚至其他硬盘下(与Qt安装目录位于同一块固态硬盘不同分区,或者位于不同固态硬盘),都能够成功打包,并且可执行文件能够被成功打开。
问题3——在Qt中使用OpenCV读取图片时,利用QFileDialog::getOpenFileName函数得到图片路径并用cv::imread函数读取,Debug时可正常运行,但是Release模式下或者打包后执行exe文件时可能会报错
原因分析
- QString转std::string 或 cv::String时,编码问题导致路径字符串解析有误
使用QFileDialog::getOpenFileName命令将得到所选中打开文件文件名的QString类型变量,而cv::imread()函数的形参变量为cv::String类型,于是需要转换为中间类型std::string,QString转换成std::string类型一般有三种方法,都需要先转换成QbyteArray,一种是toUtf8(),一种是toLocal8bit(),还有一种是toLatin1()。toUtf8()是转换成UTF-8编码的字符集,Local8bit是转换成本地操作系统设置的字符集编码,一般为GB2312,通常对中文汉字友好,而toLatin1()转换成不包含中文的ASCII码,如果遇到中文会默认转换为ASCII码0x3f也就是字符‘?’。经过尝试使用toLocal8bit()不会影响编译,但是在运行过程中,在选择并打开图片时,软件就会崩溃退出,但如果使用toUtf8()就会避免这个问题。
解决方法
在Qt中遇到QString转换成std::string的场景,如果不是必须涉及到中文,最好都采用UTF-8编码,使用如下方式进行转换:
openFile = QFileDialog::getOpenFileName(this,
"please choose an image or video file",
"",
"Files(*.jpg *.png *.bmp *.pgm *.pbm *.mp4);;All(*.*)");
cv::Mat srcImg = cv::imread(openFile.toUtf8().toStdString());
- 执行打包后的exe文件时,遇到调用QDir::currentPath()访问资源文件时出错
在VS中开发Qt并debug时,可能会使用**QDir::currentPath()**得到相应路径后,进一步组合出资源文件所在路径,并访问图片、模型等资源文件,而打包后执行可执行文件时需要调用资源文件时却会遇到崩溃退出的情况,经过这位博主的介绍,原因是在VS中编译执行代码时,**QDir::currentPath()**为启动它的父进程的路径,也就是调用它的源码路径,而在打包文件夹当中,去执行这个程序,此时QDir::currentPath()代表的路径,又变成了可执行程序的路径,那么此时资源文件的路径就不正确了,如果此时需要读取图片就无法正确找到目标图片文件了。
解决方法
在Qt中如果涉及到需要通过相关参考路径访问资源文件等的话,参考路径可以使用**QCoreApplication::applicationDirPath()或者QFileInfo::absoluteFilePath()**函数获取,这将返回包含可执行文件的路径。当然这样之后,在打包程序后,需要将资源文件拷贝到与可执行文件同一个目录下才可保证程序的正常运行。
问题4——无法链接的外部符号 “LNK2001 private: void _cdecl xxx::xxx(void)* (?xxx@xxx@@AEAAXXZ”
原因分析
这种错误的原因有很多,一种原因是可能在类成员中定义了槽函数,虽然没有在程序中用信号与之相连接,也没有调用它,但是函数没有定义,所以会出现这个错误。
解决方法
在声明该槽函数的头文件的对应cpp实现文件中,定义该函数(为空都可以)。