【问题标题】:gfortran, DLL, underscoregfortran、DLL、下划线
【发布时间】:2009-12-31 15:27:06
【问题描述】:

我想从第三方 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_' 链接错误

【问题讨论】:

    标签: dll fortran gfortran


    【解决方案1】:

    你试过 -fno-underscoring 吗?

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

    【讨论】:

    • 哼。感谢您的回复,但我想调用 existing DLL from Fortran。我已编辑问题以使其更清楚。
    • 是的,我了解到您正在从 Fortran 调用现有的 DLL。从错误消息中,Fortran 调用“foo”,而 DLL 显然具有“Foo”。所以你想告诉 Fortran 编译器不要在例程名称中添加下划线,这是编译器选项 -fno-underscoring 所做的。
    • 抱歉,提供的链接谈到了调用 fortran DLL。出于某种原因,-fno-underscoring 没有帮助。当我用-v 编译时,我看到它确实被使用了,但它并没有改变错误信息。我会在不同的设置上尝试这个,也许......
    【解决方案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 的行,它应该可以工作。

    【讨论】:

      【解决方案3】:

      只是想扩展M.S.B's -fno-underscoring answer:如果使用 f2c 和 g77,您可能会遇到问题。来自the gfortran documentation

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

      注意:GNU 的默认行为 Fortran 与 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()
      

      【讨论】:

      • 很遗憾,我无法访问 DLL 源代码(据我所知,它是用 Visual Basic 编写的,适用于所有语言)
      【解决方案4】:

      另一种方法是使用 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
      

      【讨论】:

      • 我的第一个答案有一个链接,指向有关 stdcall 的 gcc 编译器指令的说明。
      猜你喜欢
      • 2015-03-20
      • 2010-09-18
      • 1970-01-01
      • 2013-08-22
      • 2021-06-21
      • 2012-12-21
      • 2012-04-26
      • 2021-11-28
      • 1970-01-01
      相关资源
      最近更新 更多