发信人: roy (中国大兵), 信区: Matlab
标 题: VC++ 中编译 MEX 程序(zz)
发信站: 红果园 (2003年10月30日11:58:08 星期四), 站内信件
VC++ 中编译 MEX 程序
1. 目的
一般情况下,我们都是在MATLAB命令行或DOS命令行下编译MEX程序。 所用的命令就是
:mex filename.c 这有很多不方便的地方:
a. 虽然mex也可以编译C++的mex程序,但是它的主框架仍是C的 a. 当程序有多个模块
时,需要多次使用mex命令,操作很麻烦
b. 不能利用VC特有的ClassWizard自动创建和维护类
c. 不能用MFC类库编写应用程序
d. 不能方便地进行类似VC的项目管理
这样一个命令行的编程环境可能会大大束缚你的想象力... 其实解决问题的方法很简单
,下面以VC6环境为例详细解说如何在IDE中编译MEX程序。
2. 步骤
(1)准备工作 (这里假设MATLAB的路径为:C:/MATLAB)
a. 由matlab.def创建库文件matlab.lib
进入c:/matlab/extern/include目录,用lib命令生成matlib.lib
C:/>cd /matlab/extern/include
C:/MATLAB/extern/include>lib /def:matlab.def /out:matlab.lib
Microsoft (R) Library Manager Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
LIB : warning LNK4068: /MACHINE not specified; defaulting to IX86
Creating library matlab.lib and object matlab.exp
C:/MATLAB/extern/include>
警告信息不用理它。
b. 修改mex.h
该文件也在C:/MATLAB/extern/include目录
找到这一行:void mexFunction(
替换为 : __declspec( dllexport ) void mexFunction(
另保存为 :mex_vc.h
(2)启动VC,创建MFC AppWizard(dll)程序框架
(3)设置系统选项
a. 设定头文件和库文件路径
菜单Tools->Options->Directories
Include files:添加c:/matlab/extern/include
Library files:添加c:/matlab/extern/include
b. 设置编译连接选项
菜单Project->Settings
C/C++->Preprocessor definitions: 添加MATLAB_MEX_FILE
Link->Object/Library modules: 添加matlab.lib
注1. 其它优化、调试以及头文件、库文件等选项看情况调整
注2. Release版在General->Microsoft Foundation Classes选项中, 必须设置为Use
MFC in a Static Library. 原因不明 (4)编写DLL主程序
a. 文件名要用.cpp为扩展名,头两行必须是:
#include "stdafx.h"
#include "mex_vc.h"
b. 编写mexFunction函数,用如下格式声明:
void mexFunction(
int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
...
}
(5) 象普通VC的DLL程序一样继续编写其它部分程序,加入其它模块
(6) 调试错误,用F7编译,生成DLL。我的例子:
--------------------Configuration: MatWave - Win32 Release------------------
--
Compiling resources...
Compiling...
StdAfx.cpp
Compiling...
MatWave.cpp
sample.cpp
mex.cpp
Generating Code...
Linking...
Creating library Release/MatWave.lib and object Release/MatWave.exp
LINK : warning LNK4089: all references to "SHELL32.dll" discarded by /OPT:RE
F
LINK : warning LNK4089: all references to "comdlg32.dll" discarded by /OPT:R
EF
MatWave.dll - 0 error(s), 2 warning(s)
大功告成,有两个警告,不理它。 拿到MATLAB里面试试吧,不过要有非法操作和异常退
出的心理准备哦.
另外:如果要在MATLAB运行中重新编译DLL,需先执行: clear mex
在MATLAB中可调用的C或Fortran语言程序称为MEX文件。MATLAB可以直接把MEX文件视为它的内建函数进行调用。MEX文件是动态链接的子例程,MATLAB解释器可以自动载入并执行它。MEX文件主要有以下用途:
对于大量现有的C或者Fortran程序可以无须改写成MATLAB专用的M文件格式而在MATLAB中执行。
发信人: roy (中国大兵), 信区: Matlab
标 题: 在vc中调用matlab的方法
发信站: 红果园 (2003年11月09日14:53:14 星期天), 站内信件
Matlab提供了多种与C/C++混合编程的方式
目前实现的有以下一些。
1. COM组件编程。
在Matlab中,调用comtool工具,把.m文件编译成标准COM组件。
这种方式是Matlab主推的方式。
2. 用VC中的Matlab Addin,向导将.m文件直接编译成可执行文件。
这也是比较标准的做法。在实验中,没有遇到任何问题。
这种方法存在的问题是:生成的C语言代码基本不能改动,无法加入自己的代码。
如果不调用图形界面,可以加入自己的代码。
例如:其生成的主程序一般为
int main(int argc, const char * * argv) {
return mclMain(argc, argv, mlxReadd, 0, &_main_info);
}
不要调用mclMain函数,而是调用它带有原始接口的函数
void mlxReadd(int nlhs, mxArray * plhs[], int nrhs, mxArray * prhs[])
通常可以。不过这样略去了一些初始化的过程。具体可以参考Matlab帮助。
自动生成的主程序做了如下工作。
1. Defines persistent/global variables
2. Initializes the feval function table for run-time feval support
3. Performs wrapper-specific initialization and termination
4. Initializes the constant pools generated by optimization
我要实现的是下面这种,我觉得最简单,适合编写控制台程序。
3. 直接写主程序,然后通过Matlab中编译的库机制,实现程序的混编。
由于Matlab不提倡这种调用,在v6.5版中,没有这部分的帮助。参考Matlab6.1中的
Compiler
手册的Mixing M-Files and C or C++ (P110)
主程序的写法的例子为:main.c
#include
#include
#include "matlab.h"
//这里声明将要调用的.m文件
void *mlfReadd( void );
main( int argc, char **argv )
{
PkgInitialize(); /* Initialize the library of M-Functions */
mlfReadd(); /* 调用函数*/
PkgTerminate(); /* Terminate the library of M-functions */
}
只要把这个程序和readd.m文件放在一个目录里,在Matlab中编译就可以了。
编译命令为:
mcc -B sgl -W libhg:Pkg -T link:exe -h myplot main.c libmmfile.mlib
该命令是针对需要图形支持的函数的。
如果不需要图形支持,命令为:(手册里面建议的编译选项)
mcc -t -W lib:Pkg -T link:exe -h mrank mrankp.c libmmfile.mlib
注意这里的Pkg需要和主程序里的PkgInitialize()对应。
以上为直接生成.exe文件
更通常的做法是生成.c和.h文件,在vc里编译。
步骤为:
1. 编译.m文件。例子myplot.m
%example: myplot.m
function myplot(b)
a=b;
plot(a);
命令为:
mcc -t -L C -W libhg:Pkg -h myplot
(注意,我这里用了图形,如果不用的话,应该是-W lib:Pkg)
生成的文件有:
myplot.h
myplot.c
pkg.c
pkg.h
pkg.exports
pkg.mlib
其中有用的是各个源文件myplot.h,myplot.c,pkg.c,pkg.h。
把自己写的主程序main.c和上面的源文件放在一个目录里。
源程序main.c
#include
#include
#include "matlab.h"
void *mlfMyplot( mxArray * );
main( int argc, char **argv )
{
mxArray *N;
N = mlfScalar(25);
PkgInitialize(); /* Initialize the library of M-Functions */
mlfMyplot(N);
PkgTerminate(); /* Terminate the library of M-functions */
}
2.启动VC6.0编译。
设置头文件搜索路径和库文件路径
菜单Tools--Options-Directories下,show directories for改成include files,然后
添加
搜索路径,matlabroot为机器上matlab的安装路径:
matlabroot/extern/include
matlabroot/extern/include/cpp
再将show directories for 改成library files,添加搜索路径:
matlabroot/extern/lib/win32
matlabroot/extern/lib/win32/microsoft/msvc60
这些选项设置好了以后,对每个工程都适用
对于每一个project,要设置
菜单project--settings--link下,在Object/Library modules里去掉原来的加入
kernel32.lib user32.lib gdi32.lib advapi32.lib oleaut32.lib
ole32.lib libmatlb.lib /nologo libmx.lib libmat.lib libmwservices.lib libme
x.lib libut.lib sgl.lib
(注意,这里的库是我从下面启动mcc编译时给出的信息里找出来的,所以可能只对我
有效,其实就是
把需要的库都加上,参考一下配置文件,反正库就是那几个)
把.c和.h文件都加上,编译,运行。
(生成的图上只有一个点,hehe)
这里如果是需要图形库的还需要在.exe所在的目录下建一个bin目录,
从matlabroot/extern/include中copy,FigureMenuBar.fig 和 FigureToolBar.fig到
bin。否则没有菜单和工具栏
3).mcc,mex,mbuild都是作什么用的?
:#FangQ(Qianqian.Fang@dartmouth.edu), 2002/6/22.BigGreen/MathTools#
这个问题我一直都不是很清楚,看过compiler的PDF帮助之后,知道个
大概,也不知道说得对不对:
mcc(生成c/cpp文件)-----m--mex------ mex/dll
|---x--mbuild-----C/C++ compiler----独立执行的程序
mex文件是一种编译后的动态连接文件,需要在matlab中执行,优点
是执行速度比m文件快,而且如果你不想提供m文件源码,可以使用
编译后的mex/dll文件。
mbuild通过调用外部的c/c++编译器,把mcc翻译成的c/c++源码
与matlab的c/c++数学库、图形库链接,得到独立执行的可执行程序。
Creating MATLAB MEX-file
To create executable files from m-files, you can use MCC. MCC is MATLAB to C/C++ compiler. It can compile m-files to executable files with exe or dll extension. For example:
Make a C translation and a MEX-file for myfun.m:
mcc -x myfun
Make a C translation and a stand-alone executable for myfun.m:
mcc -m myfun
Make a C++ translation and a stand-alone executable for myfun.m:
mcc -p myfun
Make a C MEX wrapper file from myfun1.m and myfun2.m:
mcc -W mex -L C libmatlbmx.mlib myfun1 myfun2
Make a C translation and a stand-alone executable from myfun1.m and myfun2.m (using one MCC call):
mcc -m myfun1 myfun2
But there is another way to create MEX files. In this way you have full control of every function that you created and can optimize their speed, memory, size etc.
The components of a C MEX-file
The source code for a MEX-file consists of two distinct parts:
- A computational routine that contains the code for performing the computations that you want implemented in the MEX-file. Computations can be numerical computations as well as inputting and outputting data.
- A gateway routine that interfaces the computational routine with MATLAB by the entry point mexFunction and its parameters prhs, nrhs, plhs, nlhs, where prhs is an array of right-hand input arguments, nrhs is the number of right-hand input arguments, plhs is an array of left-hand output arguments, and nlhs is the number of left-hand output arguments. The gateway calls the computational routine as a subroutine.
In the gateway routine, you can access the data in the mxArray structure and then manipulate this data in your C computational subroutine. For example, the expression mxGetPr(prhs[0]) returns a pointer of type double* to the real data in the mxArray pointed to by prhs[0]. You can then use this pointer like any other pointer of type double* in C. After calling your C computational routine from the gateway, you can set a pointer of type mxArray to the data it returns. MATLAB is then able to recognize the output from your computational routine as the output from the MEX-file.
The following C MEX cycle figure shows how inputs enter a MEX-file, what functions the gateway routine performs, and how outputs return to MATLAB.
Creating MEX-files in Visual C++
Run Visual C++, select New... from File menu. In opened dialog, select "Win32 Dynamic-Link Library". In wizard, select "A DLL that exports some symbols" and press finish. Now everything is ready for building a MEX-file!
Add following lines to main source code:
#include "Matlab.h" //MATLAB API
#pragma comment(lib, "libmx.lib")
#pragma comment(lib, "libmat.lib")
#pragma comment(lib, "libmex.lib")
#pragma comment(lib, "libmatlb.lib")
Add MATLAB_MEX_FILE preprocessor to project settings (Project -> Settings -> C/C++ -> General -> Preprocessor definitions).
Create a text file and rename it to your_project.def. your_project is name of your MEX-file. your_project.def is a definition file for exporting symbols. In this situation, you must export mexFunction. Here is an example:
; mexFunction.def : Declares the module parameters for the DLL.
LIBRARY "ComputePrimes"
DESCRIPTION 'ComputePrimes Windows Dynamic Link Library'
EXPORTS
; Explicit exports can go here
mexFunction
Now you must add following compiler switch to your project (Project -> Settings -> Link -> General -> Project Options):
/def:"./mexFunction.def"
Example
In this example, input argument is an integer non-complex scalar (n) and output is a vector containing first n prime numbers. Name of MEX-file is ComputePrimes. Syntax:
y = ComputePrime(n)
Final Work:
#include "stdafx.h"
#include "Matlab.h"
#include "mexFunction.h"
#pragma comment(lib, "libmx.lib")
#pragma comment(lib, "libmat.lib")
#pragma comment(lib, "libmex.lib")
#pragma comment(lib, "libmatlb.lib")
//return TRUE if n is a prime number
BOOL IsPrime(int n)
{
for (int i=2; i<=n/2; i++)
{
if (n%i==0)
return FALSE;
}
return TRUE;
}
void ComputePrimes(double* y, int n)
{
int index=0, i=2;
while (index!=n)
{
if (IsPrime(i))
{
y[index]=i;
index++;
}
i++;
}
}
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[])
{
if (nrhs != 1)
{
mexErrMsgTxt("One input required.");
}
else if (nlhs > 1)
{
mexErrMsgTxt("Too many output arguments");
}
/* The input must be a noncomplex scalar integer.*/
int mrows, ncols;
mrows = mxGetM(prhs[0]);
ncols = mxGetN(prhs[0]);
if (!mxIsDouble(prhs[0]) || mxIsComplex(prhs[0]) ||
!(mrows == 1 && ncols == 1))
{
mexErrMsgTxt("Input must be a noncomplex scalar integer.");
}
double x, *y;
/*
e.g.
*x=4,
*y=2, 3, 5, 7
*/
x = mxGetScalar(prhs[0]);
/* Create matrix for the return argument. */
plhs[0] = mxCreateDoubleMatrix(mrows /* 1 */, (int) x, mxREAL);
y = mxGetPr(plhs[0]);
//call ComputePrimes subroutines to fill vector of primes
ComputePrimes(y, (int) x);
}
3. Compiling M-file into the MEX-file
3.1. To create a MEX-file from a M-file, your M-file must be written as function M-file.
If you have a script M-file you must convert it to a function. To convert a script to a function simply add a function line at the top of the M-file (the function can be both - with and without parameters).
3.3. Enter the 'mcc' command:
>>mcc -x houdini
The -x option is used in case of M-file compilation. This 'mcc' command generates:
A file named houdini.c containing MEX-file C source code.
A file named houdini.h containing the public information.
A file named houdini _mex.c containing the MEX-function interface (MEX Wrapper).
A MEX-file named houdini.mexsol. (The extension of the executable MEX-file depends of your platform, e.g., on the PC the file is named houdini.dll).
'mcc' automatically invokes mex to create houdini.mex from houdini.c and houdini_mex.c. The mex utility encapsulates the appropriate C compiler and linker options for your system.
NOTE: Ignore warning about break statement in magic-function.
3.4. After compiling, a MEX file called houdini.mexsol must be in your working directory. This file can be used like any M-file.
>>x=houdini(4)
4.4. Finally, you should check the compiler by using one of the graphics examples provided by the developer.
Let us choose the flames.m file is stored in the directory $MATLAB/extern/examples/sgl.
Copy this file to your working directory and type:
- for a C | >>mcc -B sgl flames.m |
- for a C++ | >>mcc -B sglcpp flames.m |
http://stommel.tamu.edu/~baum/toolboxes.html //Matlab工具箱列表
东北大学 薛定宇 (原作)
转载时请注明作者信息、网址,谢谢
MATLAB 到 C 语言程序的转换可以由两种途径完成,其一是 MATLAB 自己提供的 C 语言翻译程序 mcc, 另一种是原第 3 方公司 MathTools 开发的 MATCOM。后者出现较早,功能远比 MATLAB 自己的翻译程序强大,所以 MathTools 公司已经被 MathWorks 公司收购,并已将其开发技术融于新推出的 MATLAB 6.0 (Release 12) 中。
依本人的观点,二者都不完善,有大量的 MATLAB 函数及数据类型是不能兼容变换的,所以有时会发现将简洁的 MATLAB 程序翻译成 C 语言程序很晦涩。翻译后的 C 程序几乎不适合手动去维护,更谈不上升级了。
有几个不兼容的地方是不能令人容忍的,例如 eval() 函数在 C 翻译下是不兼容的,最新的 MATLAB 6 才刚刚敢说已经部分兼容了,但离真正的兼容还有很长的路要走,有很多艰难的技术困难需要克服,短时间内不可能有突破性的进展。另一个大的问题是,众所周知,MATLAB 新的控制系统工具箱中定义了大量的 LTI 类,MATLAB 5 开始也允许使用类与对象的概念,这已经向“面向对象”的编程走了一大步,但 MATLAB 到 C 的翻译明显都不支持“对象”的数据类型,所以在控制系统分析与设计 (当然还有其他的领域) 中这样的转换几乎没有什么实际意义,所以不要将这样的转换太理想化。
从转换的程序速度来看,因为 mcc 和 MATCOM 都沿用了 MATLAB 的程序运算机制,所以不可能大幅度地提高程序运行速度。相反地,如果将 MATLAB 程序中明显的瓶颈部分用 C 语言按照 MEX 格式编写,则可以大大加快速度。作者在《科学运算语言 MATLAB 5.3 程序设计及应用》一书中以例子做过探讨,MCC 可以比快 50%, 而 MEX 的形式可能快上百倍。
〖举例〗分形问题:从初始点(x0,y0) 出发,按下面的公式生成新的点 (x1,y1)
其中 gi 为 (0,1) 区间均匀分布的随机数。要求从 (x1,y1) 再生成 (x2,y2),...,直至生成 1,000,000 个点(有点夸张,但太少了用 MATLAB 测时间不准)。可以下载用 MATLAB 的 M-函数写的程序、用 Mex_C 写的程序。程序调用语句为:
>> N=1000000; v=rand(N,1); tic; [x,y]=frac_tree(0,0,v,N); toc
然后测试一下速度,再想法用 MATCOM 或 MCC 转换一下,再试试速度。问题:MATCOM 程序到底比 M 函数快多少?我用 Mex_C 实现的速度可是快100多倍啊!下面有文章介绍,用 MATCOM+VC 能平均快1.5倍 (在别的应用上),依作者的观点,为了这区区 1.5 倍还不至于自己给自己找麻烦去用 MATCOM。
这样看,可能 MATLAB 到 C 转换唯一的好处就是它能开发具有自主版权的软件了。 所以本人一般不太赞同用这样的转换方法去开发程序,尤其不赞成刻意追求 MATLAB + C 的方式。本人认为:除非必要,一般别采用这样的方法。提出这样的观点,欢迎商榷。
MATCOM 目前有 BC 和 VC 两个程序,MATLAB + VC 之家中收录了一些文章。作者见到有下载区有这样的软件。
- 在这里给出一个下载区的链接