gfortran,DLL,下划线

时间:2009-12-31 15:27:06

标签: dll fortran gfortran

我想从第三方DLL访问一些子程序。这些函数使用STDCALL作为调用约定。

正在运行dumpbin /export foo.dll给我的内容如下:

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

我使用以下代码编译代码:

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

我收到错误:undefined reference to '_foo_'(请注意下划线)。

我尝试添加-mrtd编译标志,以及我用Google搜索的其他标志,都无济于事。

如何告诉fortran不添加下划线?


编辑:按顺序进行一些澄清。

  1. 我有一个现有的DLL,我没有源代码。
  2. 如果有帮助的话,这个DLL是用Visual Basic编写的。
  3. 我想从 fortran调用此DLL
  4. 当我在test.f90中写道时:Foo(1.0d0)我收到undefined reference to '_foo_'链接错误

4 个答案:

答案 0 :(得分:3)

您是否尝试过-fno-underscoring?

我在http://www.rhinocerus.net/forum/lang-fortran/604847-fortran-dll-call-excel-2.html(接近结尾)发现了Tobias Burnus(一个gfortran开发人员)的帖子 - 他建议使用编译器指令而不是-mrtd。

答案 1 :(得分:2)

您需要将ISO_C_BINDING与编译器属性结合使用。你应该真正阅读gfortran手册的Mixed-Language Programming部分。它提供了可以与其他编译器一起使用的好建议。特别是,在您的情况下,您需要stdcall属性:

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

注意stdcall行,它应该使它起作用。

答案 2 :(得分:1)

只想展开M.S.B's -fno-underscoring answer:如果使用f2c& G77。来自the gfortran documentation

  

-funderscoring生效,GNU   Fortran附加一个下划线   外部名称没有下划线。   这样做是为了确保兼容性   使用许多UNIX生成的代码   Fortran编译器。

     

警告:GNU的默认行为   Fortran与f2c和f2c不兼容   g77,如果是,请使用-ff2c选项   你想要用。编译的目标文件   GNU Fortran兼容   用这些工具创建的目标代码。

     

使用-fno-underscoring不是   建议除非你是   试验诸如此类的问题   将GNU Fortran集成到   现有的系统环境   (相对于现有的图书馆,工具,   等等。)

您可能需要使用-fno-underscoring之类的内容重新编译DLL,以从DLL中删除下划线。

我遇到某些Fortran编译器与下划线前缀/后缀相关的可移植性问题:默认情况下有些编译器_prefix或suffix_,而其他编译器没有!我的解决方案是预处理器指令:

#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()

答案 3 :(得分:0)

另一种方法是使用Fortran 2003的ISO C绑定,gfortran> = 4.3支持。这将自动使用C的强调约定(即,可能没有),而不是Fortran编译器的约定。如果Windows链接器关心它,它还可以控制子例程名称的大小写(大小写)。 Fortran不区分大小写,因此您可以通过任何方式调用Fortran子例程 - 可能是链接器转换为小写。

在调用“Foo”的Fortran例程的声明中包含以下“接口”,将Foo描述为具有双类型的单个参数的C子例程(void函数) - Fortran输入/输出或指针C.如果Foo有其他属性,则需要更改接口。 “bind”子句指定要提供给链接器的区分大小写的名称。如果从几个Fortran例程调用Foo,那么最好将接口放入一个模块并从每个Fortran例程中“使用”它。

这适用于C - 也许它适用于Visual Basic。 ISO C绑定提供了很多控制,所以如果这不起作用,可能会有一些变化。

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