Reputation: 1939
I have inherited this mex code written in fortran 90 that I can't manage to properly build. All the object files compile nicely, but the linking fails. Fortunately, I have several leads to go on to figure out the problem.
The only complaint from the linker is
Undefined symbols for architecture x86_64:
"_mxgetstring_", referenced from:
_mexfunction_ in qgstep_mex.o
ld: symbol(s) not found for architecture x86_64
Now mxGetString
is only called in one place in qgstep_mex.f90
status = mxGetString(prhs(3), prmfname, STRLEN)
So if I change this to
status = 0
and hardcode prmfname
, the package builds just fine. But of course I don't want to hardcode it.
I have, however, managed to build another program that uses mxGetString()
, namely the Matlab-supplied example file revord.f
Both of these programs are linked by the same command made by mex
gcc -O -Wl,-twolevel_namespace -undefined error -arch x86_64 -Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/ -mmacosx-version-min=10.5 -bundle -Wl,-exported_symbols_list,/Applications/MATLAB_R2012a.app/extern/lib/maci64/fexport.map -o "revord.mexmaci64" revord.o -L/Applications/MATLAB_R2012a.app/bin/maci64 -lmx -lmex -lmat -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3/../../.. -lgfortran -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3 -lgfortranbegin
except that revord.F
is substituted by qgstep_mex.f90
and similarly for the output name.
There is an include statement in revord.F
#include "fintrf.h"
which is pointed to during the compilation by the flag
-I/Applications/MATLAB_R2012a.app/extern/include
However, if I try to put this in qgstep_mex.f90
, the linker just complains with
Warning: qgstep_mex.f90:1: Illegal preprocessor directive.
So, does anyone know how to get this working?
Changing the case of the extension to .F90 had no effect, but the -cpp
flag seems to have done the trick. However, now it gives an error (during compilation, not linking) that I do not quite understand (I'm not very good with Fortran)
$ gfortran-mp-4.7 -c -I/Applications/MATLAB_R2012a.app/extern/include -I/Applications/MATLAB_R2012a.app/simulink/include -fexceptions -m64 -fbackslash -DMX_COMPAT_32 -O -cpp "qgstep_mex.f90"
qgstep_mex.f90:102.11:
status = mxGetString700(prhs(3), prmfname, STRLEN)
1
Error: Function 'mxgetstring700' at (1) has no IMPLICIT type
The relevant lines from the include file seems to be
#if defined(MX_COMPAT_32)
.
.
.
#define mxGetString mxGetString700
Aha. It seems I'm not supposed to include fintrf.h
after all. There's another file in the project directory, mexf90.f90
, containing
module mexf90_mod
interface
function mxGetString(p, string, STRLEN)
integer(8) :: mxGetString
integer(8) :: p
character*(*) :: string
integer(4) :: STRLEN
end function mxGetString
function mxGetPr(pm)
integer(8), pointer :: mxGetPr
integer(8) :: pm
end function mxGetPr
.
.
The strange thing is that mxGetPr is called just fine in qgstep_mex.f90
, before mxGetString, but calling mxGetString fails, with the error message as noted originally above. Here's the linking command I use (linebreaks inserted for clarity)
gfortran-mp-4.7 -O -Wl,-twolevel_namespace -undefined error -arch x86_64
-Wl,-syslibroot,/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.8.sdk/
-mmacosx-version-min=10.5 -bundle -Wl,-exported_symbols_list,/Applications/MATLAB_R2012a.app/extern/lib/maci64/fexport.map
-o "QG_step_f.mexmaci64" utils.o parameters.o helmholtz.o calc.o qgflux.o qgstep.o mexf90.o qgstep_mex.o
-L/Applications/MATLAB_R2012a.app/bin/maci64 -lmx -lmex -lmat -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3/../../..
-lgfortran -L/opt/local/lib/gcc47/gcc/x86_64-apple-darwin12/4.7.3 -lgfortranbegin
As can be seen, the object files do seem to be in the right order as well.
The package builds just fine on a linux system. Hence I guess it must be some difference between the compilers. Here's the linking code used on the linux system:
gfortran -O -pthread -shared -Wl,--version-script,/ufs/local/matlab-2012a/extern/lib/glnxa64/fexport.map -Wl,--no-undefined
-o "QG_step_f.mexa64" utils.o parameters.o helmholtz.o calc.o qgflux.o qgstep.o mexf90.o qgstep_mex.o
-Wl,-rpath-link,/ufs/local/matlab-2012a/bin/glnxa64 -L/ufs/local/matlab-2012a/bin/glnxa64 -lmx -lmex -lmat -lm
Upvotes: 0
Views: 1212
Reputation: 29401
Try changing the filename qgstep_mex.f90 to qgstep_mex.F90. That will cause gfortran to run the C preprocessor. There is also a compiler option to cause that.
EDIT in response to the question update:
The compiler wants the function mxGetString7001
to be typed. There are several ways that you can do this. The ideal approach is to have the source code of the function in a module. Then when the caller use
s that module, the return type of the function and the types of its arguments are known to the compiler. Perhaps this exists and you need to add the source code file to your compile statement ... before the file that uses this function. If not, you could write an interface
block providing this information. Or you could declare the function and use an external
statement, but this is really a work around, using FORTRAN 77 methods.
Upvotes: 1
Reputation: 8267
The include statement in fortran does not have a #
include "fintrf.h"
When building, why not use gfortran instead of gcc. Saves the compiler having to figure out what you are compiling.
Upvotes: 0