Search code examples
matlabfortrangfortranmat-file

Errors in linking fortran code that imports a MAT-file


I have to import a MAT-file in a fortran program. I followed the example file but I am facing some problems while linking. The compilation happens fine.

Minimal code:

#include "fintrf.h"

PROGRAM main 

USE ssa
USE dmotifs
USE param

IMPLICIT NONE

! MAT-FILE Declarations !

INTEGER matOpen, matGetDir 
INTEGER matGetVariableInfo
INTEGER mp, dir, adir(100), pa
INTEGER mxGetM, mxGetN, matClose
INTEGER ndir, i, clstat
CHARACTER*32 names(100) 

!===========================!

if(all(fnames(:)%fn .NE. argfun)) then
    write(*,*) "No such motif: ",argfun
    write(*,*) "Input format-> main <motifname>"
    stop
else

    fin=fchton(argfun)  
    y0=nM2m*analys(p,argfun)

    ! ==> OPEN MAT-file <== !

    mp=matOpen('./PRMS_lxr_29Apr15.mat','r')

    if (mp .eq. 0) then
         write(6,*) "Can't open MAT-file"
         stop
    end if

    dir = matgetdir(mp, ndir)

      if (dir .eq. 0) then
         write(6,*) "Can't read MAT-file-directory."
         stop
    endif

    call mxCopyPtrToPtrArray(dir, adir, ndir)

    do 20 i=1,ndir
         call mxCopyPtrToCharacter(adir(i), names(i), 32)
 20 continue

    write(6,*) 'Directory of Mat-file:'

    do 30 i=1,ndir
        write(6,*) names(i)
 30 continue

    write(6,*) 'Getting Header info from first array.'
    pa = matGetVariableInfo(mp, names(1))
    write(6,*) 'Retrieved ', names(1)
    write(6,*) '  With size ', mxGetM(pa), '-by-', mxGetN(pa)
    call mxDestroyArray(pa)

    clstat=matClose(mp)

end if
END PROGRAM main

I am using gfortran 4.8.3 for compiling+linking using the default command:

gfortran main.f90 dmotifs.o param.o ssa.o -o main

This code compiles fine (without linking) when I do not include: #include "finitrf.h", otherwise the compiler says

Warning: main.f90:1: Illegal preprocessor directive

I tried renaming finitrf.h to finitrf.f90 but it did not make any difference. Nonetheless during linking I am getting these errors:

main.f90:(.text+0x3ea): undefined reference to `matopen_'
main.f90:(.text+0x487): undefined reference to `matgetdir_'
main.f90:(.text+0x52b): undefined reference to `mxcopyptrtoptrarray_'
main.f90:(.text+0x583): undefined reference to `mxcopyptrtocharacter_'
main.f90:(.text+0x71b): undefined reference to `matgetvariableinfo_'
main.f90:(.text+0x804): undefined reference to `mxgetm_'
main.f90:(.text+0x855): undefined reference to `mxgetn_'
main.f90:(.text+0x89c): undefined reference to `mxdestroyarray_'
main.f90:(.text+0x8b0): undefined reference to `matclose_'
collect2: error: ld returned 1 exit status

Do I need a makefile or add additional arguments in the compile command?

EDIT:

I added the -cpp option and that eliminates the problem of Illegal preprocessor directive

Now when I am compiling with paths to matlab external components (where finitf.h) is, I am still getting the same error.

gfortran main.f90 dmotifs.o param.o ssa.o -I/usr/local/matlab2008a/extern/include -L/usr/local/matlab2008a/extern/lib -cpp -o main

If I provide library path to /usr/local/matlab2008a/bin/glnxa64 that contains other matlab libraries including libmat.so, I still get the same errors.


Solution

  • As pointed out by Alexander Vogt, the compiler requires -cpp option for the pre-processor to recognize the header file and not to treat it as illegal.

    Linking requires finitrf.h which is usually located in the <matlabroot>/extern/include and the essential libraries are present in <matlabroot>/bin/<arch>/.

    But just specifying this does not work and specification of the exact matlab library seems essential; these are libmat.so and libmx.so.

    These libraries are in turn dependent on other libraries so another flag is required to set the rpath.

    Finally it works with following command:

    gfortran main.f90 dmotifs.o param.o ssa.o -I/usr/local/matlab2008a/extern/include -L/usr/local/matlab2008a/bin/glnxa64 -cpp -o main -lmat -lmx -Wl,-rpath /usr/local/matlab2008a/bin/glnxa64/
    

    or in general

    gfortran program.f90 -I<matlabroot>/extern/include -L<matlabroot>/bin/<arch> -cpp -lmat -lmx -Wl, -rpath <matlabroot>/bin/<arch> -o program.out
    

    Also see this post that is about the same problem in C.