在链接/编译时静态包含所有库而不是库的一部分

Posted

技术标签:

【中文标题】在链接/编译时静态包含所有库而不是库的一部分【英文标题】:Including all the library statically instead of parts of the library upon linking/compilation 【发布时间】:2020-02-25 16:53:50 【问题描述】:

如果我要将某个库静态链接到我的应用程序,据我所知,链接器可以通过一种方式进行优化,以便在生成最终可执行文件时仅放置库中使用过的部分。如果我想生成包含库的所有部分而不是我实际使用的部分的可执行文件,有没有办法在编译时关闭它,可能使用编译器标志或任何其他特定方法?

【问题讨论】:

为什么?为什么代码膨胀是可取的? @JonathanLeffler 用于一些研究工作,而不是用于生产或其他目的 :) 这不能回答我的问题——为什么代码膨胀是可取的。它可能无害,因为它仅用于研究,但您为什么认为它是可取的?然而,我的问题有一个“修辞问题”的元素——这些不一定能得到答案。 @JonathanLeffler &hogan 我们正在做与嵌入式系统指纹库的可能性相关的工作。我们要确保可执行文件包含与库相关的所有函数,因为我们要将这些反汇编代码指纹识别为没有原始源代码的潜在可执行文件。具有所有功能的可执行文件将使我们的工作更容易匹配二进制文件。我们需要找出是否有一种方法可以在不实际使用它们的情况下链接所有库函数。请不要评判别人。如果你不能回答,请放手。 我“放手”了我之前对你的评论——你正在采取不必要的羞辱。 【参考方案1】:

有一个 GNU 链接器选项 --whole-archive 正是这样做的:

对于命令行中提到的每个存档 --whole-archive 选项,包括存档中的每个目标文件 在链接中,而不是在存档中搜索所需的 目标文件。这通常用于将存档文件转换为 一个共享库,强制每个对象都包含在 生成的共享库。

更多详情请见man ld

当您使用gccclang 链接时,将此选项作为-Wl,--whole-archive 传递给链接器。

【讨论】:

【参考方案2】:

如果您必须使用 GNU 链接器以外的链接器,您可能会发现最好从库中的组件目标文件创建一个可重新链接的目标文件,然后将该(大)目标文件构建到替换库中。它变成了一个全有或全无的命题:如果您需要库中的任何符号,您将得到一切。

oldlib=/some/where/libwhatnot.a
newlib=libwhatnot1.a
bigobj=libwhatnot.o
tmpdir=libwhatnot.relink

mkdir "$tmpdir"
cd "$tmpdir"
ar x "$oldlib"
ld -r -o "../$bigobj" *
rm -f *
cd ..
rmdir "$tmpdir"
ar r "$newlib" "$bigobj"
rm -f "$bigobj"

您可能需要查看如何保留调试信息(可能是ld-g 选项)。

脚本应该处理诸如目录已经存在并且未能将cd 放入其中的问题——如果在刚刚创建的目录之外的目录中执行rm -f * 可能会造成严重的恶作剧。但基本思想——提取、构建单个目标文件、归档——意味着库是全有或全无。

您还必须安排将原始静态存档替换为您的替换文件,方法是更改​​链接中使用的库的名称,或者在链接器命令行中将替换文件放在原始目录之前的目录中,或者通过重命名原件,将替换件移到原位,然后像以前一样继续。我建议保留原件,直到您确信不再需要它为止。

-r 选项自 70 年代后期(至少)第 7 版 Unix 以来就存在于链接器上;它通常可用且通常未使用。

【讨论】:

以上是关于在链接/编译时静态包含所有库而不是库的一部分的主要内容,如果未能解决你的问题,请参考以下文章

如何防止我的makefile由于静态库而重新链接

VS2019 C++动态链接库的创建使用

静态链接库的动态 DLL

linux找动态链接库默认位置,linux动态链接库的加载顺序,编译时找静态库默认位置,找动态库,找静态库

linux找动态链接库默认位置,linux动态链接库的加载顺序,编译时找静态库默认位置,找动态库,找静态库

请教关于linux中静态库与动态库的问题