Error when compiling Fortran MEX file with mxCreateStructMatrix

I'm trying to create a struct as an output of a MEX file, but when I try to compile the file, I get errors about the function mxCreateStructMatrix not being defined. The exact error is:
Error: Function mxcreatestructmatrix730at (1) has no IMPLICIT type; did you mean ‘mxcreatedoublematrix730’?
It would seem that the library that defines mxCreateStructMatrix isn't being linked, but I don't know which library is supposed to define the function. My library string from
mex -v filename.F90
is
LINKLIBS : -Wl,-rpath-link,/usr/local/MATLAB/R2019b/bin/glnxa64 -L"/usr/local/MATLAB/R2019b/bin/glnxa64" -lmx -lmex -lmat -lm -L"/usr/lib64" -lgfortran
My guess is that the library is supposed to be defined by "-lmx," but ld is able to find the library without a problem. What could cause the function not to have a type defined?

 Accepted Answer

After some more testing I figured out what the problem was. The precompilation was failing because each function has to be defined with a type of "mwPointer," so adding the line
mwPointer :: mxCreateStructMatrix
to my MEX file fixed the problem.

8 Comments

For good programming practice, you should always have this inside every routine:
implicit none
And yes, all of the API functions should be explicitly typed with the return type.
Thanks James, but I already had that line in the subroutine, which is why the error was generated. Without implicit none, the compiler assumes the return type is an integer which in this case is pretty much correct, so no error is generated.
The only difference between mwPointer and the implicit integer type is that mwPointer is integer*8 on 64-bit systems (integer*4 otherwise) and the implicit integer type is integer*4 unless you use the -fdefault-integer-8 compiler option. In a test I ran even this difference didn't cause a problem.
You should not use -fdefault-integer-8 on any code where you are using the default integer with MATLAB API routines, as that might cause a mismatch and create problems. E.g., for mexFunction the doc is showing the default integer for the argument types:
integer nlhs, nrhs
This is almost certainly intended to be 32-bit integer*4 type, but if you use that -fdefault-integer-8 it will screw up this interface if that is how you have it coded. You would probably have to force it in this case:
integer*4 nlhs, nrhs
Interestingly, mex adds -fdefault-integer-8 automatically, even though it doesn't appear in the mexopts file. You can see this in the output of mex -v:
Building with 'gfortran'.
/usr/bin/gfortran -c -DMATLAB_DEFAULT_RELEASE=R2017b -DUSE_MEX_CMD -I"/usr/local/MATLAB/R2019b/extern/include" -fexceptions -fbackslash -fPIC -fno-omit-frame-pointer -fdefault-integer-8 -O2 -mtune=native "/home/user/Documents/MATLAB/timestwo.F90" -o /tmp/mex_9181185797012_69247/timestwo.o
/usr/bin/gfortran -c -DMATLAB_DEFAULT_RELEASE=R2017b -DUSE_MEX_CMD -I"/usr/local/MATLAB/R2019b/extern/include" -fexceptions -fbackslash -fPIC -fno-omit-frame-pointer -fdefault-integer-8 -O2 -mtune=native "/usr/local/MATLAB/R2019b/extern/version/fortran_mexapi_version.F" -o /tmp/mex_9181185797012_69247/fortran_mexapi_version.o
/usr/bin/gfortran -pthread -shared -O -Wl,--version-script,/usr/local/MATLAB/R2019b/extern/lib/glnxa64/fortran_exportsmexfileversion.map /tmp/mex_9181185797012_69247/timestwo.o /tmp/mex_9181185797012_69247/fortran_mexapi_version.o -Wl,-rpath-link,/usr/local/MATLAB/R2019b/bin/glnxa64 -L"/usr/local/MATLAB/R2019b/bin/glnxa64" -lmx -lmex -lmat -lm -L"/usr/lib64" -lgfortran -o timestwo.mexa64
MEX completed successfully.
Interesting. For C-mex routines the interface is int, which is typically a 32-bit 4-byte integer type even on 64-bit systems. I had assumed the same was true for Fortran ... in fact I had assumed that the same must be true for Fortran. How does MATLAB know in advance whether the mex routine mexFunction was compiled by C or Fortran? Wouldn't it have to pass arguments the same way, not knowing this? And, more generally, how does MATLAB know that this option won't screw up the user's code that depends on default integer being 4-bytes? It can't, of course. This seems very strange to me and hardly appropriate.
Can you run a test for me? Compile and run this code snippet to verify what size the default integer type is in a mex routine:
integer x(2)
integer*4, external :: mexPrintf
integer*4 k
character*10 line
write(line,'(I4)') LOC(x(2)) - LOC(x(1)) ! or maybe c_loc
k = mexPrintf('integer number of bytes = '//line//achar(13))
I added some boilerplate code to make this run as a MEX file:
#include "fintrf.h"
subroutine mexFunction(nlhs, plhs, nrhs, prhs)
implicit none
mwPointer :: plhs(*), prhs(*)
integer :: nlhs, nrhs
integer x(2)
integer*4, external :: mexPrintf
integer*4 k
character*10 line
write(line,'(I4)') LOC(x(2)) - LOC(x(1)) ! or maybe c_loc
k = mexPrintf('integer number of bytes = '//line//achar(13))
return
end subroutine
and here's the result:
test()
integer number of bytes = 8
I'm sure the way MATLAB tells the difference is in the symbols contained in the MEX file. The main difference I see, looking at the symbols from compiling timestwo.c and the above test.F90, is that test.mexa64 contains
0000000000000000 A FMEX
while timestwo.mexa64 contains
0000000000000000 A MEX
Compiling the mexcpp.cpp file found in the MATLAB examples produces the same symbol as the C MEX files.
OK. So maybe there is a different interface for the entry point for Fortran. I would not have expected that, and frankly don't know why they would even do that in the first place. Regardless, I still think adding the -fdefault-integer-8 option behind the user's back is inherently a bad idea since it might screw up the user's code. It would have been better to simply specify it as INTEGER*8 or mwPointer in the doc to make the intent explicit. I don't even know if there are any other routines in the API that use the default integer besides mexFunction. I feel the same way about this that I do about the silly /fixed option that they include in their mex build files that screw up the user trying to use free format code. I complained about this several years ago but it is still there. You should delete it if you haven't already.
Thanks for the post ... I learned something from this discussion.
I wonder what would happen if you built a mex function that linked some Fortran object code containing an exported MEXFUNCTION with some C object code containing an exported mexFunction ... which one would get called? Would it depend on the link order? Or is there a preferred order that it searches for the entry point? I'm not asking you to do this ... I am just wondering what would happen. I haven't had access to a Fortran compiler for quite some time so can't check this myself.
Yes, MathWorks does several things wrong with their Fortran MEX implementation, but it's been said elsewhere in MATLAB Answers that Fortran is the red-headed stepchild of the MEX languages.
Using the non-standard integer*4 and integer*8 instead of the standard KIND specification is wrong, using -fdefault-integer-8 is wrong, using /fixed and supplying examples as FORTRAN 77 source is wrong, and supporting GCC for C and C++ MEX but not GFortran for Fortran MEX on Mac and Windows is wrong.
Fortunately I don't think they include a GFortran equivalent of /fixed on Linux, but I've had to deal with removing it on Windows machines and it's annoying.
As one example of how their non-standard integer/real notation could cause problems, I write MEX files that interface with native Fortran programs using the standard KIND specification. It's not inconceivable that the MEX file could be compiled on a system where (taking real64 from the ISO_FORTRAN_ENV module) real(real64) and real*8 aren't the same thing.

Sign in to comment.

More Answers (0)

Categories

Products

Release

R2019b

Tags

Asked:

on 15 May 2020

Commented:

on 1 Jun 2020

Community Treasure Hunt

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

Start Hunting!