Bazel - 如何处理外部 .so 库的传递依赖关系?

Posted

技术标签:

【中文标题】Bazel - 如何处理外部 .so 库的传递依赖关系?【英文标题】:Bazel - how to deal with transitive dependencies of external .so libraries? 【发布时间】:2021-02-15 22:57:52 【问题描述】:

我正在尝试使用 Bazel 构建二进制应用程序。这个二进制文件依赖于一个外部的、预编译的库,我们称之为liba.so。反过来,liba.so 依赖于libb.so(我通过readelf -d liba.so | grep NEEDED 获得此信息。

为了构建它,我在 Bazel 中有以下设置:

cc_import(
    name = "liba",
    shared_library = "liba.so",
    deps = [":libb"],
)

cc_import(
    name = "libb",
    shared_library = "libb.so",  
)

cc_binary(
    name = "my_app",
    srcs = ["main.cpp"],
    deps = [":liba"],
)

构建工作正常,但是在运行时(通过bazel run 或直接)ldd 无法找到libb.so

我一直在阅读这方面的内容,原因是 Bazel 仅向二进制文件的 RUNPATH 添加了它的直接依赖项。由于libb.so 是传递依赖,所以二进制找不到它。

为了解决这个问题,我可以想到以下技巧:

添加丑陋的链接器标志以告诉 Bazel 添加到 RPATH 而不是 RUNPATH。然而,这被认为是一个坏主意,因为 RPATH 已被弃用,并且不允许通过 LD_LIBRARY_PATH 覆盖。

修补第三方 .so 文件以添加到他们的RUNPATH。这可行,但修补我不拥有的库感觉不太好。

使传递依赖成为二进制的直接依赖。这不好,每个库都应该对它的依赖负责。二进制文件不需要知道liba.so 依赖什么。

有没有更好的方法来做到这一点?我尝试过的其他事情没有成功:

使用cc_library 而不是cc_import 使用data 而不是deps

谢谢!

【问题讨论】:

您的第三点非常值得商榷:liba 依赖于 libb 的事实可能是由您在 liba 中使用的内容引起的 如果liba 包含函数a(),它又从libb 调用函数b(),我不想在我的应用程序中链接libb。应该只链接直接依赖项 【参考方案1】:

我为这个问题纠结了很长时间。我建议您尝试的第一件事是启用

copy_dynamic_libraries_to_binary

工具链功能。我认为它主要是为 Windows 设计的,但也应该适用于 Linux。

现在,出于我们的目的,我不得不采用更复杂但最终更可靠的方法:我已经实现了每个二进制文件遍历依赖关系图的方面,收集属于二进制输出文件夹的所有内容并生成文件复制操作以在构建二进制文件时将必要的文件放在那里。这包括传递依赖,但足够灵活,可以在输出文件夹中复制我们需要的其他文件 - C++ 运行时、数据文件等。如果您有兴趣,我可以剪辑和分享相关代码 sn-ps。

康斯坦丁

【讨论】:

以上是关于Bazel - 如何处理外部 .so 库的传递依赖关系?的主要内容,如果未能解决你的问题,请参考以下文章

openfire 外部组件如何处理存在和订阅?

使用 WebFlux 的反应式编程如何处理依赖的外部 api 调用

如何处理奇怪组合的 websocket 消息?

带有 Smack 4.1.8 客户端库的 Apache Vysper - 如何处理 TLS 证书?

如何处理 XMPP XEP-0363:客户端使用 SMACK 库的 HTTP 文件上传功能?

browserify 如何处理循环依赖?