【问题标题】:Export COMMON block from DLL with gfortran使用 gfortran 从 DLL 导出 COMMON 块
【发布时间】:2019-12-28 06:19:24
【问题描述】:

当变量是COMMON 块的一部分时,我无法从 Fortran EXE 正确访问 Fortran DLL 中的变量。

我有一个简单的代码 simple.f90,我使用 MSYS64/MinGW-w64 gfortran 9.2 as 将其编译成 DLL

x86_64-w64-mingw32-gfortran simple.f90 -o simple.dll -shared
! simple.f90

module m
    implicit none
    integer :: a, b
   !common /numbers/ a, b
end module

subroutine init_vals
    use m
    implicit none
    a = 1
    b = 2
end subroutine

这个库是从一个更简单的程序prog.f90中使用的,编译为

x86_64-w64-mingw32-gfortran prog.f90 -o prog -L. -lsimple
! prog.90

program p

    use m
    implicit none

    print *, 'Before', a, b
    call init_vals
    print *, 'After', a, b

end program

COMMON/numbers/ 被注释掉时,代码工作并打印预期结果:

 Before           0           0
 After           1           2

但是,当我取消注释 COMMON 块时,输出变为

 Before           0           0
 After           0           0

好像程序使用的变量突然与库中使用的变量不同。

这两种变体在带有 gfortran 9.1 的基于 Linux 的操作系统中同样有效。

我知道“在某些系统上,过程和全局变量(模块变量和 COMMON 块)在共享库中时需要特殊处理才能访问”,如下所述:https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gfortran/GNU-Fortran-Compiler-Directives.html。但是,我无法插入该类型的语句

!GCC$ ATTRIBUTES DLLIMPORT :: numbers

!GCC$ ATTRIBUTES DLLEXPORT :: numbers

代码中的任何位置,而不会被编译器捕捉到。

【问题讨论】:

  • 尝试在 ATTRIBUTES 指令中使用/numbers/。这就是在 ifort 中的做法。
  • 代码是无效的Fortran,所以gfortran可以为所欲为。
  • @SteveLionel 感谢您的建议,但是当我将numbers 括在斜杠中时,gfortran 会吐出“错误:名称中的字符无效”。 @evets 您能否更具体地说明代码的哪一部分无效以及如何解决?
  • 当您尝试使用print *, "Before", a, b 打印它们时,您期望ab 具有什么价值? ab 未定义!如果您使用模块,请不要使用common
  • 这是 gfortran 中的一个已知错误 gcc.gnu.org/bugzilla/show_bug.cgi?id=47030

标签: dll fortran gfortran mingw-w64


【解决方案1】:

正如 M. Chinoune 在comment 中指出的那样,当前的 gfortran 缺乏从 DLL 导入公共块的能力。尽管patch 已经有一段时间了,但它还没有被合并。最后,我需要两件事来使上面的代码工作:

首先,将以下补丁应用到 GCC 9.2 并在 MSYS2 中手动编译编译器:

--- gcc/fortran/trans-common.c.org  2019-03-11 14:58:44.000000000 +0100
+++ gcc/fortran/trans-common.c      2019-09-26 08:31:16.243405900 +0200
@@ -102,6 +102,7 @@
 #include "trans.h"
 #include "stringpool.h"
 #include "fold-const.h"
+#include "attribs.h"
 #include "stor-layout.h"
 #include "varasm.h"
 #include "trans-types.h"
@@ -423,6 +424,9 @@
   /* If there is no backend_decl for the common block, build it.  */
   if (decl == NULL_TREE)
     {
+      unsigned id;
+      tree attribute, attributes;
+
       if (com->is_bind_c == 1 && com->binding_label)
        decl = build_decl (input_location, VAR_DECL, identifier, union_type);
       else
@@ -454,6 +458,23 @@

       gfc_set_decl_location (decl, &com->where);

+      /* Add extension attributes to COMMON block declaration. */
+      if (com->head)
+       {
+         attributes = NULL_TREE;
+         for (id = 0; id < EXT_ATTR_NUM; id++)
+           {
+             if (com->head->attr.ext_attr & (1 << id))
+               {
+                 attribute = build_tree_list (
+                   get_identifier (ext_attr_list[id].middle_end_name),
+                   NULL_TREE);
+                 attributes = chainon (attributes, attribute);
+               }
+           }
+         decl_attributes (&decl, attributes, 0);
+       }
+
       if (com->threadprivate)
        set_decl_tls_model (decl, decl_default_tls_model (decl));


其次,只有一行

!GCC$ ATTRIBUTES DLLIMPORT :: a, b

在主程序中需要(在implicit none 之后),但在任何地方都不需要任何导出。这显然是一种与英特尔 Fortran 不同的语法方法,其中导入 COMMON 块而不是其组成部分。我还发现我需要同时导入ab,即使我只需要b。 (当只需要a 时,只导入a 就足够了。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2021-09-17
    • 2013-10-23
    相关资源
    最近更新 更多