找回密码
 注册
Simdroid-非首页
查看: 15159|回复: 162

【原创】程序中使用MATLAB编译产生的DLL (VS2005, MATLAB7.5, mwArray)

[复制链接]
发表于 2007-10-6 22:51:33 | 显示全部楼层 |阅读模式 来自 新加坡
本帖最后由 messenger 于 2011-3-27 20:04 编辑

最近有几个帖子都在讨论有关在C++程序中使用MATLAB编译产生的动态链接库DLL。本来想用原来帖子中给出的m代码作为例子,无奈那段代码其实无法执行。为了避免分散注意力,也为了更好地讨论问题,于是决定还是另外新开一个主题,以简单的例子,和大家一起讨论如何在C++程序中使用matlab编译产生的DLL。

同时MATLAB最新版本R2007b刚刚发布不久,其中包含编译器4.7版,有了一些新的特性,于是也借这个例子来验证一下相关的技术有没有发生大的变化。

最近讨论的问题是关于在C++程序中调用MATLAB编译产生的动态链接库。具体的问题是在调用DLL中函数时传递参数。我们知道,MATLAB可以把m代码编译成两种DLL,分别是C语言接口和C++语言接口的DLL。论坛上的问题是关于调用C++接口的DLL中的函数,所以这里我们就以这种DLL为例来介绍。在C++接口的DLL中,函数的输入、输出参数都是mwArray对象。所以问题归结为如何在C++程序中使用mwArray

这个问题本来可以只用一个简单的C++程序来练习,而不需要MATLAB编译的DLL。不过为了模拟实际情况,选择以一个更为接近实际的m代码作为例子。在这个例子中,输入输出都是矩阵,至于标量,它也是一个一行、一列的矩阵。

实验环境:Windows 2003 Std Server with SP2 (En),MATLAB R2007b,Visual Studio 2005。MATLAB安装路径:h:\MATLABR2007b。

实验内容:把一个简单的m代码编译成C++接口的DLL,然后在C++程序中调用。为了简单起见,这里的C++程序是一个Win32 Console程序,而不是Windows图形界面的程序,不过不妨碍我们的讨论。

下面是这个例子用到的m代码。它定义了一个名为myadd2的函数:
  1. function [y,z] = myadd2(a, b)
  2. % dummy function, just to demonstrate the idea
  3. y = a+b;
  4. z = a+2*b;
  5. end
复制代码
首先把这个函数编译成C++接口的DLL。为此,我们需要先设置MATLAB编译器。具体做法是在MATLAB命令行执行“mbuild -setup”。然后用下面这行命令把myadd2函数编译成一个C++接口的DLL:
  1. mcc -W cpplib:libmyadd2 -T link:lib myadd2
复制代码
结果,我们将会得到包含libmyadd2.dll,libmyadd2.ctf,libmyadd2.h,libmyadd2.lib等在内的一些文件。接下来我们只需要这四个文件。请注意:在MATLAB R2007b之前,这些文件都会在和编译
的m代码所在的目录中,而在MATLAB R2007b,缺省情况下这些文件会在Documents and Settings中用户的My Documents目录中


此时,打开libmyadd2.h看看,在文件的最下面我们可以发现C++接口的函数定义。仔细观察过后,我们可以发现,这个接口函数的参数是按照这样的顺序定义的:输出参数的个数、输出参数、以及输入参数。

然后在VS2005中创建一个Win32 Console的VC++工程,我在测试时取名为testmyadd2_r2007b。把以上四个文件拷贝到VC++工程的源代码所在目录。

接下来设置VC++,让它能找到MATLAB接口函数的定义及连接库函数。可以有两种设置方式:一种是改VS2005中关于VC++的设置,这样的好处是每个新的工程都能自动获得这个设定;而另一种是只改当前工程的设置,也就是设置只对该工程有效。这里用后一种方式。

在VS2005中打开工程testmyadd2_r2007b,选择菜单“Project-->Properties,在出来的对话框上,把MATLAB提供的include路径加到VC++的头文件搜索路径。如图所示:



===============================================================================================

补充一下:如果使用MATLAB2008之后的版本(注:该信息源自roc的精华帖:程序中使用MATLAB编译产生的DLL (VC6.0, MATLAB R2010b, mwArray)),我使用的是MATLAB2010b,则上述taohe兄给出的步骤有两个地方需要小调整:
1.增加include路径时,看看mclmcr.h在哪个路径下,应该是不能要后面那个“win32”;
2.vs下的代码去掉两个#include,最前面几行改成:
  1. #include "stdafx.h"

  2. #include <iostream>
  3. #include "libmyadd2.h"


  4. int _tmain(int argc, _TCHAR* argv[])
  5. {

  6.         std::cout << "Hello world!" << std::endl;
  7. ...
复制代码
也就是去掉mclmcr.h和mclcppclass.h这两个include,如此编译即可正常。

————源自bainhome 2010-12-7的补充

===============================================================================================

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评分

2

查看全部评分

 楼主| 发表于 2007-10-6 22:53:06 | 显示全部楼层 来自 新加坡
Simdroid开发平台
然后把相应的lib所在目录加到linker的额外搜索路径上。如图所示:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-6 22:54:37 | 显示全部楼层 来自 新加坡
接下来,告诉VC++,我们的这个程序需要连接到另外两个额外的库函数:libmyadd2.lib和mclmcrrt.lib。中间用空格隔开。如图所示:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-6 22:55:58 | 显示全部楼层 来自 新加坡
最后则是程序代码。这个程序只有一个main函数,其完整代码附在下面给大家参考。欢迎大家拍砖。谢谢!
  1. #include "stdafx.h"

  2. #include <iostream>
  3. #include "mclmcr.h"
  4. #include "mclcppclass.h"
  5. #include "libmyadd2.h"


  6. int _tmain(int argc, _TCHAR* argv[])
  7. {

  8.         std::cout << "Hello world!" << std::endl;
  9.         /* Initialize the MCR */
  10.         if( !mclInitializeApplication(NULL,0) )
  11.         {
  12.                 std::cout << "Could not initialize the application!" << std::endl;
  13.                 return -1;
  14.         }

  15.         // initialize lib
  16.         if( !libmyadd2Initialize())
  17.         {
  18.                 std::cout << "Could not initialize libmyadd2!" << std::endl;
  19.                 return -1;
  20.         }

  21.         try
  22.         {
  23.         // declare and initialize a
  24.         mwArray a(2, 2,  mxDOUBLE_CLASS);
  25.         double *aData;
  26.         aData = new double[4];
  27.         int i;
  28.         for( i=0; i<4; ++i)
  29.         {
  30.                 aData[i] = 1.0*i;
  31.         }
  32.         // print output
  33.         std::cout << "a = " << std::endl;
  34.         std::cout << aData[0] << ",\t" << aData[1] << std::endl;
  35.         std::cout << aData[2] << ",\t" << aData[3] << std::endl;

  36.         a.SetData(aData, 4);

  37.         // declare and initialize b
  38.         mwArray b(2, 2,  mxDOUBLE_CLASS);
  39.         b(1,1) = 11.;
  40.         b(1,2) = 12.;
  41.         b(2,1) = 21.;
  42.         b(2,2) = 22.;

  43.         mwArray y(2, 2,  mxDOUBLE_CLASS);
  44.         mwArray z(2, 2,  mxDOUBLE_CLASS);

  45.         // call the function
  46.                 myadd2(2, y, z, a, b);

  47.         // copy data from mwArray to C++ objects

  48.         // allocate outputs
  49.         double *yData, *zData;
  50.         yData = new double[4];
  51.         if( yData == NULL )
  52.         {
  53.                 std::cout << "Failed to allocate memory for yData!" << std::endl;
  54.                 return -1;
  55.         }

  56.         zData = new double[4];
  57.         if( zData == NULL )
  58.         {
  59.                 std::cout << "Failed to allocate memory for zData!" << std::endl;
  60.                 return -1;
  61.         }

  62.         // copy data from mwArray to C++
  63.         y.GetData(yData, 4);
  64.         z.GetData(zData, 4);

  65.         // print output
  66.         std::cout << "y = " << std::endl;
  67.         std::cout << yData[0] << ",\t" << yData[1] << std::endl;
  68.         std::cout << yData[2] << ",\t" << yData[3] << std::endl;

  69.         std::cout << "z = " << std::endl;
  70.         std::cout << zData[0] << ",\t" << zData[1] << std::endl;
  71.         std::cout << zData[2] << ",\t" << zData[3] << std::endl;

  72.         
  73.         // deallocate memory
  74.         delete [] aData;
  75.         delete [] zData;
  76.         delete [] yData;
  77.         }
  78.         catch( const mwException& e)
  79.         {
  80.           std::cerr << e.what() << std::endl;
  81.                   
  82.         }
  83.         // terminate the lib
  84.         libmyadd2Terminate();

  85.         // terminate MCR
  86.         mclTerminateApplication();


  87.         return 0;
  88. }
复制代码

[ 本帖最后由 taohe 于 2007-10-6 23:18 编辑 ]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-6 23:02:30 | 显示全部楼层 来自 新加坡
实验的结果表明,在C++程序中使用MATLAB编译产生的C++接口DLL非常容易。mwArray也很容易使用。另外,最新的MATLAB R2007b中关于这部分并没有什么大的变化。这个练习适合MATLAB 7.0以后直到MATLAB R2007b的所有版本。
回复 不支持

使用道具 举报

发表于 2007-10-7 09:15:11 | 显示全部楼层 来自 湖北武汉
就我个人6.5混编的经验
我很少弄DLL
直接编译M文件为cpp,h文件即可
VC工程中引用,按.h文件格式调用即可
这样混编基本没有任何难度,将MATLAB程序看成MFC一个类即可,看看extern里面
相关头文件的定义,跟看MSDN一样。
抛开mclTerminateApplication();这些,这应该是一个通用的办法
手头只有6.5,不知道7.5还能生成cpp么?
回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-7 12:03:52 | 显示全部楼层 来自 新加坡
从matlab7.0开始,其编译器的功能就和以前版本不一样了。它不再把m代码翻译成C/C++源代码,而是对m代码作个简单的wrapper,通常以动态链接库的形式提供给用户以方便用户在其他的程序中使用。所以,在matlab 7.x,编译m代码不能得到以前那种意义的C/C++源程序。

不过,仅从软件开发的角度来看,我觉得用DLL来打包更为方便。如果m函数的接口不变,那么每次改变m代码后,我们只需重新编译m代码,获得新的DLL及CTF,而不需要重新编译VC客户程序。这在开发大型软件时有很大的优越性。

评分

1

查看全部评分

回复 不支持

使用道具 举报

发表于 2007-10-7 12:26:07 | 显示全部楼层 来自 湖北武汉

这个我欠考虑了
不过,从软件开发角度说,7.X混编实在太庞大
我都成了6.X混编的遗老遗少:lol
回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-7 15:22:40 | 显示全部楼层 来自 新加坡
呵呵,要与时并进呀。新版的matlab有可能带给我们好的技术,比如matlabR2007b中的多线程计算,就是个好例子。现在多核电脑在个人电脑上也很普遍了,使用新版的matlab的多线程计算,就能很好的利用这些新的硬件从而获得更好的计算性能。

有些技术,在刚出来的时候可能是最好的,不过可能会随着时间的推移,而被淘汰。matcom就是个例子,其实我当初用过matcom而且也挺喜欢他的,而且那时也刚开始学习VC。所以二者结合后给我的感觉很好。只可惜,matcom已经成为历史。现在有时看见有人在找matcom,都不知道说什么好。

不过,我也是挺喜欢恋旧的。我电脑上还有matlab6.5.1。感觉那版很不错。VC6.0也不错,虽然那是差不多十年以前的产品,到现在还是必装软件之一。

好像有点扯远了。其实我想说的是:没有必要总是更新工具软件。如果已经是老用户,而且手中的旧版本能满足要求,或者没有必要的理由,就不用换;反之,如果刚开始学习使用某个软件,不妨从最新版开始。
回复 不支持

使用道具 举报

发表于 2007-10-7 18:49:50 | 显示全部楼层 来自 湖北武汉
最后跑次题:我先学混编,再学VC
鼓捣了一段VC/MATLAB混编
最近放弃了,自己写了个类似于MATLAB AXES的VC绘图类
语法,功能,完全类似MATLAB
所以,基本远离了MATLAB混编
回复 不支持

使用道具 举报

发表于 2007-10-10 20:57:07 | 显示全部楼层 来自 北京
多谢taohe的文章,我想问一下,ctf文件是干嘛用的,谢谢,记得matlab 6.5版里面编译为DLL时没这个东西啊。
回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-10 21:14:21 | 显示全部楼层 来自 新加坡
原帖由 daoxiangcun2002 于 2007-10-10 20:57 发表
多谢taohe的文章,我想问一下,ctf文件是干嘛用的,谢谢,记得matlab 6.5版里面编译为DLL时没这个东西啊。


这是matlab7.0以后matlab编译器的新特性。它和旧版技术不兼容。ctf其实就是一个zip文件,其中包含加密或者说编码过的一些m代码。其中有你自己的代码,以及matlab编译器通过分析你的代码根据依赖关系找到的其他一些m代码。
回复 不支持

使用道具 举报

发表于 2007-10-18 17:27:12 | 显示全部楼层 来自 北京
还有一个问题,可能也有些朋友都遇见过,还请taohe和版主等各位牛人解释一下,就是matlab 6.5和7.0是不兼容的,如果一台计算机上面同时装了matlab 6.5和7.0的话,那么我要用7.0将m文件编译为dll的话,能够不出问题吗?
我最初的时候为了解决一个问题是想将m文件编译为c文件,这个想法是在看过邓科的那几篇关于matlab与VC混合编程的文章之后产生的,起初装了一个matlab 7.0但是编译不出来,后来换成6.5才行.所以就产生了这个问题,如果matlab 6.5和7.0同时存在一台计算机上面的话,我们应该注意些什么?可能会产生什么样的问题?
我也是看了刚才taohe的帖子才有这个想法的,还请taohe和大家给解释一下,谢谢!

评分

1

查看全部评分

回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-19 22:44:35 | 显示全部楼层 来自 新加坡
我现在同时安装了6.5.1,r2006b,r2007b。在使用某个版本时,我把另外几个版本的安装目录改名。比如r2006b安装在h:\matlabr2006b,不用的时候我把它改成h:\matlabr2006bxxx
回复 不支持

使用道具 举报

发表于 2007-10-21 21:50:26 | 显示全部楼层 来自 北京
多谢taohe,我原来装了matlab 6.5(R13),现又装了7.0(R14),发现如果只有matlab7.0的话,调用matlab编译后的dll是可以的,就像你给的例子一样(在别人的计算机上试的),如果同时装了两个,即使把matlab6.5所在的文件夹改名,VC6.0里面编译运行时还是出现错误,说是“找不到mclmcrrt71.dll",不知道怎么回事,可能同时装多个版本容易出问题吧。
另外,我近几天看了一些matlab网站上的support documentation,发现matlab的版本经常有一些奇怪的变动,比如comtool这个命令在7.5(R2007b)中变成了deploytool,还有matlab builder for com 变成了matalb builder for .NET,看来以后要多与新版本接轨了,不然很多新的功能都不知道,比如说deploy这个打包功能,在7.0里面就没有。
回复 不支持

使用道具 举报

发表于 2007-10-24 11:36:12 | 显示全部楼层 来自 山东青岛
老师同学,您好我按您的步骤编译错误如下:
fatal error C1083: Cannot open include file: 'mclmcr.h': No such file or directory
这个类mwArray在哪声明的呢?
mclmcr.h 和 "mclcppclass.h" 不是已经包含于libmyadd2.h了吗?
为什么还包含一次啊?
而且这两个是干吗的 在哪呢?
谢谢!
回复 不支持

使用道具 举报

发表于 2007-10-24 12:02:07 | 显示全部楼层 来自 山东青岛
老师同学 我刚刚找了找
我的mclmcr.h 和 "mclcppclass.h" 在C:\MATLABR2007b\extern\include少了个win32 子目录
去掉之后 就行了
黑窗口闪了一下就没有了
好像
a的值是
0  1
2  3
后面的看不清 都不一样
结果和你的也不一样
我看来还没有理解
回复 不支持

使用道具 举报

 楼主| 发表于 2007-10-24 19:10:22 | 显示全部楼层 来自 新加坡
这个程序是个命令行程序,如果没有在VS2005的IDE中执行的话,最好开一个DOS窗口,进入程序所在目录,然后执行程序,这样就能看到运行结果,不要在Explorer中运行。
回复 不支持

使用道具 举报

发表于 2007-11-4 16:22:12 | 显示全部楼层 来自 上海
很感谢楼主的分享~!我正在学习这方面的知识。
我按照您提供的步骤执行下来,遇到一些问题
事件1、在输入命令mbuild -setup之后,Select a compiler: 的选项只有1,第二个选项是none。
事件2 、如果我直接执行mcc -W cpplib:libmyadd2 -T link:lib myadd2 时,会报错。
matlab说编译cpp文件出错,在工作目录下只能得到libmyadd2.ctf,libmyadd2.h文件,而没有libmyadd2.lib,libmyadd2.dll文件。
部分错误代码:
Error libmyadd2.cpp: 112  missing parameter type
Error libmyadd2.cpp: 112  skipping `&' `y' `,' `mwArray' `&' `z' `,'
……
Error libmyadd2.cpp: 116  syntax error; found `end of input' expecting `}'
17 errors, 3 warnings

  E:\MATLAB71\BIN\WIN32\\..\MEX.PL: Error: Compile of 'libmyadd2.cpp' failed.

事件3、当我执行mcc -l myadd2 ,则不会报错,而且会生成所有的文件。但是我在vc2005里调试的时候,则会报错,说我调用的函数 myadd2 没有定义。
我去myadd2.h里查看时,
bool myadd2InitializeWithHandlers
bool myadd2Initialize(void);
void myadd2Terminate(void);都有声明。
但是我自己的myadd2的声明变成了
……
void mlxMyadd2(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]);
extern LIB_myadd2_C_API
void mlfMyadd2(int nargout, mxArray** y, mxArray** z
                                       , mxArray* a, mxArray* b);
……
我把main函数里的函数名改成上面的任意一个都没用,因为都会报参数错误。
-----------------------------------------------------------------
问题1:同样的步骤为什么结果不同,请问我这里是哪里出了问题?是因为我mbuild -setup命令后没有出现vc++的选项而引起的错误吗?是否我少装了什么呢?
问题2:我看help也没看懂-l和-w有什么大的不同。。为什么用另外一个命令编译,得到同样类型的文件,而myadd2传的参数就不同了。
问题3:百度了一下mxArray和mwArray的区别,只知道是不同的数据类型,具体也没太明白。
是不是mwArray是C++的接口对象,而mxArray或许是C的接口对象?(-l命令编译了c接口文件?)

现在不是很清楚这里的编译问题,有很多疑惑,看了help也不是很明白,感谢帮助!
回复 不支持

使用道具 举报

发表于 2007-11-4 17:35:51 | 显示全部楼层 来自 上海
cpplib         C++ Library           -W  cpplib:<shared_library_name> -T link:lib
csharedlib  C Shared Library     -W  lib:<shared_library_name> -T link:lib
我现在稍微明白问题2.3了。是我编译成了c接口的文件。所以在vs2005中调试时候,函数不同了。
我的matlab7.0版,vs2005;
看到E:\MATLAB71\extern\lib\win32\microsoft目录下,只有到msvc50~71
是指我的vs版本太高了,matlab7.0不支持么?
看楼主的范例,似乎matlab7.5支持vs2005?

谢谢~
如果是vs版本太高,那为什么我编译c的可以,而编译c++就不行呢?
回复 不支持

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-4-19 12:49 , Processed in 0.050075 second(s), 13 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表