使用gfortran从DLL导出公共块
当变量是使用gfortran从DLL导出公共块,dll,fortran,gfortran,mingw-w64,Dll,Fortran,Gfortran,Mingw W64,当变量是公共块的一部分时,我无法从Fortran EXE正确访问Fortran DLL中的变量 我有一个简单的代码simple.f90,我使用MSYS64/MinGW-w64 gfortran 9.2作为 x86_64-w64-mingw32-gfortran simple.f90 -o simple.dll -shared 该库来自一个更简单的程序prog.f90,编译如下 x86_64-w64-mingw32-gfortran prog.f90 -o prog -L. -lsimple
公共
块的一部分时,我无法从Fortran EXE正确访问Fortran DLL中的变量
我有一个简单的代码simple.f90,我使用MSYS64/MinGW-w64 gfortran 9.2作为
x86_64-w64-mingw32-gfortran simple.f90 -o simple.dll -shared
该库来自一个更简单的程序prog.f90,编译如下
x86_64-w64-mingw32-gfortran prog.f90 -o prog -L. -lsimple
当注释掉公共
块/numbers/
时,代码工作并打印预期结果:
Before 0 0
After 1 2
但是,当我取消注释COMMON
块时,输出变为
Before 0 0
After 0 0
好像程序使用的变量突然与库中使用的变量不同
这两种变体在使用gfortran 9.1的基于Linux的操作系统中同样有效
我知道“在某些系统上,过程和全局变量(模块变量和公共块)需要特殊处理,以便在共享库中访问”,如下所述:。但是,我无法插入该类型的语句
!GCC$ ATTRIBUTES DLLIMPORT :: numbers
或
在代码中的任何位置都不会被编译器捕捉。正如M.Chinoune在文章中指出的那样,当前的gfortran缺乏从DLL导入公共块的能力。尽管已经有一段时间了,但它尚未合并。最后,我需要两件事才能使上述代码正常工作: 首先,将以下修补程序应用于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));
在主程序中需要(就在
implicit none
之后),但在任何地方都不需要任何导出。这显然是一种不同于英特尔Fortran的语法方法,在英特尔Fortran中,导入的是公共
块,而不是其组成部分。我还发现我需要导入a
和b
,即使我只需要b
。(当只需要a
时,只导入a
就足够了。)正如M.Chinoune在中指出的那样,当前的gfortran缺乏从DLL导入公共块的能力。尽管已经有一段时间了,但它尚未合并。最后,我需要两件事才能使上述代码正常工作:
首先,将以下修补程序应用于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));
在主程序中需要(就在
implicit none
之后),但在任何地方都不需要任何导出。这显然是一种不同于英特尔Fortran的语法方法,在英特尔Fortran中,导入的是公共
块,而不是其组成部分。我还发现我需要导入a
和b
,即使我只需要b
。(当只需要a
时,只导入a
就足够了。)尝试在属性指令中使用/numbers/
。ifort就是这样做的。代码是无效的Fortran,所以gfortran可以做它想做的任何事情。@SteveLionel谢谢你的建议,但当我用斜杠括起数字时,gfortran吐出了“错误:名称中的无效字符”@您能否更具体地说明代码的哪些部分无效以及如何修复它?当您尝试使用print*,“Before”,a,b
打印它们时,您希望a
和b
具有什么值<代码>a
和b
未定义!如果您使用的是模块,则不要使用common
。这是gfortran中的已知错误,请尝试在属性指令中使用/numbers/
。ifort就是这样做的。代码是无效的Fortran,所以gfortran可以做它想做的任何事情。@SteveLionel谢谢你的建议,但当我用斜杠括起数字时,gfortran吐出了“错误:名称中的无效字符”@您能否更具体地说明代码的哪些部分无效以及如何修复它?当您尝试使用print*,“Before”,a,b
打印它们时,您希望a
和b
具有什么值<代码>a
和b
未定义!如果您使用的是模块,则不要使用common
。这是gfortran中已知的错误
!GCC$ ATTRIBUTES DLLEXPORT :: numbers
--- 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