【问题标题】:How to statically link all libraries except a few using g++?如何使用 g++ 静态链接除少数库之外的所有库?
【发布时间】:2011-09-03 21:04:21
【问题描述】:

我要求我静态链接我的所有库,包括 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 显示为唯一的动态链接库。

我如何做到这一点?

【问题讨论】:

    标签: c++ g++ dynamic-linking static-linking


    【解决方案1】:

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

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

    达到预期结果的一种可能方法是:

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

    • 使用命令 ldd 或 lsof 找出编译后的二进制文件所需的所有库 (运行时)在二进制文件上,详情here

    • 将旧 Linux 操作系统所需的库复制到“custom-lib”文件夹中

    • 始终将此 custom-lib 文件夹与您的二进制文件捆绑/发布

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

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

    请注意,我总是使用 cli 应用程序/二进制文件对此进行测试。

    其他可能的方式..

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

    【讨论】:

    • 今天的一些 debian 更新讲述了相反的故事,libstdc++-6 丢失,libstdc++-7 已安装,应用程序需要重新编译。
    • 我想知道,从旧版本复制 libstdc++ 是否可以解决问题,如前所述,复制“依赖项”是解决我的问题的一种方式......很久以前。
    • 此外,有时,发行版中提供了向后兼容包。例如,packages.debian.org/buster/libstdc++6
    【解决方案2】:

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

    那是不可能

    首先,ldd总是为任何需要动态链接的 (x86_64) 二进制文件显示 ld-linux-x86-64.so.2。如果您使用动态链接(您可以使用libomniDynamic4.so.1),那么您获得ld-linux-x86-64.so.2

    其次,linux-vdso.so.1 被内核“注入”到您的进程中。你也无法摆脱它。

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

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

    【讨论】:

    • 您能否详细说明您的评论“最常见的原因通常是错误地认为“大部分是静态的”二进制文件不具有更高的可移植性,并且可以在更多系统上运行。在 Linux 上,这是与真实相反。” 我已经能够生成无法在没有“大部分静态”路由的其他机器上运行的二进制文件......
    【解决方案3】:

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

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

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

    edit #1 我只是想补充一下 The script on this page produces a .png of an executables .so dependencies. 这在尝试执行您描述的操作时非常有用。

    请注意ldd <exename> 将列出链中的所有依赖项,而不仅仅是可执行文件的直接依赖项。因此,即使您的可执行文件仅依赖于 omniorb.so,但 omniorb.so 依赖于 libphread.so,ldd 的输出也会列出这一点。查看readelf 的联机帮助页,仅查找二进制文件的直接依赖项。

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

    【讨论】:

    • 令人沮丧的是,我没有足够的代表来评论任何人的帖子。但我想问@EmployedRussian 为什么相信“大部分是静态的”二进制文件更不便携。为什么相反呢?如果没有“大部分静态”路由,我已经能够生成无法运行的二进制文件......
    • 您现在拥有在任何地方发表评论所需的代表。请明智地使用你新获得的力量。
    【解决方案4】:

    链接时,在指定要静态链接到的库之前使用-static,在要动态链接到的库之前使用-dynamic。你最终应该得到一个如下所示的命令行:

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

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

    【讨论】:

    • 这个答案完全错误:-static 关闭 -dynamic,反之亦然。最后一个获胜。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-23
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多