如何使用g++静态链接除少数库外的所有库

How to statically link all libraries except a few using g++?

本文关键字:g++ 何使用 静态 链接      更新时间:2023-10-16

我有一个要求,即静态链接我的所有库,包括libstdc++、libc、pthread等。有一个omniorb库我想动态链接。

目前我已经动态链接了所有的库。ldd显示以下

linux-vdso.so.1 =>  (0x00007fff251ff000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f291cc47000)
libomniDynamic4.so.1 (0x00007f291c842000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f291c536000)
libm.so.6 => /lib64/libm.so.6 (0x00007f291c2e0000)
libgomp.so.1 => /usr/lib64/libgomp.so.1 (0x00007f291c0d7000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f291bebf000)
libc.so.6 => /lib64/libc.so.6 (0x00007f291bb66000)
/lib64/ld-linux-x86-64.so.2 (0x00007f291ce63000)
librt.so.1 => /lib64/librt.so.1 (0x00007f291b95d000)
libomniORB4.so.1 (0x00007f291b6aa000)
libomnithread.so.3 (0x00007f291cf35000

我需要ldd来显示libomniDynamic4.so.1作为唯一的动态链接库。

我该如何做到这一点?

试图制作一个在所有发行版上运行的linux可执行文件,嗯?祝你好运但我离题了。。。

您需要查看g++的-v标志输出。它显示了g++/ld执行的内部链接命令。具体来说,您将需要检查最终链接命令collect2及其所有参数。然后,您可以指定要链接到的.a库的确切路径。您还必须跟踪所有内容的静态库。我的libstdc++.a在/usr/lib/gcc/x86_64-linux-gnu/4.4/libstdc++.a

咆哮:我对linux最大的抱怨是可执行文件的断裂状态。为什么我不能在一台机器上编译二进制文件,然后将其复制到另一台机器并运行它!?即使是相隔一个版本的Ubuntu发行版,由于libc/libstdc++ABI不兼容,也会产生无法在另一个版本上运行的二进制文件

edit#1我只是想补充一下,这个页面上的脚本生成了一个可执行文件.so依赖项的.png。这在尝试执行您所描述的操作时非常有用。

请注意,ldd <exename>将列出链下的所有依赖项,而不仅仅是可执行文件的直接依赖项。因此,即使您的可执行文件只依赖omniorb.So,但omniorb.So依赖libphrad.So,ldd的输出也会列出这一点。查找readelf的手册页,只查找二进制文件的直接依赖项。

另一个需要注意的事项。如果omniorb.so依赖于libstdc++,那么您将别无选择,只能依赖于同一个lib。否则,ABI不兼容将破坏您的代码和omniorb的代码之间的RTTI。

我需要ldd来显示libomniDynamic4.so.1作为唯一的动态链接库。

这是不可能的。

首先,对于任何需要动态链接的(x86_64)二进制文件,ldd将始终显示ld-linux-x86-64.so.2。如果使用动态链接(与libomniDynamic4.so.1一样),则获得ld-linux-x86-64.so.2

其次,linux-vdso.so.1由内核"注入"到进程中。你也无法摆脱它。

接下来,问题是为什么要尽量减少动态库的使用。最常见的原因通常是错误地认为"大部分是静态的"二进制文件更具可移植性,并且将在更多的系统上运行。在Linux上,情况正好相反。

如果实际上您正在尝试实现一个可移植的二进制文件,那么有几种方法。迄今为止(根据我的经验)最好的一个是使用apgcc。

构建一个在许多Linux发行版上运行的二进制文件非常困难,静态链接不是关键。

请注意,使用旧的glibc版本(即旧的Linux发行版)构建的二进制文件也可能在新的Linux发行版本上运行。这是因为glibc是向后兼容的。

获得所需结果的一种可能方法是:

  • 在旧的Linux操作系统上编译二进制文件

  • 使用命令ldd或lsof查找已编译二进制文件所需的所有库(运行时)在二进制文件上,此处为详细信息

  • 将旧Linux操作系统所需的库复制到"自定义lib"文件夹中

  • 始终将这个自定义lib文件夹与您的二进制捆绑/发布

  • 创建一个bash脚本,将自定义lib文件夹放在LD_LIBRARY_PATH环境变量中文件夹列表的顶部,然后调用您的二进制文件。

通过这种方式,通过使用bash脚本执行二进制文件,我能够在各种不同Linux版本的嵌入式设备上执行二进制文件。但总有问题的情况下,这是失败的。

请注意,我一直使用cli applications/binary进行测试。

其他可能的方式

似乎还有一些优雅的方法可以编译glibc向后兼容的二进制文件,例如,这似乎可以编译与旧ABI兼容的二进制代码。但我没有检查过这条路线。

链接时,在指定要静态链接到的库之前使用-static,在要动态链接到的库前使用-dynamic

g++ <other options here> -dynamic -lomniDynamic4 -static -lpthread -lm -lgomp <etc>

当然,您需要静态链接的库的.a版本(duh)。