在一个Linux应用程序

时间:2018-06-01 16:21:03

标签: c++ linux shared-libraries libstdc++

我们在旧的发布系统上编译了一组给定的遗留C ++库,使用libstdc ++。so.5.0.0编译旧的编译器gcc 3.2。最新的CentOS7将使用兼容性库libstdc ++。so.5.0.7运行在旧操作系统上编译的可执行文件,而具有不同库ABI的当前C ++版本是libstdc ++。so.6。

我们新版本的可执行文件是在新操作系统上构建的,无法再在旧平台上构建。但目前在CentOS7上重新编译遗留库也不是一个选择:数值结果会略有不同。所以我想使用它们与libstdc ++。so.5一样,而我的二进制文件的其余部分使用c ++版本。

this post建议使用与静态版本libstdc ++链接的包装器c接口库.a.5。

this post主要暗示相同。

在我们的例子中,这个方法似乎是可行的,因为接口只是C风格,不使用C ++对象。而且C-ABI似乎是c ++ lib两个版本之间的一种障碍。

但是,我还没有找到提供静态C ++。5库的人。另外我想我曾经在一个应用程序中听说过并行使用libstdc ++的两个共享库版本。那么还有一个保持共享C ++。5库的解决方案吗?我有一些弱的记忆,他们也使用C库作为边界。它也适用于dlopen()吗?

我目前的情况是这样的:

使用旧的gcc-3.2,libstdc ++。so.5,32位模式在旧操作系统上编译:

  • libA1.so使用C ++
  • libA2.so调用libB.so,两者都使用C ++,libA2明确地链接 libstdc ++与链接器选项-lstdc ++,libB没有,但可能它得到了它 来自libA的符号
  • libwrapper.so只使用C而不是C ++,与/使用libA1和libA2链接。

使用新的gcc-4.8.5在新操作系统上编译:

  • 可执行(32位)使用dlopen()系统调用调用libwrapper.so, 所以间接调用C ++库libA1.so和libA2。
  • 可执行文件还使用共享C ++库libC.so(但接口是C风格)
  • 可执行文件还使用共享C ++库libB.so(但接口是C样式),libA1和libA2也需要它。

因此,可执行文件必须使用新的libstdc ++。so.6 for libC,但是会间接调用libA1,libA2,libB,它必须使用旧的libstdc ++。so.5。

我是否必须将包装器lib导出的符号完全限制在我的API中,而不是使用链接器的版本脚本标志来公开1中的pobedims注释中的任何c ++符号?

或许我只是将旧操作系统上的旧版lib链接到-lstdc ++,但使用全名/usr/lib/libstdc++.so.5? libB将继续从libA2中获取正确的符号吗?

我的可执行链接/依赖于......

  1. libB.so(C ++)
  2. libC.so(C ++),需要libstdc ++。6
  3. libwrapper.so(带有C接口),使用动态加载dlopen()加载,它本身链接到" worker" libA1和libA2(也提供C接口):
    • libA1.so使用C ++。5
    • libA2.so使用C ++。5
      • libB.so使用C ++。5
  4. 可执行文件与-rdynamic链接,也许这是一个问题?如何确保使用同名可执行文件中的符号解析libA1,A2,B中的符号?

    稍后修改/解决方案注1:尝试在旧平台上使用存档版本libstdc ++进行链接.a.5导致错误,该错误仅在更高版本的gcc> = 3.4中修复:
        错误:ld:libwrapper.so:未定义的版本化符号名称_ZSt10time_put_w @@ GLIBCPP_3.2
        ld:未能设置动态部分大小:错误值

    所以这不是一个选择。

    注2: LibB是一个问题,因为它是由工作库和可执行文件本身所期望的。如果可执行文件使用新版本的libB,则会引入libstdc ++。so.6,其中的符号将传递给worker libs,这会在启动时崩溃。我已经将用过的libB版本更改为旧系统上编译的版本,只需在运行时系统上进行交换即可。这是可能的,因为简单的C接口是二进制兼容的。因此,我的可执行文件(通过libB)和worker libs libA1和libA2都使用相同的libstdc ++。so.5。我的(C)可执行文件是直接链接libstdc ++。so.5构建的。现在我的可执行文件可以启动并运行。

    注3:我发现参考结果和新结果之间存在一些数值差异。使用LD_PRELOAD机制已经解决了这些问题:     LD_PRELOAD = libstdc ++。so.5 my_executable

    这似乎很好用。我认为通过使用LD_PRELOAD,我确保libstdc ++。so.5在提供从libstdc ++解析的符号方面具有优势。我之前没有提到的:我们在旧平台上使用了英特尔编译器,我使用了数学库libimf.so,如下所示:LD_PRELOAD =" libimf.so libstdc ++。so.5"提供两个库。结果,数值差异消失了,这似乎是由普通数学函数的实现引起的。

0 个答案:

没有答案