该篇介绍QT下调用MatLab编译好的运行库
环境:Windows10,QT5.12.6,MatLab r2018b 64位
MatLab的安装可以看这篇文章MatLab安装
一、打开MatLab,先设置编译器,在命令行输入:
>> mbuild -setup C++
结果如下:
MBUILD configured to use 'Microsoft Visual C++ 2017' for C++ language compilation.
即设置C++编译器,如果设置C编译器可以输入 mbuild -setup
二、编译.m文件,命令行输入>> deploytool
,出现下图结果:
选择Library Complier,配置如下:
等待打包…
打包完成,输出如下:
for_redistribution目录下是MyAppInstaller_web.exe,这个是MATLAB运行时库的和本项目的安装文件,运行后可从网上下载MATLAB的运行时库进行安装,还会安装本项目生成的dll、lib和h文件。for_redistribution_files_only目录下是编译生成的.dll 、.lib和.h文件,其中.lib和.h文件是在Qt项目编译时需要用到的,.dll文件是程序运行时需要用到的。for_testing 目录下是用于测试的。该段引自:https://blog.csdn.net/HongAndYi/article/details/79433623
三、在QT中配置项目需要的动态库
右击项目:
选择Add Library:
先在QT项目下,新建include文件夹,把MatLab编译好的.lib和.h复制过来:
而.dll文件要放在项目生成的debug目录下:
然后添加lib文件,路径是刚才建立在QT项目下的include下的lib:
之后会在QT项目的.pro文件生成如下代码:
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/include/ -lpsoelse:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/include/ -lpsoelse:unix: LIBS += -L$$PWD/include/ -lpsoINCLUDEPATH += $$PWD/includeDEPENDPATH += $$PWD/include
目前是把Matlab编译好的库文件包含进来的,但是还没完,还需要把MatLab需要的运行库包含进来:
INCLUDEPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/include)INCLUDEPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/include/win64)INCLUDEPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft)DEPENDPATH += $$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft)LIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibmexLIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibmxLIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibmatLIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -llibengLIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -lmclmcrLIBS += -L$$quote(C:/Program Files/MATLAB/R2018b/extern/lib/win64/microsoft/) -lmclmcrrt
之所以加quote是因为路径中包含空格,比如Program Files,这种情况就需要加quote包含进来,否则会出错。
四、在QT项目下调用MatLab编译好的pso.dll中的函数,先说一下QT中的编译器,我的有MinGW也有MSVC编译器(手动配置的,但是实际运行没用到),我用的MinGW,为了避免不必要的问题,建议MatLab的c++编译器和QT编译器要版本一致,
我的MSVC编译器是手动配置的,因为之前装过vs2017,所以配置起来比较方便,只需要安装debugger就可以,CDB安装可以在官网下载Debugging Tools for Windows 10 (WinDbg)
我的初衷是使用MSVC但是项目运行的时候却无法选择MSVC只能用MinGW,我不清楚具体是怎么个问题。
另外如果想把MATLAB中的C++编译器调成和QT中的编译器一样的,可以通过MATLAB中的控制台来设置:①输入mex -setup,如果有的话就会显示出可以用的编译器。②没有的话就要安装一个,选择的是MinGW编译器,下载地址sourceforge.net/projects/mingw-w64/files/latest/download,然后安装,一定记得选择符合自己操作系统位数的。③等待安装结束后,添加新的环境变量MW_MINGW64_LOC,值为MinGW的安装路径 ④设置完环境变量之后,在Matlab命令行运行setenv(‘MW_MINGW64_LOC’,folder),folder为MinGW的安装位置(跟环境变量路径一致即可),要加单引号;如果每次重启Matlab后还是没有发现编译器,而且每次都要重新编译,此时就要看看MinGW的安装目录是不是空格,很多人默认安装在C:\Program File\下,结果就运行不了,因为这其中有空格,此时有两种方法可以解决,第一种就是重新安装到没有空格的文件夹里面,当然这得重新安装,比较麻烦;第二种就是,直接在环境变量那里,把Program File改为Progra~1。链接:https://www.jianshu.com/p/621cba9a8417来源:简书
另外也可以看这篇文章:MATLAB如何安装配置MinGW-w64 C/C++编译器,
我的调用代码如下:
#include "pso.h"
//下面是调用MatLab编译好的粒子群算法 QLibrary myLib("pso.dll"); typedef bool MW_CALL_CONV(*Fun)(int,class mwArray const &,class mwArray const &,class mwArray const &,class mwArray const &,class mwArray const &,class mwArray const &); Fun myFunc = Fun(myLib.resolve("?PSO@@YAXHAEAVmwArray@@000AEBV1@1@Z")); if(!psoInitialize()) //必须要初始化成功 { qDebug()<<"could not initialize psodll\n"; exit(0); } mwArray coor(str.size(),4,mxDOUBLE_CLASS); //输入值 mwArray v(1,1,mxDOUBLE_CLASS); mwArray x(1,1,mxDOUBLE_CLASS); //输出值 mwArray y(1,1,mxDOUBLE_CLASS); mwArray z(1,1,mxDOUBLE_CLASS); mwArray t(1,1,mxDOUBLE_CLASS); coor.SetData(adjustToArray,4*str.size()); v(1,1)=WAVEVELOCITY; myFunc(4,x,y,z,t,coor,v); XRESULT=x.ToString(); YRESULT=y.ToString(); ZRESULT=z.ToString(); TRESULT=t.ToString();
注:
需要说明的是由于matlab使用vs的msvc编译器生成的dll文件,生成后我们使用mingW调用,但生成的头文件中指定各种编译器对应的情况,但唯独没有MinGW,这就导致了在使用MinGW编译器时我们在.pro文件中添加:DEFINES += MW_STDINT_H使用msvc编译器调用matlab生成的dll时,编译器会自动识别函数名,因此也不需要使用resolve函数。这段话引自:https://blog.csdn.net/China_Rocky/article/details/104592488
比如:
Fun myFunc = Fun(myLib.resolve("?PSO@@YAXHAEAVmwArray@@000AEBV1@1@Z"));
上述resolve中的值来自pso.dll(即刚才matlab编译好的运行库),我们可以利用Dependency Walker 2.2该软件查看dll文件,然后找到入口函数,后边跟着的值就是这个resolve中的值。可以在matlab编译生成的.h文件中查看项目生成的调用函数,比如:
extern LIB_pso_CPP_API void MW_CALL_CONV PSO(int nargout, mwArray& x, mwArray& y, mwArray& z, mwArray& t, const mwArray& sample, const mwArray& v);
说明:
(1)DLL的初始化在使用pso.dll里的函数之前,必须先初始化。psoInitialize()是matAdd.h文件里面的库初始化函数。(2)PSO函数的输入输出参数mwArray是MATLAB的数组类,MATLAB编译生成的DLL的接口函数的参数都是采用mwArray类型,例如:extern LIB_pso_CPP_API void MW_CALL_CONV PSO(int nargout, mwArray& x, mwArray& y, mwArray& z, mwArray& t, const mwArray& sample, const mwArray& v);int nargout 是输出参数个数,比如我这里是4,那么,后面x,y,z,t变量是输出参数,mwArray &sample, const mwArray &v是输入参数(3)mwArray类的使用mwArray coor(str.size(),4,mxDOUBLE_CLASS); 定义mwArray类型的变量coor时,利用构造函数传递了数组的行数、列数、元素类型、实数或复数类型语句coor.SetData(adjustToArray,4*str.size()); 将一维向量adjustToArray的数据内容赋值给coor,元素个数为4*str.size(),等于行数*列数。使用SetData赋值时,输入adjustToArray必须是一个向量,是逐列存储的。注意:mwArray数组的下标都是从1开始的,与C/C++的数组元素下标从0开始不同。这段话修改自:https://blog.csdn.net/HongAndYi/article/details/79433623
另外mwArray的详细用法如下:
一.矩阵赋值<1>mwArray 定义矩阵变量 mwArray A(rows, cols, type)参数说明: A :变量名 rows:行数 col :列数 type:数t据类型type类型有:typedef enum{ mxUNKNOWN_CLASS = 0, //未知类型 mxCELL_CLASS, //细胞类型 mxSTRUCT_CLASS, //结构类型 mxLOGICAL_CLASS, //布尔类型 mxCHAR_CLASS, //字符串类型 mxVOID_CLASS, //void类型 mxDOUBLE_CLASS, mxSINGLE_CLASS, //单精度浮点数 mxINT8_CLASS, // mxUINT8_CLASS, mxINT16_CLASS, mxUINT16_CLASS, mxINT32_CLASS, mxUINT32_CLASS, mxINT64_CLASS, mxUINT64_CLASS, mxFUNCTION_CLASS, //函数类型 mxOPAQUE_CLASS, // mxOBJECT_CLASS //对象类型}整体含义是:定义矩阵A,行数为:rows,列数为:cols,类型为:type注:如果参数不是矩阵,只是一个数,令 rows=1,cols=1即可。<2>矩阵赋初值:int a[6] = {1,2,3,4,5,6}mwArray A(2,3,mxINT32_CLASS); A.SetData(a,6); //第二个参数为要设置的数的个数,大小可设为rows*cols注:该过程相当于把1*6的矩阵,转化为2*3的矩阵,matlab转化顺序是,先排第一列,由上到下为a[0] a[1],然后排第二列,由上到下为a[2] a[3],即转化后的A为:1 3 52 4 6如果要使A为:1 2 34 5 6需这样赋值:
"code"
mwArray A(3,2,mxINT32_CLASS); //修改此处:行列数互换A.SetData(a,6); //第二个参数为要设置的数的个数,大小可设为rows*cols此时生成的A为:1 42 53 6该矩阵转置之后,既可以达到所需形式,转置过程可以在matlab的.m文件中添加,先修改.m,然后在生成dll、lib、h文件。尤其是,在图像处理时,如果传递的矩阵为图像数据矩阵,要采用后一种方法赋值,否则,图像会严重变形失真。二、字符串赋值char str[5] = "abcd";//或 CString str = "abcd"mwArray mwA(str);该段转载自:https://blog.csdn.net/hong__fang/article/details/43307701仅用于学习使用