Problems with Fortran MEX files with R2020b on Linux

조회 수: 2 (최근 30일)
Delta-Echo N.N.
Delta-Echo N.N. 2021년 2월 15일
편집: Josh G. 2021년 5월 24일
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

채택된 답변

James Tursa
James Tursa 2021년 2월 15일
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
Delta-Echo N.N.
Delta-Echo N.N. 2021년 2월 16일
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. 2021년 5월 24일
편집: Josh G. 2021년 5월 24일
@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

댓글을 달려면 로그인하십시오.

추가 답변 (0개)

카테고리

Help CenterFile Exchange에서 MATLAB Compiler에 대해 자세히 알아보기

제품


릴리스

R2020b

Community Treasure Hunt

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

Start Hunting!

Translated by