使用gfortran从DLL导出COMMON块 [英] Export COMMON block from DLL with gfortran
问题描述
当变量是COMMON
块的一部分时,我无法从Fortran EXE正确访问Fortran DLL中的变量.
I am having trouble correctly accessing a variable in a Fortran DLL from a Fortran EXE when the variable is part of a COMMON
block.
我有一个简单的代码 simple.f90 ,我使用MSYS64/MinGW-w64 gfortran 9.2将其编译为DLL
I have a trivial code simple.f90 which I compile into a DLL using MSYS64/MinGW-w64 gfortran 9.2 as
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 ,编译为
This library is used from a even simpler program prog.f90, compiled as
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/
被注释掉时,代码开始工作并打印预期结果:
When the COMMON
block /numbers/
is commented out, the code works and prints the expected result:
Before 0 0
After 1 2
但是,当我取消注释COMMON
块时,输出变为
However, when I uncomment the COMMON
block, the output becomes
Before 0 0
After 0 0
好像程序使用的变量突然不同于库中使用的变量.
as if the variables used by the program were suddenly distinct from those used in the library.
两个变体在具有gfortran 9.1的基于Linux的操作系统中均能很好地工作.
Both variants work equally well in a Linux-based OS with gfortran 9.1.
我知道在某些系统上,过程和全局变量(模块变量和COMMON块)在共享库中时需要进行特殊处理才能访问",如下所述:
I am aware that "On some systems, procedures and global variables (module variables and COMMON blocks) need special handling to be accessible when they are in a shared library," as mentioned here: https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gfortran/GNU-Fortran-Compiler-Directives.html . However, I was not able to insert a statement of the type
!GCC$ ATTRIBUTES DLLIMPORT :: numbers
或
!GCC$ ATTRIBUTES DLLEXPORT :: numbers
在代码中的任何位置,而不会被编译器锁定.
anywhere in the code without being snapped at by the compiler.
推荐答案
正如M. Chinoune在补丁了,但这并不是尚未合并.最后,我需要做两件事才能使上面的代码起作用:
As pointed out by M. Chinoune in the comment, current gfortran lacks the ability to import common blocks from DLLs. Even though there has been a patch for some time, it is not yet merged. In the end, I needed two things to make the above code work:
首先,将以下修补程序应用于GCC 9.2,然后在MSYS2中手动编译该编译器:
First, apply the following patch to GCC 9.2 and compile the compiler manually in 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
之后)需要
,但在任何地方都没有任何导出.这显然是与Intel Fortran不同的语法方法,在Intel Fortran中,此方法导入COMMON
块而不是其组成部分.我还发现,即使我只需要b
,也需要同时导入a
和b
. (当只需要a
时,仅导入a
就足够了.)
was needed in the main program (right after implicit none
), but not any exports anywhere. This is apparently a different syntactical approach then in Intel Fortran, where one imports the COMMON
block rather than its constituents. I also found out that I needed to import both a
and b
even if I only needed b
. (When only a
was needed, importing a
only was enough.)
这篇关于使用gfortran从DLL导出COMMON块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!