mex是Matlab提供的一种混合编程方式。通过mex,用户可以在Matlab中调用C/C++或者Fortran编写的计算程序,加速Matlab内部的矩阵运算(尤其是加速Matlab代码中的for循环)。mex本质上是一个动态链接库文件,可以被Matlab动态加载并执行。
本文介绍Windows环境下基于mingw的mex开发流程和一些注意事项。
首先运行mex -setup配置mex开发环境,主要是设置编译器。
一般Windows下最常用的是采用Visual Studio进行开发;在Unix系统下一般是采用gcc开发。
Windows下利用mingw进行Matlab mex开发主要有两种方式:
普通方式—使用Matlab的mex命令 Matlab提供了mex命令,可以方便地将C/C++或者Fortran代码编译为mex文件。mex命令的选项与mingw有很多相似之处,例如-I,-L,-l等等,熟悉mingw环境的童鞋很容易上手。mex命令支持的全部选项可以输入mex -help或者doc mex查看。 mex -v -g -I %MEX_INCLUDE% -L %MEX_LIBRARY% xx.c -lmx -lmex -lmat -leng -lyy -lzz
使用gnumex 下载gnumex,参照下面方式进行安装。 此时输入mex -setup就会多出一个选项,选择gnumex即可。以后使用mex命令则默认调用的是mingw编译器。 但是这种方式有两个局限。首先,如其名所暗示的那样,gnumex只能利用mingw进行mex开发,若使用mbuild将m代码编译为可执行文件或者DLL文件,此时不能使用mingw。因为gnumex只是修改了mexopts.bat文件。 并没有修改mbuild相关的配置文件。其次,需要额外安装工具箱。比较麻烦。
上述两种方法一般均需要在Matlab环境下操作,实际上,我们完全可以脱离Matlab环境,基于mingw编译器完成mex文件的开发和调试。这主要是基于以下两个事实:1. mex文件本质上是一个动态链接库文件,可以由相应的编译器生成。2. Matlab为Matlab与C/C++混合编程提供了相应的函数库(libmx.lib, libmex.lib, libmat.lib和libeng.lib),这为我们在Matlab环境之外进行mex开发提供了可能性,因为我们连接库中的代码调用Matlab完成相应功能。
注意:这里所说的是mex开发可以脱离Matlab环境,而mex文件实际运行时还需依赖Matlab运行时环境!
首先确保MATLAB_HOME已经加入环境变量:
set MATLAB_HOME=D:\Program Files\MATLAB\R2010a path %MATLAB_HOME%/bin;%MATLAB_HOME%/bin/win32;%path%MATLAB_HOME代表MATLAB安装目录,在Matlab Command下输入matlabroot可以获得其值。
Makefile如下:
MATLABROOT ?= "D:\Program Files\MATLAB\R2010a" CC = gcc CCFLAGS = -I${MATLABROOT}/extern/include -L${MATLABROOT}/extern/lib/win32/microsoft MEXLIBS = -llibmex -llibmat -llibeng -llibmx -llibut all: yprime.mexw32 yprime.mexw32: yprime.c @${CC} ${CCFLAGS} -shared -fPIC -o $@ $< ${CCFLAGS} clean: @-rm *.mexw32.*以下是另一个版本(调用Matlab mex命令,需要确保<MATLABROOT>/bin及<MATLABROOT>/bin/win32已经加入系统PATH环境变量):
MATLABROOT ?= "D:\Program Files\MATLAB\R2010a" all: yprime.mexw32 yprime.mexw32: yprime.c @mex -g yprime.c clean: @-rm *.mexw32.*在Windows下,脱离Matlab环境,利用mingw环境进行mex开发,并且利用Makefile进行mex项目管理,可以更加方便地控制构建流程,具有极大的灵活性。例如,如果mex需要连接第三方库,可以这样写(以OpenCV为例):
MATLABROOT ?= D:\Progra~1\MATLAB\R2010a OPENCVROOT ?= D:\Bigben\usr\opencv OPENCVLIBS = -lopencv_calib3d242.dll -lopencv_contrib242.dll -lopencv_core242.dll -lopencv_features2d242.dll -lopencv_flann242.dll -lopencv_gpu242.dll -lopencv_highgui242.dll -lopencv_imgproc242.dll -lopencv_legacy242.dll -lopencv_ml242.dll -lopencv_nonfree242.dll -lopencv_objdetect242.dll -lopencv_photo242.dll -lopencv_stitching242.dll -lopencv_ts242 -lopencv_video242.dll -lopencv_videostab242.dll MEXLIBS = -llibmex -llibeng -llibmat -llibmx -llibut CC = g++ CCFLAGS = -I${OPENCVROOT}/include -L${OPENCVROOT}/lib -I${MATLABROOT}/extern/include -L${MATLABROOT}/extern/lib/win32/microsoft -Wl,--dll .PHONY: all all: mexCascadeClassifier.mexw32 mexCascadeClassifier.mexw32: mexCascadeClassifier.cpp @${CC} ${CCFLAGS} -shared -fPIC -O2 -o $@ $< ${OPENCVLIBS} ${MEXLIBS} @strip $@ clean: @-rm *.o *.mexw32当然,利用mex命令也能很容易实现这一点。运行mex -help,可以看到mex支持-I、-L、-l选项。-I用于添加头文件搜索路径,-L添加库文件搜索路径,-l用于指定要连接的库文件名称。这些都与gcc/g++类似。例如,要连接OpenCV,也可以这样写:
mex -I${OPENCVROOT}/include -L${OPENCVROOT}/lib -I${MATLABROOT}/extern/include -L${MATLABROOT}/extern/lib/win32/microsoft mexCascadeClassifier.cpp ${OPENCVLIBS} ${MEXLIBS}compile.m代码如下:
MATLABROOT = matlabroot; OPENCVROOT = 'D:\Bigben\usr\opencv'; cc_include = ''; cc_include = [cc_include '-I' fullfile(MATLABROOT, '/include')]; cc_include = [cc_include '-I' fullfile(OPENCVROOT, '/include')]; cc_library = ''; cc_library = [cc_library '-L' fullfile(MATLABROOT, '/extern/lib/win32/microsoft')]; cc_library = [cc_library '-L' fullfile(OPENCVROOT, '/lib')]; mex mexCascadeClassifier.cpp ${OPENCVLIBS} ${MEXLIBS}