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

Bru*_*ams 8 c++ linux gcc libstdc++ c++11

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

我希望使用/ opt // lib64下的应用程序发布新版本的libstdc ++(注意:这是在GPL例外情况下特别允许的)

新版本的libstdc ++.so与目标平台上的版本只有次要版本不同.libstdc ++旨在向前兼容,以便现有程序可以使用新版本的库.但是,当一些程序使用新版本而不是旧版本时,我观察到行为(即错误)的细微差别.我希望防止这种情况发生.

我还发现,ld将尝试我的应用程序使用的libstdc系统版本链接++,除非我把的/ opt // lib64的较早的LD_LIBRARY_PATH.据说你可以使用强制链接特定版本-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 
Run Code Online (Sandbox Code Playgroud)

它可能会导致细微而难以诊断的问题.所以我一直在寻找更好的方法.

我想知道是否有某种方法我可以将libstdc ++重命名为lib_stdc ++并链接到该soname.重命名libstdc ++是不够的,因为您需要更改readelf给出的文件中的soname.即

0x000000000000000e (SONAME)             Library soname: [libstdc++.so.6]
Run Code Online (Sandbox Code Playgroud)

如果你在一个正常的程序上执行此操作,gcc即使使用-l:stdc++.so.6.0.20说,你会发现这给出了主要版本,而不是特定的次要版本.即

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

而不是:

0x0000000e (SONAME)                     Library soname: [libstdc++.so.6.0.20]
Run Code Online (Sandbox Code Playgroud)

所以我改为使用我想要依赖的soname创建一个虚拟共享库,以便添加依赖项,如下所示:

gcc dummy.o -Wl,-soname,lib<vendor>_stdc++.so.6.0.20 -nostdlib -shared -o lib<vender>_dummycpp.so
Run Code Online (Sandbox Code Playgroud)

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

然后:

gcc <myapp> -l<vendor>_dummycpp
Run Code Online (Sandbox Code Playgroud)

根据需要,我现在得到:

readelf -d <myapp>

0x0000000000000001 (NEEDED)             Shared library: [lib<vendor>_stdc++.so.6.0.20]
Run Code Online (Sandbox Code Playgroud)

代替

0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
Run Code Online (Sandbox Code Playgroud)

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

它让我感到有些狡猾,因此我想问的问题是:

  • 这是一个好主意吗?

  • 如果不是为什么不呢?

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

注意:如果在RPM中使用不同的名称(例如lib_stdc ++.so.6.0.20)打包libstdc ++,您将缺少对它的依赖,需要使用--nodeps进行安装.这是因为RPM扫描链接时间依赖性.解决方法是安装虚拟库.然后RPM将从虚拟库中获取soname而不是声称它丢失了.

Jon*_*ely 2

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

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

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

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