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


     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 file for MEXing the above file with the IFC

            FFLAGS='-fPIC -u -w95 -warn all'
            FLIBS='$RPATH $MLIBS -L/opt/intel_fc_80/lib -lm'

            LDFLAGS='-pthread -shared'
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.