gfortran, DLL, underscore

2019-03-03 11:51发布

问题:

I want to access some subroutines from a third party DLL. The functions use STDCALL as the calling convention.

Running dumpbin /export foo.dll gives me something like:

      ...
      7    6 00004B40 Foo@16
      ...

I compile my code using:

      gfortran test.f90 -o test.exe -Wl,foo.dll

I get an error: undefined reference to '_foo_' (note the underscores).

I have tried adding the -mrtd compilation flag, as well as other flags I googled, all to no avail.

How can I tell fortran to not add the underscores?


edit: A bit of clarification is in order.

  1. I have an existing DLL to which I do not have the source to.
  2. This DLL is written in Visual Basic, if it helps.
  3. I want to call this DLL from fortran.
  4. When I write in test.f90: Foo(1.0d0) I get an undefined reference to '_foo_' linkage error

回答1:

Did you try -fno-underscoring ?

I found a post by Tobias Burnus (a gfortran developer) at http://www.rhinocerus.net/forum/lang-fortran/604847-fortran-dll-call-excel-2.html (near the end) -- he recommends the use of compiler directives instead of -mrtd.



回答2:

You need to combine the use of ISO_C_BINDING with compiler attributes. You should really read the Mixed-Language Programming section of the gfortran manual. It gives good advice that can be used with other compilers as well. In particular, in your case you need the stdcall attribute:

interface VisBasSubs

   subroutine foo (DoubleArg)  bind (C, name="Foo")
      !GCC$ ATTRIBUTES stdcall :: foo
      use iso_c_binding, only: c_double
      real (kind=c_double), intent (inout) :: DoubleArg      

   end subroutine foo

end interface VisBasSubs

Notice the line with stdcall, it's what should make it work.



回答3:

Just wanted to expand on M.S.B's -fno-underscoring answer: You may run into issues if using f2c & g77. From the gfortran documentation:

With -funderscoring in effect, GNU Fortran appends one underscore to external names with no underscores. This is done to ensure compatibility with code produced by many UNIX Fortran compilers.

Caution: The default behavior of GNU Fortran is incompatible with f2c and g77, please use the -ff2c option if you want object files compiled with GNU Fortran to be compatible with object code created with these tools.

Use of -fno-underscoring is not recommended unless you are experimenting with issues such as integration of GNU Fortran into existing system environments (vis-à-vis existing libraries, tools, and so on).

You might need to recompile the DLL with something like -fno-underscoring to remove the underscores from the DLL.

I've run into portability issues related to underscore prefix/suffix by certain Fortran compilers: Some compilers _prefix or suffix_ by default, while others don't! My solution has been preprocessor directives:

#ifdef LC_UNSC
#define  GET_DIP_MOMENT get_dip_moment_
#elif LC_NOUNSC
#define  GET_DIP_MOMENT get_dip_moment
#endif
...
     call GET_DIP_MOMENT()


回答4:

A different approach is to use the ISO C Binding of Fortran 2003, which is supported by gfortran >= 4.3. This will automatically use the underscoring conventions of C (i.e., probably none), rather those of the Fortran compiler. It will also give you control over the case (capitalization) of the subroutine names, if the Windows linker cares about that. Fortran is case insensitive, and so you can call Fortran subroutines by any case -- probably the linker is converting to lower case.

Including the following "interface" in the declarations of the Fortran routine that calls "Foo" describes Foo to be a C subroutine (void function) with a single argument of double type -- Fortran input/output, or a pointer in C. If Foo has other properties, the interface needs to be changed. The "bind" clause specifies the case-sensitive name to provide to the linker. If you call Foo from several Fortran routines, then it is best to put the interface into a module and "use" it from each Fortran routine.

This is intended for C -- maybe it will work for Visual Basic. The ISO C Binding gives a lot of control, so if this doesn't work, maybe some variation will.

interface VisBasSubs

   subroutine foo (DoubleArg)  bind (C, name="Foo")

      use iso_c_binding, only: c_double
      real (kind=c_double), intent (inout) :: DoubleArg      

   end subroutine foo

end interface VisBasSubs