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

时间:2014-09-22 17:25:32

标签: c++ linux gcc c++11 libstdc++

为了使用C ++ 11和c ++ 14的功能,我有一个使用的应用程序 更新版本的gcc(4.9.1),因此是更新版本的libstdc ++。该应用程序包含许多 小程序所以我将libstdc ++作为共享库而不是静态库链接 (即我不想使用-static-libstdc ++)

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

新版本的libstdc ++。与目标平台上的版本只有次要版本不同。 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 

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

我想知道是否有某种方法我可以将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与soname libstdc ++链接。我似乎完全解决了这个问题。

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

  • 这是个好主意吗?

  • 如果不是为什么不呢?

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

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

1 个答案:

答案 0 :(得分:2)

libstdc ++ FAQ条目How do I insure that the dynamically linked library will be found链接到手册部分Finding Dynamic or Shared Libraries,该部分解释了如何使用RPATH。

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

ldconfig无法扫描的某个自定义路径中将二进制文件与二进制文件一起安装,并且没有LD_LIBRARY_PATH弄乱环境,新的libstdc ++将永远不会被应用程序找到不应该使用那个版本。

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