3

环境:Intel Linux,Red Hat 5。编译器:gcc 3.4.6(旧东西,具有严重基础设施的遗留环境,抱歉)

我有从 Fortran 派生的特定共享库的多个版本(称之为“shared_lib.so”),其中包含一个 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 在链接时拥有的一些智能。

4

2 回答 2

1

简短的回答

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

长答案

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

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

将代码从 Windows 转换到 Linux 的主要变化是分别使用部分替换 WindowsLoadLibraryGetProcAddressLinuxdlopen和例程。共享库是使用.dlsym#ifdef-fpic-shared

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

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

于 2015-01-13T23:49:11.460 回答
0

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

以下是 2008 年标准的内容COMMON

5.7.2.4 共同关联

1 在一个程序中,所有同名的非零大小公共块的公共块存储序列具有相同的第一个存储单元,所有同名的零大小公共块的公共块存储序列是与一个关联的存储其他。在一个程序中,所有非零大小的空白公共块的公共块存储序列具有相同的第一存储单元,并且所有零大小的空白公共块的存储序列相互关联,并且与任何非零大小的第一存储单元相关联。大小的空白公共块。这会导致对象在不同范围单元中的关联。使用或主机关联可能会导致这些关联对象在同一范围单元中可访问。

简而言之,COMMON同一程序中同名的段占用相同的存储空间。

程序定义如下。

2.2.2 程序

1 一个程序应仅由一个主程序、任意数量(包括零)的其他类型的程序单元、任意数量(包括零)的外部程序以及任意数量(包括零)的通过非 Fortran 方式定义的其他实体组成. 主程序应由 Fortran 主程序程序单元或通过 Fortran 以外的方式定义,但不能同时由两者定义。

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

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

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

于 2014-11-20T23:28:27.113 回答