Does symbol capitalization matter in object files

2019-07-27 11:20发布

问题:

I'm trying to get the gfortran compiler working in MATLAB on Windows to create mex files. Gfortran isn't supported, but the Intel Fortran compiler is, which leads me to believe that a Fortran compiler should be able to compile Fortran source using MATLAB libraries.

As detailed in my previous question, I get an "undefined reference" error for every symbol that should come from the MATLAB libraries. I thought this was an error with the preprocessor not getting invoked as suggested in a question on MathWorks Answers, but after looking into this problem some more I don't believe that's the problem since the errors refer to things like "mxisnumeric800" which is a substitution made in the fintrf.h header.

I checked the symbols exported from the required libraries, libmx.dll and libmex.dll, using dumpbin. The exported symbols include two that are close to mxisnumeric800:

  Section contains the following exports for libmx.dll
...
       1431  596 0009F200 MXISNUMERIC800
...
       1747  6D2 000ABC24 mxIsNumeric_800
...

I can understand why mxIsNumeric_800 wouldn't be read as the same symbol due to the extra underscore, but does capitalization make a difference too?

回答1:

The problem you are having is that Fortran is a case insensitive language. So if you have a subroutine foo:

subroutine foo(x)
  real :: x
end subroutine foo

you could call it with any of the following:

call foo(x)
call FOO(x)
call fOo(x)

When you build an object file or library with this function, the symbol name will be compiler dependent. In case of Gfortran on a Linux system, it will always downcase the symbol name and add an underscore behind it such as

foo_

On Windows Systems it will behave differently (see here and here), and even different compilers will have different ideas.

So what now, what does this all mean?

This means that when you write a subroutine call like:

 call mxIsNumeric_800(arg1, arg2, arg3)

Gfortran will attempt to link it against a symbol mxisnumeric_800_ and not the symbol you expect. In the past, this often resulted into ugly hacks which were very not-portable. Fortran 2003, addressed this issue in a clear way by introducing the BIND attribute. An attribute which allows the programmer to inform the compiler that this object should be handled as a non-Fortran object (cfr. Section 15.5 of the F2008 standard).

With this attribute, you can now define an interface that is fully understood by Fortran and that the compiler knows where to find the corresponding symbol with its respective case-sensitivity. Eg.

interface
   subroutine mxisnumeric(arg1,arg2,arg3) BIND(C, NAME="mxIsNumeric_800")
      use, intrinsic :: iso_c_binding
      implicit none
      real(c_float) :: arg1
      integer(c_int) :: arg2
      character(c_char) :: arg3
   end subroutine mxisnumeric
end interface

Some more details can be found here.