EDA365电子论坛网

标题: Windows 64 与 Matlab 64 MEX混合编程初步 [打印本页]

作者: piday123    时间: 2020-5-7 09:21
标题: Windows 64 与 Matlab 64 MEX混合编程初步
说明' T# d+ x' g, w% }/ U
Matlab混合编程
' t" f/ @# ], O7 d+ h* l% P: D6 S       下载与安装编译器6 y. ~% U* Y/ L. d
              Microsoft Windows SDK 71CC. K: b4 l6 ^+ O' C; ^
              TDM-GCCgccg
" d% E' c7 B0 k0 R9 C: ^                     For Matlab 2015
0 }/ \2 w2 B+ N+ v, u9 a. [# C                     For Matlab 2014
" J8 Y( a" _7 ^' g8 p" A              选择编译器
" @- Y8 d" g  U3 n2 J- Z) O, ^              编写ccpp文件
6 W8 S8 }5 ~0 e                     mexFunction函数介绍1 M- t2 d& p1 i# Z+ |
              编译多个ccpp文件8 `! \& @# b/ t0 `3 E
! ?% b4 |, @" Y$ L9 s0 D# w; v$ @" u: b

# a' F+ b8 m0 b  {0 u说明. E5 S: d$ m" G
记录本人在Windows下,使用Matlab 64-bit 版进行混合编程时遇到的问题,主要记录编译器的安装与简要的混编过程。
* `  Y8 I" ^. f, d. s/ O
8 U2 {5 P# I+ N1 c( N7 _6 [# r( u+ B1 l3 X
% P1 o9 N/ S* ~3 v$ r
! z8 ]2 [4 _' x/ X) h  m3 I
Matlab混合编程
* Z7 ?, I! W( S3 I$ R5 [下载与安装编译器4 F. o* Q% ?6 l# p( W! l& a* A
Microsoft Windows SDK 7.1(C/C++); _- v4 _0 S5 b8 t
点此Microsoft Windows SDK for Windows 7 and .NET Framework 4 (ISO)打开下载页面,是镜像文件,选择64-bit版,文件大小500M+,全部安装需占磁盘近2G。
/ D- E8 _* X" u
% p. I! d4 [, H9 U5 K下载完成后根据提示安装即可,如果出现问题,安装失败,参考:Problem&Solution 部分。$ J; g: B5 Y7 O6 ?; |$ q" ~* R2 l
' h7 K* k/ z" o9 J+ e) y4 t
TDM-GCC(gcc/g++)
- E8 |7 \& {7 I7 KFor Matlab 2015+ F0 |- v0 ?  ]& V& v
Matlab 2015已经开始支持GNU编译器,具体参见:Supported and Compatible Compilers for R2015b,安装方法参见:Install MinGW-w64 Compiler。7 ?9 d/ Z; |9 A* a

7 H4 d2 l0 A1 N; i) ?
% k9 E5 u. c. K+ L( a2 y5 O
9 H, b! n; W. ?4 r% Q8 v
0 Q8 |0 r" p" r' p2 T: k& o0 f
5 ?2 l- b2 n! J1 t9 ] 9 N" c& i* J+ o* S) I% G

, L- b! m1 r+ p; d% a至此完成!
: [) F) i/ v7 V" T( s0 [! G  w7 o& Y7 \: N* }' A
For Matlab 2014! L: R. R( N+ T5 a
如下文章针对于MATLAB 2014a。
9 e; u0 H  ^0 E  A+ U. S& b& x$ a  N5 N, V7 Y0 M& ?
点此tmd-gcc打开下载页面,选择64位版本,40M+,全部安装占用400M+磁盘空间。
4 c" ~* |: x; V+ r# ?- e* g
$ l. w) e" w$ z) |: }& v根据以前使用经验,安装路径最好不要有空格中文。: V9 k8 {5 B7 R9 ]( M

% U! g4 n. @* l安装完成后,开始 -> 运行 -> cmd打开Windows命令窗口,输入gcc -v,如下图所示,显示安装信息,说明安装成功:
% z7 Y- Q" c1 a# }
" p" f# b  j# |4 r* V) @
! W5 o5 ^& D8 k8 }9 n最后的战斗:
, k% ?! t4 [7 K3 W% z3 i/ P6 W因为Matlab不支持GNU的编译器,还得做点事,下面的方法来自Using GCC (MinGW) as MATLAB’s MEX compiler 中的Bogdan的解答:# z5 F/ U) g$ S% W1 e
% A1 _9 j+ N& Z( c! u& H( j0 _
下面的代码是从Bogdan主页上下载的mexopts.bat文件代码,使用时需要做一点小小的改动。
; H: }: C. `4 N  [3 I* w. i, K5 }
5 U) F; _. v+ E  h在下面的代码中找到:set MINGWPATH=p:\mingw64这句代码,将其中的路径p:\mingw64替换成你的TMD-GCC-64的安装目录,如我的是:E:\devtools\TDM-GCC-64,然后保存并将mexopts.bat文件copy到计算机如下路径(复制下面的路径地址,粘贴到资源管理器窗口地址栏,回车即可):
6 p0 h( e, p9 K
6 a& y. ?+ V0 ^6 L%USERPROFILE%\AppData\Roaming\Mathworks\MATLAB\R2014a\$ v/ U9 `) |7 \8 t) |& P

+ X% D! s: _0 `& v1 k/ t下面是代码:
" y/ Q% A1 y3 K( F/ {0 A2 h. A; s; {, B! A; B. t) @9 V& R; l
@Echo off
8 l& t* E$ C+ S9 I6 h$ k% x8 K: D1 ~3 x
:: NOTE: this is actually not a proper .bat file executed by Windows. MEX5 d8 o: O+ Z; M7 p7 @
::       parses it and only understands a very reduced set of commands:% r2 T# R( L9 q- G, k. Z. u. }
::       "set" and "rem" apparently, everything else is ignored (behaves as3 k( |# R8 V5 v
::       "rem"), so don't do any fancy batch stuff in here. There are some
# j! R* q0 f2 N: z::       undocumented special vars you can set here that will trigger MEX
; _6 C) f8 @) {' m::       to do fancy stuff.' u* b) q) Y& r% |3 R- v. V. B
' c/ [0 y0 r/ |6 N$ ^8 V0 Q
:: You can use MinGW64 builds (win32 threads + seh unwinding) from here:
& s/ Z5 b* o9 R% I; s8 \:: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/
1 N/ J; k: |' ^7 Q! c' C
2 z6 d) u$ s5 ?. I% F: `9 G( X; c:: Tested with the following:
8 j6 u" n7 X3 }:: http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.1/threads-win32/seh/x86_64-4.9.1-release-win32-seh-rt_v3-rev1.7z! C+ u( k- w, R# {, [7 w! n
9 {( u  k, ]/ y- T) g
:: Set this to your Mingw64 top folder, where you extracted the above
  @. a( W6 i8 u  cset MINGWPATH=p:\mingw64
5 Q( P5 C3 ^( {
3 ^* n, F1 M+ n5 V) {7 H! L" v:: Leave these alone unless you know what you're doing.
  p: L% \& i; u! sset PATH=%MINGWPATH%\bin;%PATH%7 m0 z, `$ p  ~
set PRELINK_CMDS=echo.>%TEMP%\mexstaticlibs5 }& d8 r2 a; {6 B, f
4 K* c2 ]5 q2 E* H- A
:: You can have MEX run some commands before calling the linker.7 g4 u. M$ J2 h1 A- m& g$ _
:: The two examples below will cause gcc to output the full path to some
4 I1 Y6 m9 A  B! g6 n) M:: static libraries so you can link statically to them (see the/ n  q7 m8 h+ z% }# S5 l& U
:: LINGFLAGSPOST special var below). You can set any command here, however.
4 C6 X; f- S- `& W- urem set PRELINK_CMDS1=gcc -print-file-name=libwinpthread.a >> %TEMP%\mexstaticlibs) Y, g7 P' j# f. ?
rem set PRELINK_CMDS2=gcc -print-file-name=libquadmath.a >> %TEMP%\mexstaticlibs
6 `2 ^1 p5 }) c+ Prem set PRELINK_CMDS3=...
+ e6 P0 h" X8 G) m
2 {9 v$ _( n* g8 J3 q2 k; Q:: You can have MEX run some commands also after calling the linker& h! H& _- F2 Y+ ~# n; z
:: (e.g. upx compress the output .mex)/ p# t/ b4 Y- f; m0 v
rem set POSTLINK_CMDS1=upx -9 "%OUTDIR%%MEX_NAME%%MEX_EXT%"
! g3 N' p! D9 C- e" n3 k" t5 qrem set POSTLINK_CMDS2=...5 g$ V3 v( \0 h" X& T; J2 w
( e1 q5 `& @+ H8 r9 G3 M
:: You can change these if you really need to.0 ^& h7 e% D) S5 u
set COMPILER=g++# P& Z- ^  |2 m2 h% Q" A3 \
set COMPFLAGS=-c -I"%MATLAB%\extern\include" -DMATLAB_MEX_FILE
3 h, f% L$ v; }  g& p7 H0 _set OPTIMFLAGS=-O3 -funroll-loops -DNDEBUG1 l3 f7 |( Z7 E; A: P  i
set DEBUGFLAGS=-g
. X- B6 S2 w# l2 E  M1 `' B% }set NAME_OBJECT=-o
! s" Y% R9 P7 K  A* J6 P
$ j% z" Z! E) Y) n1 _" Cset LINKER=g++  Q- k$ F( S  h2 \0 w
set LINKFLAGS=-shared -static-libstdc++ -static-libgcc -L"%MATLAB%\bin\win64" -L"%MATLAB%\extern\lib\win64\microsoft" -lmex -lmx -leng -lmat -lmwlapack -lmwblas3 L+ b0 e  G2 s" V: S2 ?
' ]3 z3 L, x8 Z, V3 N) \
set LINKFLAGSPOST=@%TEMP%\mexstaticlibs& F. r# G% I! G8 l) t  h
set NAME_OUTPUT=-o "%OUTDIR%%MEX_NAME%%MEX_EXT%", u4 |6 V0 {1 Z6 ?& F  [2 A7 b9 h

4 P& r. X  h. i
- }  \; k: h/ j& X% ]$ z' |:: EXAMPLES
3 a. ]) a! \) W" D& {:: ========
* @9 |9 T- P. D- V0 S) w  e" R9 v9 O0 {' L
:: You can compile simple files using "mex file.cpp". To support more than 2^32 elements, use/ h0 x" k. B0 T/ E9 H
:: "mex -largeArrayDims file.cpp" ... use this by default, unless you know what you're doing.
$ b0 L/ }2 T3 ]% w. N7 B- J1 r% \- {; t; S4 a
:: To add include dirs, lib dirs, or compile/link flags, do:
% E; ]' W# S/ ^:: mex COMPFLAGS="$COMPFLAGS -std=gnu99 -Ix:/include/dir" LINKFLAGS="$LINKFLAGS -Lx:/libs/dir -lmylib" -largeArrayDims file.cpp$ {+ ?) m4 ]. Y1 V3 N# _( R

0 x; n7 ~' u: a% `* V" e: I* q! P+ m  M3 p0 H% l1 u
选择编译器
& T& E- }% |9 k/ O( \2 r& l
: H& s$ C4 E. x0 R. F) ^6 y) _  x
% k1 a% F6 [$ c3 G刚开始我也以为不能用,后来试着编译了一下,竟然可以! 2 g! i: O' S1 D. t* H: B6 \/ s4 O
       . N5 ~1 d' f, O7 @% L+ Y
DT.c文件中重复定义了无穷大,注释掉,就没有提示啦!7 J- i2 j( D% H$ Q

+ U  C7 u( k# D8 J8 s9 W3 ~
& N$ U2 T+ z: ?) A( Y" @编写c/cpp文件
5 T/ e4 f2 T$ F7 D与普通的C文件的编写有两点不同:
$ L* t, n8 Y6 `. v/ g) W9 r, q) Z% }
0 ~. q; t- U  Z: m

0 m, Z( z6 H, g! @1 z下面以一个求和的例子说明:' e& T+ b6 x. J
) n& s$ B2 k5 R: g
#include "mex.h" // 使用MEX文件必须包含的头文件, o% ~- a: n2 ?3 g3 E
// 执行具体工作的C函数
* K9 p8 A5 N1 N9 F  \- Rdouble add(double x, double y)
/ }. I2 O$ C- I' P- V, m$ g{! i; N- C9 \5 p. D5 V5 j- E/ z
    return x + y;
( N8 G* Z* b' F3 v, B5 R, M( X}# e) G( {: v6 R0 p- D" e
// MEX文件接口函数
: g; z( \5 W% l3 F7 Xvoid mexFunction(int nlhs,mxArray *plhs[], int nrhs,const mxArray *prhs[])
) ]5 C* c2 V! _0 W' y{7 |; u# M/ \2 O$ Z& d1 L7 F$ a: Q
    double *z;
  c- _3 u6 {0 U2 H% i; `    double x, y;
& W1 k0 _0 ^. p3 r* f- F    plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
  @: P' W6 A  W5 g, G! e8 ^    z = mxGetPr(plhs[0]);
, ^; V0 |9 ~: L' Q. X! W! ?    x = *(mxGetPr(prhs[0]));6 a; {1 [& ]7 @* n3 C. U* ^
    y = *(mxGetPr(prhs[1]));
1 X) h9 H# S2 J) n! t) G    *z = add(x, y);
$ Y$ b- W/ ^' x5 ?! V* r2 }}
1 P: v2 {; l( H2 R) n. T- F5 I- z* }5 V  ?
/ @& O; ~2 f3 z6 i$ h9 y8 M
Matlab命令窗口输入mex add.cpp,运行结果如下图: / t9 R) M( N4 r* O$ Q0 w4 C

. @' _% b, C; j! k# ?; p$ N  ]! W+ W7 o+ y$ Z2 T
在Windows上编译后生成mexw32和mexw64文件,在Linux上编译会生成mexa32和mexa64文件。  X$ m( j& Y2 _- z9 M3 \* ^8 p
* }( m6 y0 N9 `6 i$ l' A7 F1 e  h
mexFunction函数介绍2 Y* M7 o: a) U- e
mexFunction函数接口如下:
$ s9 J3 I, D9 u8 F3 H5 n' L- m" E3 J! |7 H5 ?& d( |
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
# A' h" j+ F0 l5 d
  U! z" D7 d! g( P  U可见,是没有返回值的,其实是通过指针数组plhs传递的。它共有四个参数,即左边的输出参数及数目和右边的输入参数及数目,具体参数意义如下:9 x: x" j: Y# d. w' {6 H  R
4 ~+ W2 I$ K0 i: `) `& x
参数                  意义                          英文全称                 类型
" }* W% i7 d9 s5 X5 {& `; }8 l4 G' jnlhs        左边输出参数的数目        number of left-hand side        整型(int)( ~8 i, ?3 ^, c. [
plhs        指向输出参数的指针        pointer of left-hand side        指针数组
  x1 ^$ a1 ~# Z- ^nrhs        右边输入参数的数目        number of right-hand side        整型(int)
& l% x# _9 N- x! e. Uprhs        指向输入参数的指针        pointer of right-hand side        指针数组
( q  Z. `) S$ T; q, d. W/ ^3 n( N2 |% I, ~% z0 n
详情参考:
; v& y# v+ ]( g8 S# z* M1 |  h& r+ f% u4 p* f

3 }( m5 U: g: T0 t* |# n/ f; }
编译多个c/cpp文件  O7 A* V0 Y  }* Q4 B
假设A.c调用B.c,B.c调用C.c
) V: O6 r! X& j# t可以使用如下命令编译:) m, X: z9 E: G$ M% m$ z) |

  d+ P( g9 M" Mmex C.c
1 Z5 Q7 w$ f& h, @) B; W  ~4 Pmex B.c
' B  ^  X1 f2 kmex A.c. g& M4 s+ t" w) W2 i

" O/ x) Q; F' a% u& v, W7 Z或者# q) G6 L( g: G
7 r9 C2 o' m. [8 o" `
mex A.c B.c C.c
, O7 j2 N: w# s1 d7 x3 |- E7 z; r  }, v" x! o: D$ E# y3 z: C9 A& k- p
& K6 [+ R% ?, P6 y8 Z9 m: G1 P

/ M- ?: s0 ?6 ?8 v* O9 }0 ]$ v  U) J& Z8 h& P3 W8 I; B
8 o; s# T5 t% F. ^

6 B+ H( p; }. d# P$ H8 ]
作者: NNNei256    时间: 2020-5-7 13:31
先收藏了吧




欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/) Powered by Discuz! X3.2