Problems with Fortran MEX files with R2020b on Linux

2 views (last 30 days)
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

Accepted Answer

James Tursa
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
Delta-Echo N.N.
Delta-Echo N.N. on 16 Feb 2021
Thank you very much for this in-depth answer.
I have chosen the "timestwo.F" in order to keep first tests as simple as possible, and I did not consider, that this example may only be made for scalar inputs.
Maybe, you also have a hint for how to direct the mex-command to use the correct compiler version, when there are multiple versions installed on a system ?
Thank you and Best regards,
Denn
Josh G.
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

Sign in to comment.

More Answers (0)

Categories

Find more on MATLAB Compiler in Help Center and File Exchange

Products


Release

R2020b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!