一尘不染

强制或禁止使用特定的次要版本的libstdc ++

linux

为了利用C 11和c 14功能,我有一个使用较新版本的gcc(4.9.1)和较新的libstdc
编译的应用程序。该应用程序由许多小程序组成,因此我将libstdc 作为共享库而不是静态库进行链接(即,我不希望使用-static-libstdc
++)

我希望将新版本的libstdc ++与应用程序一起放在/ opt // lib64下(注意:GPL的例外明确允许这样做)

libstdc 。so的新版本与目标平台上的版本仅次要版本不同。libstdc
设计为向前兼容,以便现有程序可以使用该库的新版本。但是,当某些程序使用新版本而不是旧版本时,我观察到了行为上的细微差异(即错误)。我希望防止这种情况。

我还发现,ld除非我将/ opt // lib64放在较早的LD_LIBRARY_PATH上,否则它将尝试将我的应用程序与libstdc
的系统版本链接。可以使用强制链接到特定版本-l:<library>.<version>,但这似乎不起作用。我怀疑这是针对用户创建的库,而不是针对像libstd
这样的语言运行时库,因为gcc本身会生成链接描述文件。同样在我的目标平台之一(RHEL5)上,gcc / ld甚至不了解它。我认为可以通过使用-
nostdlib并在构建系统中链接所需的所有内容(例如-lgcc),而不是将其留给我希望的gcc来实现。到目前为止,我还没有尝试过。

一种简单的解决方法是确保在我运行应用程序时LD_LIBRARY_PATH包含/ opt //
lib64,否则,我可以将LD_PRELOAD与正确的库版本一起使用。如果有人决定忽略我的建议并运行,则会出现此问题

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/<vendor>/lib64

它可能导致难以诊断的问题。所以我一直在寻找更好的方法。

我想知道是否可以通过某种方式将libstdc 重命名为lib_stdc 并链接到该soname。重命名libstdc
++是不够的,因为您需要按照readelf的要求更改文件中的soname。即

0x000000000000000e (SONAME)             Library soname: [libstdc++.so.6]

如果您对gcc使用甚至通过-l:stdc++.so.6.0.20说链接的普通程序执行此操作,您会注意到这给出的是主要版本,而不是特定的次要版本。即

readelf -d <myapp>
0x0000000e (SONAME)                     Library soname: [libstdc++.so.6]

而不是:

0x0000000e (SONAME)                     Library soname: [libstdc++.so.6.0.20]

因此,我改为使用我想依赖的soname创建了一个虚拟共享库,以添加依赖关系,如下所示:

gcc dummy.o -Wl,-soname,lib<vendor>_stdc++.so.6.0.20 -nostdlib -shared -o lib<vender>_dummycpp.so

(其中dummy.o是一个空的目标文件,由一个空的源文件制成,以停止-nostdlib导致投诉)

然后:

gcc <myapp> -l<vendor>_dummycpp

根据需要,我现在得到:

readelf -d <myapp>

0x0000000000000001 (NEEDED)             Shared library: [lib<vendor>_stdc++.so.6.0.20]

代替

0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]

dummycpp库包含libstdc 中的所有符号,因为它是libstd ,因此完全不需要gcc与sost libstdc
++链接。我似乎已经完全解决了这个问题。

这让我感到有点棘手,所以我想在这里提出的问题是:

  • 这是一个好主意吗?

  • 如果不是,为什么不呢?

  • 有没有更好/更正确的方法?

注意:如果在RPM中将libstdc 打包为其他名称(例如lib_stdc 。so.6.0.20),则会缺少对它的依赖关系,需要使用–
nodeps进行安装。这是因为RPM扫描链接时间相关性。解决方法是也安装虚拟库。然后,RPM将从虚拟库中获取soname,并且不会声称它丢失。


阅读 550

收藏
2020-06-03

共1个答案

一尘不染

libstdc
++常见问题解答条目如何确保找到动态链接的库,链接到手册部分“
查找动态或共享库”,该部分说明了如何使用RPATH。

我的首选方法是使用RPATH,$ORIGIN这意味着搜索动态库依赖项的起始位置与二进制文件所在的目录相同(请参阅ld.so(8))。因此,如果与链接'-Wl,-rpath,$ORIGIN'(请注意引号,以防止$
ORIGIN被shell扩展),则可以将共享库安装在与已安装的二进制文件相同的目录中,并且在运行二进制文件时可以找到它们。或者,'-Wl,-rpath,$ORIGIN/../lib'如果您希望在某个安装前缀下有单独的binlib目录,请使用。

由于该库与二进制文件一起安装在一些ldconfig不会扫描的自定义路径中,并且不会LD_LIBRARY_PATH破坏环境,因此不应该使用该版本的应用程序将永远找不到较新的libstdc
++。

确保还安装了libstdc++.so.6指向libstdc++.so.6.0.20文件的符号链接,以便DT_NEEDEDfor
libstdc++.so.6可以找到该文件。

2020-06-03