如何链接(或解决)两个定义相同符号的第三方静态库?

Posted

技术标签:

【中文标题】如何链接(或解决)两个定义相同符号的第三方静态库?【英文标题】:How can I link with (or work around) two third-party static libraries that define the same symbols? 【发布时间】:2012-10-23 09:15:45 【问题描述】:

我不可能是唯一一个遇到这种情况的人。

我有一个 C++ 应用程序,它需要与一个第三方和另一个在 SDK 中设置的静态库链接。 SDK 出于某种可怕的令人沮丧的原因,将同一第三方库的子集重新编译到他们自己的(重命名的)库中,尽管符号本身的名称相同并且它们没有封装在命名空间中。我的应用程序本身依赖于同一个第三方库。

我考虑了几个选项,但也许我遗漏了一些东西,希望新的外观能帮助我。也许我很接近,有人会知道其中一个的下一步。我将列举到目前为止我尝试过的方法以及每个解决方案的缺点:

    链接两者。 我收到大约 2500 行符号重新定义/大小更改警告和错误。这是我第一次发现它们定义了相同的符号。我正在尝试使用 g++ 重新编译 OpenSSL 并将其放入命名空间中...请参阅下面的编辑...

    仅与 SDK 链接。 我得到了我自己的代码所依赖的未定义符号 - 这是我发现他们对第三方库的重新编译是一个子集,或者至少配置为禁用了一个模块。

    仅与第三方库链接。 我有几个由 SDK 报告的未定义符号 - 其中一个实际上是第三方库中头文件中的#define,因此第三方库中的所有引用都解析为定义,但外部引用没有。我把它移到了 c 文件中,它解决了这个问题,但是我仍然有两个我在任何地方都找不到的未解决的函数。这是迄今为止我得到的最接近的。

    从一个库中去除冲突符号并在两个库中进行链接。 到目前为止,这还没有奏效。这可能是 SDK 中静态链接的 lib 与我尝试使用的第三方 lib 的版本之间的版本问题,但看起来某些函数在符号之间移动,因此通过删除符号,我无意中删除了我在其他地方需要的功能。 SDK 中符号中的函数与第三方库中符号中的函数之间似乎没有完美的映射。无需手动调整地址,剥离功能是否合理?

我一直在检查库中的符号:

nm -C --defined-only lib<name>.a

然后提取整个对象:

ar -x lib<name>.a <objname>.o

希望这也能帮助那些不得不与相互冲突的第三方库链接的其他人。具体来说,第三方库是OpenSSL,SDK 是Opsec - libcpopenssl.a 是 Opsec 中的违规库。

**EDIT- 一个较晚的解决方法可能是使用 g++ 重新编译 OpenSSL 并将整个内容放在命名空间中,然后链接两个库。我现在正在尝试...更多...

【问题讨论】:

你能把 opsec openssl 派生的排除,而改为链接你的 OpenSSL 吗?听起来他们包含 libcoopenssl.a 以防您没有 OpenSSL 链接。如果符号正确拆分了它们的 OpenSSL 衍生物,它们应该连接起来。 IE。链接他们的 lib-set except 中的所有其他内容,然后链接 OpenSSL。 这就是我在上面#3 中尝试的,基本上。我不得不将#define 移动到 C 文件中并重新编译,然后我仍然有两个未定义的符号。我在任何地方都找不到 SSL_get_peer_dh 或 DH_dup。 您不能使用nm 编写脚本以从good OpenSSL 中获取它们的符号。然后剥离此名称列表的 bad 库。如果它们已静态链接,则内部引用已被解析。如果没有,请使用-r-Ur 链接器。 【参考方案1】:

如果您非常好奇,在最新版本的 OpenSSL 中修改了 249 个文件以使其能够编译。到目前为止,最常见的问题是大量的 C 样式指针强制转换,尤其是 void*。现在我在梦中看到了“reinterpret_cast”。

但这并没有单独解决它 - 它仍然需要完整地放入命名空间中,这意味着再次修改所有文件以及我自己对它的内部引用。我想我现在要传递这个。

感谢大家的帮助。

【讨论】:

【参考方案2】:

Google 搜索表明 SSL_get_peer_dh 和 DH_dup 确实是从 libcpopenssl.a 中添加的,并且它们也不存在于我的 OpenSSL 副本中。所以你真的必须链接那个库。在二进制级别将两个库混合在一起(上面的方法 4)不太可能工作——OpenSSL 对其 ABI 非常挑剔(它们通常将 .so 文件版本化为次要编号) 所以你必须非常幸运地拥有一个与他们的 .a 文件兼容的 .so 。

我的建议是方法 4 的变体,但在源代码级别:您将在 Opsec libcpopenssl.a 中有链接,因为它是 OpenSSL 的修改版本,其中包含额外的符号(可能还有其他修改),并获取您需要来自 OpenSSL 源的额外函数,并使用 libcpopenssl.a 重新编译这些对象,以便它们可以使用 Opsec 版本中的函数。如果你只使用了一些没有被 libcpopenssl.a 导出的 OpenSSL 函数,这是完全可行的。

当然,这仍然是一种繁琐的方法,但它是获得符号兼容性的保证方法,当然前提是 Opsec SDK 没有对 OpenSSL 进行语义更改,这会破坏您引入的其他 OpenSSL 功能项目。

(我是 *** 的新手,所以我不知道这个建议是否可以作为正确的答案,但无论如何我没有发布 cmets 的声誉点。如果不合适,我会删除它。)

【讨论】:

我找不到太多关于这些功能的信息,谢谢!我厌倦了修改 OpenSSL,但这就是我要去的地方,我将尝试为 c++ 编译它并将其放入命名空间。当我有更多信息时,我会更新。

以上是关于如何链接(或解决)两个定义相同符号的第三方静态库?的主要内容,如果未能解决你的问题,请参考以下文章

当 iOS 应用程序链接到静态库时,如何获取丢弃的符号列表?

dll从静态链接库导出函数符号

静态库中的未定义符号链接到动态库

链接器如何使用静态库解析引用

归档时应用程序获取“架构 armv7 的未定义符号”,除非我不剥离库中的链接产品

如何在链接到静态库的 DEV-CPP 中构建控制台应用程序时解决对 _imp__** 的未定义引用?