可见性,Fortran公共变量,共享库的运行时加载

时间:2014-11-18 23:53:28

标签: c fortran visibility dlopen fortran-common-block

环境:英特尔Linux,Red Hat 5。 编译器:gcc 3.4.6 (旧的东西,有严重基础设施的遗留环境,对不起)

我有一个特定共享库的多个版本(称之为" shared_lib.so"),它来自Fortran,它包含一个COMMON块和各种计算,并引用该COMMON中的变量。

我需要能够(从最终产品可执行文件中的其他地方的C代码)使用dlclose()和dlopen()在运行此库的版本(其中所有版本的COMMON内容完全相同)的同时运行。在某些情况下,相同的COMMON也出现在代码中,该代码是静态库的一部分(称为" static_lib.a"),它也链接到可执行文件中,并且与我的项目分开维护但具有功能它与我的共享库中的交互。

我似乎看到COMMON的多个实例在可执行文件中结束,并且(更重要的是)实例中的变量值与静态库之间没有链接,并且“相同”的值“使用dlopen()引入共享库的实例中的变量。

总之,我需要(在整个可执行文件中)dlopen() - 加载的shared_lib.so能够在COMMON ABC中设置/使用变量XYZ,并且在static_lib.a中设置/使用代码来设置/使用XYZ,并使其实际上是XYZ的相同实例,或者至少使两者保持同步。这可能吗?

我在shared_lib.so中的源代码编译命令的格式为:

g77 –c –g –m32 -fPIC –o shared_src.o shared_src.f

我建立shared_lib.so的命令格式为:

gcc -g -m32 -fPIC -shared -o shared_lib.so *.o

我构建可执行文件的命令格式为:

gcc –g -m32 –rdynamic –o exec exec.o static_lib.a shared_lib.so –lm –ldl –lg2c

我需要从表格的C代码中做一些事情:

handle1 = dlopen ("shared_lib.so", RTLD_NOLOAD);
dlclose (handle1);
handle2 = dlopen ("shared_lib2.so", RTLD_NOW | RTLD_GLOBAL);
...

对于所需的变量,初始启动配置似乎确实正常运行,但后续dlclose()和dlopen()序列的结果却没有。也许潜在的问题是dlopen()缺乏gcc在链接时拥有的一些智能。

2 个答案:

答案 0 :(得分:0)

这不是一个真正的答案,但可能对你有帮助。

以下是2008年标准对COMMON所说的内容:

  

5.7.2.4共同关联

     

1在程序中,所有非零大小的公共块的公共块存储序列具有相同的   name具有相同的第一个存储单元和公共块存储   具有相同名称的所有零大小公共块的序列是   存储相互关联。在一个程序中,共同的   所有非零大小的空白公共块的块存储序列都有   相同的第一个存储单元和所有的存储顺序   零大小的空白公共块彼此相关联   使用任何非零大小的空白公共块的第一个存储单元。   这导致不同作用域单元中的对象的关联。   使用或主机关联可能会导致这些关联的对象   可以在同一个范围单元中访问。

简而言之,同一程序中具有相同名称的COMMON个部分占用相同的存储空间。

程序定义如下。

  

2.2.2计划

     

1程序应由一个主程序,任何数量(包括零)的其他类型的程序单元组成   外部程序的编号(包括零)和任何编号   通过除以外的方式定义的其他实体(包括零)   Fortran语言。主程序应由Fortran主程序定义   程序单元或Fortran以外的方式,但不是两者。

标准没有说明静态与动态链接的任何内容,也没有将之前的语句限制为静态链接。因此,似乎动态加载的库应该与主程序共享COMMON块(我不确定技术上是否可行),因此GNU实现是不正确的。

另一方面,该标准也没有说明能否动态加载库。程序单元"由Fortran以外的方式定义"应该包括C库,但这并不能告诉我们这些程序单元如何连接到主程序。一般来说,Fortran不是一种非常动态的语言。

当然,您可以通过简单地不使用COMMON块来解决所有这些问题。如果一个过程需要读取/写入一些数据,只需将其作为参数传递给意图输入/输出。您还可以将派生类型中的数据组合在一起,并将其作为一个单元一起传递。如今(Fortran 2003+),您甚至可以使用面向对象的编程,因此不再需要全局变量。

答案 1 :(得分:0)

简短回答

您是否可以使用-fPIC重新编译可执行文件?我发现有必要使用-fPIC编译共享库和可执行文件,以便正确识别COMMON块。

答案很长

最近我遇到了一个类似的问题,即在可执行文件和FORTRAN共享库之间共享的COMMON块。但是,我使用的是英特尔编译器而不是GNU编译器。可执行文件混合为C/C++FORTRAN

现有(工作)Windows版本的代码通过DLLEXPORT / DLLIMPORT ATTRIBUTE指令共享可执行文件和DLL之间的公共块来工作。根据英特尔编译器文档,这些属性指令在Linux中无法识别。实际上,Linux Intel编译器只会为这些指令发出警告。

将代码从Windows转换为Linux的主要变化是使用{{1}分别用Linux的LoadLibraryGetProcAddress例程替换Windows dlopendlsym部分。共享库使用#ifdef编译并与-fpic链接。

虽然共享库是使用-shared编译的,但可执行文件是 NOT 。运行以这种方式编译的代码时,通过子例程调用传递给共享库的变量被正确传递,但-fpic块变量未正确设置(或未初始化)。

绝望之下,我终于尝试使用COMMON编译器选项编译可执行文件,然后在共享库中正确识别-fpic块。