Problems with Fortran MEX files with R2020b on Linux
2 views (last 30 days)
Show older comments
Hello,
I wanted to try out using Fortran MEX files with Matlab R2020b on Linux (Ubuntu 20.04).
First, "mex -setup" does not detect the right compiler. On my system, I have installed both -
gfortran 9.3.0 as well as gfortran 8.4.0.
According to the list of supported compilers, R2020b supports gfortran 8.x - but
mex -setup
does not detect it.
So how can tell mex to properly use gfortran 8.4 ?
When I compile e.g. the supplied example timestwo.F, I get weird behaviour. It compiles without error, but the output values are totally wrong. E.g.
timestwo([1 2 3 4 5])
gives
ans =
2.0000 0.0000 5.0000 0.0000 0.0000
For me, this looks like a memory access problem on input or output parameters. And timestwo(1:10) crashes.
I have tried with switch -R2017a (separate complex API) as well as -R2018a (interleaved complex API), but without success and same errors.
Any ideas, what is going wrong here ?
Best regards,
Denn
0 Comments
Accepted Answer
James Tursa
on 15 Feb 2021
So, the timestwo.F file that ships with MATLAB has bugs. I pointed this out to TMW several years ago, but I just checked and as of R2020a the bugs are still there. Yes this code will crash or behave badly if you give it anything other than a full double scalar. E.g., take these lines:
real*8 x_input, y_output
mrows = mxGetM(prhs(1))
ncols = mxGetN(prhs(1))
size = mrows*ncols
#if MX_HAS_INTERLEAVED_COMPLEX
x_ptr = mxGetDoubles(prhs(1))
#else
x_ptr = mxGetPr(prhs(1))
#endif
call mxCopyPtrToReal8(x_ptr,x_input,size)
So x_input and y_output are scalars, but the mxCopyPtrToReal8( ) call happily will try to copy any size array into them. If the input is anything other than a scalar you will be writing into invalid memory and bad things happen. Also there are no checks for sparsity or non-double numeric.
Here is one way to write the routine without these bugs (CAVEAT: I don't have a Fortran compiler installed so this is all untested):
#include "fintrf.h"
!\
! Gateway
!/
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
implicit none
mwPointer plhs(*), prhs(*)
integer nlhs, nrhs
!\
! API functions
!/
mwPointer, external :: mxGetData
mwPointer, external :: mxDuplicateArray
integer*4, external :: mxIsDouble, mxIsComplex, mxIsSparse
mwPointer, external :: mxGetNumberOfElements
!\
! Data pointer
!/
mwPointer y_ptr
!\
! Array size
!/
mwPointer n
!-----
!\
! Argument checks
!/
if( nrhs /= 1 ) then
call mexErrMsgIdAndTxt ('MATLAB:timestwo:nInput', &
& 'One input required.')
elseif( nlhs > 1 ) then
call mexErrMsgIdAndTxt ('MATLAB:timestwo:nOutput', &
& 'Too many output arguments.')
elseif( mxIsDouble(prhs(1))==0 .or. &
& mxIsComplex(prhs(1))==1 .or. &
& mxIsSparse(prhs(1))==1 ) then
call mexErrMsgIdAndTxt ('MATLAB:timestwo:InvalidInput', &
& 'Input must be full real double.')
endif
!\
! Get array size
!/
n = mxGetNumberOfElements(prhs(1))
!\
! Create output array as a deep data copy of the input
!/
plhs(1) = mxDuplicateArray(prhs(1))
!\
! Get the data pointer
!/
y_ptr = mxGetData(plhs(1))
!\
! Call the Multiply routine, passing address by value
!/
if( n > 0 ) call timestwo( %VAL(y_ptr), n )
!\
! Done
!/
return
end
!\
! The Multiply routine -------------------------------------------------
!/
subroutine timestwo(y_output, n)
mwPointer n
real*8 y_output(n)
y_output = 2.0 * y_output
return
end
The reason for the two & usage on lines is so that the code can be compiled as either fixed format .f or free format .f90 and the continuation characters will work in either case.
2 Comments
Josh G.
on 24 May 2021
Edited: Josh G.
on 24 May 2021
@Delta-Echo N.N. Matlab uses whatever is stored in the $FC environment variable as the Fortran compiler, so you can change the version by setting the environment variable when you call mex: mex FC=$path_to_your_gfortran_version_here timestwo.F
More Answers (0)
See Also
Categories
Find more on MATLAB Compiler in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!