Qt与matlab混合编程详细实现过程

最近项目需要,matlab的一些算法需要工程用,因此需要直接转成Qt能够调用的形式,之前也做过类似的,但那个时候是使用vs2012,而且也没怎么做记录,一些坑坑绕绕也都忘了,现在用Qt调用,感觉区别还是很大的。

环境:

Qt5.9 mingW(32位)

matlab2015b(32位)

vs2015

这里要注意Qt官方发布的qt安装都是32位的,如果想要64位需要自己编译,所以能做取舍的只有选择32位的matlab,好在matlab不同版本可以完美兼容。

vs2015是由于matlab的mbuild命令需要,要想使用编译dll文件就要使用mcc命令,要想使用mcc命令就必须配置好matlab的编译配置,具体命令:

mbuild -setup

mex -setup

选择vs2015的就行了。

当然这里有其他的选择,mbuild的时候也可以选择window自带的microsoft SDK,一般是7.1版本,你会发现它的版本和windows的版本是对应的7.1 8.1 10毕竟SDK中文就是software development kit(软件开发包)嘛,版本号一一对应也是情理之中。

mex的时候也可以选择matlab自带的lcc,有时候需要自己手动安装,但其实装vs的效率是最高的,装完mbuild和mex都有了,而且博主发现matlab2015b作为matlab最后一个32位版本似乎……不识别微软的SDK10版本,emmmmmm这一点我没法解决,有读者解决了的话希望可以在评论区反馈给我。

第一步:将matlab程序写成函数形式

第二步:将函数的.m文件转换成动态链接库形式

matlab mcc命令:mcc -W cpplib:svm -T link:lib svm.m

将生成的.h.lib.dll文件三个一起拷到代码所在的文件夹。

这里就会有好奇宝宝问了,dll文件不应该放到debug路径下嘛?由于我采用的是动态调用,往后看你就知道了。

第三步:qt调用

这一步尤为关键,分步说:

1、宏定义:

.pro文件中一般需要添加很多很多

首先:

DEFINES += __MW_STDINT_H__

这个东西是针对matlab的mclmcr.h头文件中第170行到第190行中编译器的一些宏的设定,一般来说如果是mingW编译器我们一般写+= __MING_W__,但是这个头文件中并没有给出mingW编译器的情况,所以一般选择加上上面这行代码,选择一个编译器的类型,如果不加,则会报错如下:

D:\matlab2015b32\extern\include\mclmcr.h:278: error: 'mxUint64' has not been declared
     virtual int get_numeric(mxUint64* x, mwSize len) = 0;
                             ^

大致意思就是说64位的mxUint64没有定义,你不要一看matlab的头文件就慌,你好好看一看就会发现其实就是几个if else而已,不要慌对不对。

还有大佬加上这一句

DEFINES += QT_DEPRECATED_WARINGS

这句我真没发现有什么用,我删掉了……好像也没报错,emmmmmm字面意思似乎是屏蔽一些警告……我真不知道所以大家有知道什么意思的希望可以在评论区告诉我一哈,相互交流嘛。

2.添加外部库:

这里要尤其感谢csdn上的这位友好的大佬ID qq657863206,这里和下面一部分都是由这位大佬教会我的,当我顺着他的id加他的qq的时候还在想会不会被拒绝,结果这位大佬友好负责地教会了我调用方法,他本人的一篇博文也是说这件事的,大家可以去看下,链接:https://blog.csdn.net/qq657863206/article/details/82354874

添加外部库的方法:按照图片一步一步走即可

Qt与matlab混合编程详细实现过程_第1张图片

Qt与matlab混合编程详细实现过程_第2张图片Qt与matlab混合编程详细实现过程_第3张图片

点击下一步,你就会发现你的.pro文件中多了几行:

win32: LIBS += -L$$PWD/./ -lsvm

INCLUDEPATH += $$PWD/.
DEPENDPATH += $$PWD/.

自己直接写也可以,但前提是你得写对哦~

3、添加matlab依赖以及头文件

这个就相对简单粗暴了,首先确认你的matlab路径,然后复制粘贴即可

LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -lmclmcrrt
LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -lmclmcr
LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -llibmx
LIBS += -LD:/matlab2015b32/extern/lib/win32/microsoft -llibmat
INCLUDEPATH += D:/matlab2015b32/extern/include
DEPENDPATH += D:/matlab2015b32/extern/include

我的……就这么多就够了,网上有不少恨不得把所有的库都填进去的……也没差,反正这年头你也不会一个字母一个字母地往上打,但这里就涉及到一个问题,应该放多少呢……不知道,我真地不知道,反正我的就这么几行,程序好使,没报错,嗯。

当然还要注意,在你的头文件中刚才你拷进去的.h文件

4.动态调用

QLibrary myLib("svm.dll");
typedef bool MW_CALL_CONV(*Fun)(int,class mwArray &,class mwArray const &,class mwArray const &,class mwArray const &);
Fun svm = (Fun)myLib.resolve("?svm@@YAXHAAVmwArray@@ABV1@11@Z");

这里需要注意,加粗上红字,嗯,emmmmmmmmmm

分条说:

1、我之前说过dll文件和代码放一起吧,就是这样,不放一起找不到

2、你需要一个软件 dependency walker,这个软件是干嘛用的呢……看dll文件中的函数用的,别慌,你别慌,别关网页,这个真不难,咱都是用matlab的,都不是计算机科班出身,我都学会了你还能学不会?

这玩意就几M,界面是这样的

Qt与matlab混合编程详细实现过程_第4张图片

你唯一需要的就是左上角的打开按钮,使用它打开dll文件就这么简单,打开你生成dll文件你会发现

Qt与matlab混合编程详细实现过程_第5张图片

你会发现乱码中夹着你写的函数,我的是svm,什么你的不是乱码?那你右键点一下选择取消修饰C++函数看看,必乱码。

这是由于C++的重载,用形参列表来区分同名函数,因此在调用时对函数名进行了编码(自己的理解,有大老知道请指教)。

这是由于matlab使用vs的msvc编译器生成的dll文件,生成后我们使用mingW调用,但生成的头文件中指定各种编译器对应的情况,但唯独没有MinGW,这就导致了在使用MinGW编译器时我们使用了:

DEFINES += __MW_STDINT_H__

使用msvc编译器调用matlab生成的dll时,编译器会自动识别函数名,因此也不需要使用resolve函数,这一点博主会在后续博文中详细介绍。

但现在既然乱码了我们怎么处理呢,你看我上面那几行就完事,其实就是用Qlibrary的resolve函数把乱码换个函数名,仅此而已,乱码可以从dependency walker中直接复制过来,函数原型当然也要对应着你自己的修改一下。

剩下的,完事了,再不完事这个代价就有点大了,讲道理我费这么大力气(其实也没……还好)做出dll,实际执行速度什么的我还没测试,这玩意……确实有点麻烦。

emmmmmmmmmmm总结

感谢大佬qq657863206是他将以上方法总结出来,由我总结发出来的。

那么回过头来,qt调用matlab动态链接库好处在哪?

1、qt做界面,matlab做算法,二者相得益彰

2、相对于将算法C++化,这样做当然节约时间和成本

缺点:

1、程序执行速度尚未测试,尽管转换为dll,我个人认为matlab甚至是官方并不重视这一需求,毕竟你不能对脚本语言期望太高,因此我对其执行效率表示担忧,不知道有没有人了解这一块,看在我码了这么多字的面子上能在评论区指点我一下。

//19.4.22更新/

最近看到网上有很多不需要使用Qlibrary和reslove给函数改名的程序,这是由于他们qt用的msvc编译器,再用msvc编译器调用就不会出现需要改名的问题。

如果你仔细看matlab的头文件你就会发现,其中考虑了不同平台不同编译器的情况,但是唯独没有使用mingw的情况,这是mathwork和ms这种闭源对开源的抵制???瞎猜的,别当真(手动滑稽)。

 

你可能感兴趣的:(qtmatlab混合编程,Qt,matlab)