Back to homepage
Writing Matlab MEX files using Fortran 90 / 95 (and
the Intel Fortran Compiler)
(Update: This text refers primarily to Matlab 6.5 (aka R13) on
Linux. The new Matlab 7 introduces some serious problems with
non-GNU compilers due to throwing C++ exceptions. Read on below
for details.)
The Mathworks do not officially support Fortran 90 / 95, but thanks to
people like Benjamin Barrowes who wrote Matlab2FMex
and the people at
NAGWare it is easy to figure out how to write your MEX files in
Fortran 95 without using the awkward mxCopy-functions. Lately, I also
found this
page which describes in detail all three possible ways of writing
MEX files entirely in Fortran. However, of these three ways, two make
a local copy of the data which is less than optimal when dealing with
big data sets.
The trick is to declare the pointer you get from mxGetPr as
an integer pointer and pass it along with the array dimensions to a
subroutine which expects a double precision array. Until now this
works for me without any problems (Linux w/ Intel Compiler), but note
that this procedure may not work with every compiler or on any
platform. I may also add that this procedure does NOT work with the F programming language as it
forbids passing "wrong" arguments to subroutines.
First, we will have to explicitly define the used
Matlab API functions, at least those who have a return value:
module mexf90
interface
function mxGetPr(pm)
integer,pointer :: mxGetPr
integer :: pm
end function mxGetPr
function mxGetM(pm)
integer :: mxGetM,pm
end function mxGetM
function mxGetN(pm)
integer :: mxGetN,pm
end function mxGetN
function mxCreateDoubleMatrix(m,n,type)
integer :: m,n,type,mxCreateDoubleMatrix
end function mxCreateDoubleMatrix
function mxGetScalar(pm)
integer :: pm
double precision :: mxGetScalar
end function mxGetScalar
end interface
end module mexf90
Just save this file under the name "mexf90.f90" and compile it. (For
those unfamiliar with modules: you must prevent the compiler from also
linking the file - this is usually done with the "-c" switch.) This
module contains only the API functions we need, but adding further
functions is straightforward. You may also click here
to obtain a module file with more function definitions.
Now the actual function, consisting of the subroutine
"mexFunction" (the gateway to Matlab) and an example subroutine
"scalarMult" which multiplies the matrix A with a scalar "alpha" and
returns the result in matrix B. The comments should make clear how
these functions work:
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
use mexf90 ! API function definitions
implicit none
integer, intent(in) :: nlhs, nrhs
integer, intent(in), dimension(*) :: prhs
integer, intent(out), dimension(*) :: plhs
integer :: m,n
integer, pointer :: A,B ! These are the pointers to the matrix data
double precision :: alpha
! Check input arguments
if(nrhs /= 2) then
call mexErrMsgTxt('Function requires two input arguments.');
end if
! Get data and size of the input matrix
A => mxGetPr(prhs(1))
m = mxGetM(prhs(1))
n = mxGetN(prhs(1))
! Get scalar value
alpha = mxGetScalar(prhs(2))
! Create output matrix
plhs(1) = mxCreateDoubleMatrix(m,n,0)
B => mxGetPr(plhs(1))
! Call subroutine for multiplication
call scalarMult(A,B,alpha,m,n)
end subroutine mexFunction
subroutine scalarMult(A,B,alpha,m,n)
implicit none
integer :: m,n
double precision :: alpha
! Now define the matrices with the actual data type and dimension
double precision, dimension(m,n) :: A,B
! Now do something useful...
B = alpha * A
end subroutine scalarMult
For more complex functions it is a bit tedious to pass the dimensions
along with the data pointers - if someone finds a better solution,
please let me know!
The Intel
Fortran Compiler for Linux is free for non-commercial use, but you
probably already know that... These are the relevant parts in the
mexopts.sh file for MEXing the above file with the IFC
FC='ifort'
FFLAGS='-fPIC -u -w95 -warn all'
FLIBS='$RPATH $MLIBS -L/opt/intel_fc_80/lib -lm'
FOPTIMFLAGS='-O3'
FDEBUGFLAGS='-g'
LD='icc'
LDFLAGS='-pthread -shared'
LDOPTIMFLAGS='$FOPTIMFLAGS'
LDDEBUGFLAGS='-g'
As you can see, I do not use any map-files as that didn't work for
me. It is important to note that linking with "ifort" will usually NOT
work, the above file uses the Intel C++ Compiler "icc" instead. If you
do not have icc installed, the GNU compiler "g++" should also work.
If you also want to use functions like "print", e.g. for debugging
purposes (mexprintf does not allow format strings in Fortran...), you
will also have to link "ifcore", but you should remove that for the
release version of your code. If you get error messages about
unresolved symbols when executing the mex-file, make sure that the
Intel libraries are scanned by ldconfig or put them into your
LD_LIBRARY_PATH before starting Matlab.
If you get an error message
saying that __MAIN couldn't be found, check again that you are NOT
linking with ifort. If you still have problems with unresolved
symbols, try using the "-static-libcxa" switch.
Now happy
MEXing!
Oh, and also check out LAPACK95, incredibly useful
for porting M-files to MEX. And Matran
looks very promising, although I didn't use it yet.
Update: Problems with Matlab 7 (aka
R14)
The new Matlab 7 now uses C++ exceptions
in library functions like mexErrMsgTxt. As Matlab was built on Linux
with the GNU compiler, this breaks practically all other compilers
which are unable to correctly propagate these exceptions - including
the Intel Fortran Compiler (and also Ocaml, by the way...). (A sidemark:
the Intel C Compiler (icc) will usually work as long as you always
compile with "-Kc++").
This means, as soon as a Fortran MEX file
compiled with the Intel Fortran Compiler calls mexErrMsgTxt, the
complete Matlab session will abort and return to the shell, as there
is no handler to catch the exception. I doubt that there exists an
easy solution to this problem, as the implementation of exception
handling in C++ differs between different compilers.
Thus, if you want to write your files entirely in Fortran 95
and you want to use the IFC, don't call mexErrMsgTxt or your session
will abort. If you have to use mexErrMsgTxt, you are for now forced to
use a GNU Fortran compiler. Although Fortran and C don't "know"
exception handling, the GNU C and Fortran compilers have a switch
"-fexceptions" which includes code to correctly propagate these
exceptions. For Fortran 95 you can use either g95 or GNU Fortran 95, both work for
creating Matlab MEX files as long as you compile with
"-fexceptions". However, both compilers are not yet stable, but they
are making rapid progress recently.