网上虽然有一些VS+Matlab混合编程的博客,但是有很多行不通的地方,我按照流程依然碰到了很多比较新的问题,现在将问题以及解决方案做出整理,希望可以帮到需要帮助的盆友。
环境:Qt 5.5.1(Qt Creator 3.5.1) + VS2013(64位) + Matlab R2014a
第一步:用Matlab根据(.m)函数文件生成(.dll,.h,.lib,.ctf)文件
(1)新建->函数->保存
function b = myFunc(a)
b = a.*a;
end
(2)调用编译器,生成(.dll,.h,.lib,.ctf)文件;这一步在编译器上可能会有比较多的问题:
首先,检查一下自己的mcc编译器是否可用
命令行输入指令 !mcc
正常的结果应该如下(指令结果比较长,我只截取了上面一部分):
>> !mcc
MCC Invoke MATLAB to C/C++ Compiler (Version 5.1).
MCC [-options] fun [fun2 ...]
Prepare fun.m for deployment outside of the MATLAB environment.
Generate wrapper files in C or C++ and optionally build standalone
binary files.
Write any resulting files into the current directory, by default.
For all targets except standalone, if more than one file is
specified, a C or C++ interface is generated for each file.
The only exception to this rule is when the file is specified
with a '-a' flag.
If C or object files are specified, they are passed to MBUILD along
with any generated C files.
If conflicting options are presented to MCC, the rightmost conflicting
option is used.
OPTIONS:
a Add to the CTF archive. If the specified file
is an M, mex or p file, this function will not be exported in the
resulting target.
如果出现error,那么就是Matlab的编译器不能用,原因是Matlab并未完全破解,
也就是说,有证书编号的,而不是unknown,这就需要自己重新激活或者重新找一个靠谱的Matlab安装包了;当然我还发现有一些没有完全破解的,就是有证书编号,但是编译器依然不能用,这个解决方法如下:
适用于已安装compiler但破解不完全的,http://pan.baidu.com/s/1qWFbOjq,提取码84rg ,下载后解压,把install.jar以及相应位数的三个文件(compiler.dll,mcc.exe,libmwservices.dll)复制到对应位置替换即可,另外把license.lic改为与MATLAB\licenses文件夹下的那个lic文件同名,复制并替换之。
解决了编译器问题之后,输入指令:mex -setup
如果安装了VS2013的话应该是有Microsoft Visual C++ 2013这个选项的,我们选择mex -setup C++,然后选择VS2013的C++编译器即可
然后输入指令:mbuild -setup
选择 mex -setup C++ -client MBUILD,然后进一步点击VS2013C++编译器即可
之后就可以调用mcc编译指令来完成我们的第一步了,当然Matlab文件夹要设定为我们.m所在的文件夹,输入指令:
mcc -W cpplib:libmyFunc -T link:lib myFunc.m -C
这个指令有一些需要解释,网上有三个版本,有的前面加了-t,有的后面没有-C,那样都是行不通的,有-t的话指令不支持了,编译出错,之所以后面加上 -C是为了生成.ctf文件,这个文件对后面的库初始化很重要。OK,这一步完成,我们就有了libmyFunc.h,libmyFunc.lib,libmyFunc.dll,libmyFunc.ctf四个文件。
中间插一些小工具:链接: https://pan.baidu.com/s/1dFLAn8t 密码: fifh,这个软件可以查看dll文件里面的函数
我们需要用的函数是libmyFuncInitialize,libmyFuncterminate,以及mlxMyFunc。有的网友会问,为什么没有所谓的mlfmyFunc,C++编译出来的dll文件确实只有mlxmyFunc,要想使用mlfmyFunc,需要使用C编译器,指令如下:mcc -W lib:libmyFunc -T link:lib myFunc.m -C,这样生成的dll文件里面就有mlfmyFunc函数了,当然,功能是一样的。
第二步:QT中调用生成的库,有显示调用和隐式调用两种方式,显式调用一般是在没有.lib文件的情况下使用,隐式调用则显得很方便,清洁明了,所以这里我们只介绍一下隐式调用
(1)首先将上面生成的.h,.lib文件拷到QT的.h文件目录下面,然后把.dll,.ctf文件拷到debug输出目录下面,这方面Qt和VS不一样的是,VS的.exe文件和.h,.cpp等文件是在同一个目录下面的,但是Qt的输出目录是自己设置的,需要先空工程运行一下,就可以找到debug目录了
(2)然后就是在.pro文件里面配置Matlab库和头文件的路径了,如下图所示即可:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = MatlabTest
TEMPLATE = app
SOURCES += main.cpp\
mainwindow.cpp
HEADERS += mainwindow.h \
libmyFunc.h
FORMS += mainwindow.ui
OTHER_FILES += libmyFunc.ctf
INCLUDEPATH += E:\Matlab2014a\Matlab2014aInstall\extern\include\
E:\Matlab2014a\Matlab2014aInstall\extern\include\win64
LIBS += E:\Matlab2014a\Matlab2014aInstall\extern\lib\win64\microsoft\libmx.lib\
E:\Matlab2014a\Matlab2014aInstall\extern\lib\win64\microsoft\mclmcr.lib\
E:\Matlab2014a\Matlab2014aInstall\extern\lib\win64\microsoft\mclmcrrt.lib\
E:\Matlab2014a\Matlab2014aInstall\extern\lib\win64\microsoft\libmat.lib\
E:\Matlab2014a\Matlab2014aInstall\extern\lib\win64\microsoft\libmex.lib\
E:\Matlab2014a\Matlab2014aInstall\extern\lib\win64\microsoft\libeng.lib\
F:\VSFiles\QtFiles\MatlabTest\libmyFunc.lib
(3)下面就是测试程序部分了
int MainWindow::ClickToShow()
{
// 此处调用Matlab函数
libmyFuncInitialize();
double _x[5] = {1,2,3,4,5};
double _y[5];
mxArray *im = mxCreateDoubleMatrix(1,5,mxREAL);
mxArray *out = mxCreateDoubleMatrix(1,5,mxREAL);
memcpy(mxGetPr(im),(void *)_x,sizeof(_x));
mlxMyFunc(1,&out,1,&im);
memcpy(_y, (double*)mxGetPr(out), sizeof(_y));
libmyFuncTerminate();
QString ResultShow = QString::number(_y[2]);
QMessageBox::information(NULL,"OK",ResultShow);
return 1;
}
我这里将测试程序写在了一个按钮的槽函数里面,便于测试,大概的框架就是先调用库初始化函数:libmyFuncInitialize(),然后调用我们的功能函数mlxMyFunc(),最后调用结束时使用libmyFuncTerminate()函数
如果程序没什么问题,那么结果应该是这样的:
但是,在这个过程中,我遇到了一个纠结了四五天的问题,同样的程序,放在VS2013里面,输出结果就正常,但是放在Qt里面虽然编译通过(当时我还不知道要把.ctf文件放到.dll目录下面),但是结果一直是0,我翻查了国内外很多网页都没有找到直接的答案。
搞技术只要坚持一定会有答案的,这不是真理,这是信念。
在各种调试之后,我把问题锁定在了初始化方面,因为libmyFuncInitialize()函数是bool类型,在VS里面返回值是true,但是在Qt里面是false,我查了很多网页,发现跟初始化相关的我们能操作的只有.ctf文件了,然后我就把.ctf文件放在跟.dll文件相同的目录下面,终于,我成功地连编译都出问题了:
程序这么简单,我们能操作的很少,这种异常实在不知道从何处下手,然后就继续翻网页,网页上说有可能是Qt调试器的问题,我就没有点击调试,直接运行程序了一下,然后整个世界都亮了,结果是正确的。但是调试就依然不行,而调试总是有必要的,解决放案如下:
工具->选项->调试器
把C++异常的勾号取消,然后点击Apply就可以了。
没错,就是在将近有几百个异常的情况下跑出来的正确答案,至于这些异常如何根除,我们这里就无法操作了。
VS和Matlab的混合编程相较而言是更简单实现的,这里就不多作介绍了,如果有问题可以评论联系我。