matlab 运行时库
由于项目需要将生成的数据转成C3D运动捕捉格式,目前无C++转换算法,有MATLAB算法,考虑到C++重新码算法的时间,选择了将MATLAB算法直接转成C++dll供Qt调用。由于初次搞所以难免踩了很多坑,最后完成后觉得这条路比MATLAB转C++代码更方便快捷(以前多个项目是将MATLAB代码直接手动转C++代码,痛苦的是MATLAB内置算法转换。当然较简单的算法还是直接写C++代码吧,毕竟调用会增加程序运行环境的复杂)。
简单过一下MATLAB转dll的过程
转dll需要安装MATLAB程序,可自行下载各版本。Qt调用的话只需要MATLAB运行库即可,后面提及。首先打开MATLAB在命令行输入“mbuild -setup”查看可切换的编译器(其实msvc编译器生成的Qt也可调用,我Qt选择的是MinGW64所以很老实的在MATLAB的附加功能-获取附加功能里面下载了MinGW64编译器。)如图:
**第一个坑:**这里一定要选择编译器+语言即:MinGW64 Compiler ? + mex -setup C++ -client MBUILD ,我当初只选择了编译器忘记勾选C++语言,这样依旧可以打包生成dll,不过导致的问题就是Qt加载编译时提示“undefined to XXXX”。
切换编译器和语言之后在命令行输入“deploytool”,在弹出的界面中选择“Library Complier”。
这里的m文件只需要添加包含主函数的.m文件即可,它会自动识别依赖的m文件,可以再当前界面下方栏看到。点击“package”等待生成即可。生成的目录有图中的几个:
v2目录中的.ctf文件(具说影响dll接口中的初始化函数)较高版本的MATLAB不需要。我的是2019b。如果不放心也可将.ctf同dll放在一起使用。到此Matlab转dll已经完成,后续就是集成到Qt里面。
继续完成Qt调用dll部分
如果是要发布的Qt程序最好还是在本地环境下载Matlab运行库,不安装运行库用Matlab软件配置也可以。这里给个运行库链接(下载的运行库一定要和你生成dll的Matlab程序一个版本):
https://ww2.mathworks.cn/products/compiler/matlab-runtime.html
运行库的安装一路到底就行。安装完成后先配置系统环境:
系统环境-path-编辑-新建-浏览,找到你安装的Matlab运行库目录,把v97\runtime\win64和v97\bin\win64添加进去。2019b版本对应的是v97,其他版本都不一样。图:
(如果没装运行库使用MATLAB程序设置环境变量和上述目录一样设置就行)。
上面MATLAB环境已配置完成,继续Qt链接dll(ps:设置完系统环境后重启下QtCreator)。至于Qt怎么加载第三方库,我就不详说了,按部就班就行。这里主要的是配置编译依赖目录和配置MATLAB必须的几个lib文件。
添加转换的lib:右击Qt工程-添加库-浏览-将转换完成的lib找到,添加完成后pro工程文件会自动更新。
添加MATLAB必须lib:这里就直接上个pro代码吧:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
win32: LIBS += -L$$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 -llibmex
win32: LIBS += -L$$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 -llibmx win32: LIBS += -L$$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 -llibmat win32: LIBS += -L$$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 -llibeng win32: LIBS += -L$$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 -lmclmcr win32: LIBS += -L$$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 -lmclmcrrt INCLUDEPATH += $$PWD/../../../Matlab2019bRuntime/v97/extern/include/win64 INCLUDEPATH += $$PWD/../../../Matlab2019bRuntime/v97/extern/include INCLUDEPATH += $$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 INCLUDEPATH += $$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64 DEPENDPATH += $$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64/mingw64 DEPENDPATH += $$PWD/../../../Matlab2019bRuntime/v97/extern/lib/win64 DEPENDPATH += $$PWD/../../../Matlab2019bRuntime/v97/extern/bin/win64 DEPENDPATH += $$PWD/../../../Matlab2019bRuntime/v97/runtime/win64 win32: LIBS += -L$$PWD/../sdk/matlab/lib -lconverToC3D |
“$$PWD/”标识符是代表相对于工程所在目录,“…/”是上一级目录。你可以设置绝对路径 “+= D:/XXX”这种。看个人喜好设置,效果都是为了找到库和头文件顺利通过编译。上面也列出了MATLAB运行需要的lib。“mingw64”也可以是“microsoft”,我选的MinGw64转换的dll所以很老实的加了对应的。“-lconverToC3D”是转换的lib文件。
添加转换的头文件:将头文件.h放在你需要调用的工程目录即可,在你的cpp中include “xxx.h”。至于加不加进你的工程里面看你自己,没啥区别。
将转换的dll放在构建运行目录:将转换的dll文件拷贝到你的运行目录,即debug或者release目录(和你Qt生成的exe同级目录)。较低版本的MATLAB也可将.ctf放在同dll一个目录。
到此Qt配置转换dll环境也完成了。后面介绍下函数调用方式
Qt代码调用dll中的函数:其实很简单:第一步调用初始化函数:converToC3DInitialize(),这里是我自己的初始化函数,你的也是XXXInitialize()这种格式,“XXX”是你转换.m中的主函数;第二步:调用你所需的主函数:XXX();我的是converToC3D();带参数的函数需要先试用mwArray转换一下,具体自行了解mwArray怎么使用。之前查资料的时候很多人遇到mwArray创建对象时崩溃,我这里到是没遇到,其实按部就班应该不会出现错误。
注意几点: 1.初始化函数一定要先调用。2.初始化函数有点耗时,有业务需求的可以考虑将它放在软件启动时刻执行。3.初始化函数只能调用一次,多次调用只有第一次成功。而且一个exe进程只需要初始化一次就行。4.函数中涉及中文的要转toLocal8bit。这里有个很难遇到的第二个坑,我简述下我的辛酸过程:我的转换函数需要读取文件路径,路径中包含中文,其实我的代码中已经做了转换,可以正常识别。可在我交付给同事测试的时候一调用转换函数软件就崩溃,其他三台机器都运行正常,由于抓不到崩溃日志,只知道是转换函数崩了,就怀疑是那台电脑环境问题,搞了一天的环境还是没能解决。无奈只能在那台电脑安装Qt软件用Debug模式跑,发现了MATLAB中xlread函数无法识别路径退出。同样的代码为何这台电脑不行,结果查了之后发现同事在win10输入法上做了改动,如图:
勾选了图中Beta版选项。。。取消勾选后就正常了。实际C++在勾选的情况依然可以识别中文而MATLAB却不行。
Qt调用转换dll函数的实现方式(线程)
这里单独拎出来说下Qt调用转换函数的方式,建议尽量在线程中调用MATLAB转换函数,不然会卡住主线程,若有UI交互会明显的界面卡顿现象。这里卡顿或许和函数处理的复杂程度有关,简单的处理函数可以不用开线程处理,(如果简单也不用转dll了0-0)。有些小伙伴遇到放在槽函数调用会失败的问题。
结束语
看似简单的过程其实也花了2天时间才完全搞定,当然这比当初计划将MATLAB语言转C++语言代码省时多了,结果还是很可靠的(这可是MATLAB)。当然也损失了一些东西比如软件的启动时间,软件运行环境变复杂。
很多时间都是在尝试中,一遍不行又一遍结果发现还是不行~~~那就不是它的问题。
第一点:MATLAB 编译器切换 的要和Qt的一致。都是64位或者32。都是MinGw或者msvc。这样肯定是没问题的。。。
第二点:MATLAB 语言切换 要是C++。。。这个坑耗了我一上午+半下午的时间。具体可看我前面的讲述。
第三点:Matlab运行库到系统环境配置。
第四点:Qt集成dll。 没啥特别的地方,目录正确就行。转换的dll要和.h,.lib配对。
有不对的地方可留言指出,一同交流。