Hi all, I'm trying to learn how to write MEX functions using Fortran. I have encountered a couple issues, and the documentation is quite dated (mostly fixed-form Fortran, and predating the current -R2018a API). Many suggestions lead to functions like mxGetPr and mxGetPi which are 'not recommended' in the current API. This goes for all the .F examples in $matlabroot/extern/examples/.
I am on Ubuntu 20.04, Matlab R2019b, gfortran 9.3.0
I have two issues:
- If I declare my arrays as allocatable, and then allocate them, I will hit a segfault or some other instability causing Matlab to lock or crash. The "solution" is to pre-allocate the arrays with some maximum size, and then work with inputs smaller than that hidden limit. It no longer segfaults, but this harms the ability to write a general-purpose array input without adding an arbitrarily large allocation for all arrays. I'm not sure of a way to use `%VAL(A)` with matrix operations — perhaps `RESHAPE()` into a local variable that is matrix-shaped within the computational subroutine?
- In my minimum-working training example, I just pass array A to a subroutine, and then copy it to B, and return B. Some, but not all of the elements of A are returned in B. The usage in Matlab is B = copyab(A).
The F90 file, 'copyab.F90' (both gateway and computational subroutines)
#include "fintrf.h"subroutine mexFunction(nlhs, plhs, nrhs, prhs) implicit none mwPointer :: plhs(*), prhs(*) integer :: nlhs, nrhs mwPointer :: mxGetDoubles mwPointer :: mxCreateDoubleMatrix mwPointer :: mxGetM, mxGetN mwPointer :: A_ptr, B_ptr mwPointer :: m, n mwSize :: mn ! Issue here: using allocatable, allocate() causes segfault. integer, parameter :: maxm = 10 integer, parameter :: maxn = 10 real :: A(maxm,maxn), B(maxm,maxn)! real, allocatable :: A(:,:), B(:,:) m = mxGetM(prhs(1)) n = mxGetN(prhs(1)) mn = m * n! allocate(A(m,n), B(m,n)) ! RHS: input args A_ptr = mxGetDoubles(prhs(1)) call mxCopyPtrToReal8(A_ptr, A, mn) ! LHS: return vals plhs(1) = mxCreateDoubleMatrix(m, n, 0) B_ptr = mxGetDoubles(plhs(1)) call copyab(A, B, m, n) call mxCopyReal8ToPtr(B, B_ptr, mn)end subroutine mexFunctionsubroutine copyab(A, B, m, n) implicit none mwSize :: m, n real :: A(m,n), B(m,n) B = Aend subroutine copyab
Makefile with compile options:
FC = gfortranFCFLAGS = -O3 -cpp -fPIC -ffree-form -fdefault-real-8 -fdefault-integer-8 -WallMATLABDIR = /usr/local/MATLAB/R2019bMEX = $(MATLABDIR)/bin/mexMEXLIBDIR = $(MATLABDIR)/sys/os/glnxa64MEXLIBS = -lgfortranMEXINCLUDE = $(MATLABDIR)/extern/includeMEXFLAGS = -R2018a COMPFLAGS='$(FCFLAGS)'EXT = mexa64copyab.$(EXT): copyab.F90 $(MEX) $^ $(MEXFLAGS) -output $@ -I$(MEXINCLUDE) -L$(MEXLIBDIR) $(MEXLIBS)clean: rm -rf *.$(EXT) *.o *.mod
And the test Matlab code, 'test.m'
A = rand(3,3)B = copyab(A)
which results in,
>> testA = 0.8147 0.9134 0.2785 0.9058 0.6324 0.5469 0.1270 0.0975 0.9575B = 0.8147 0.9134 0.0000 0.9058 0.0000 0.0000 0.1270 0.0000 0.0000
B appears to containg floor(numel(A)/2) correct elements, regardess of the shape of A.
Best Answer