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

时间:2020-11-03 09:18:24

标签: shared-libraries bazel rpath

我正在尝试使用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

谢谢!

1 个答案:

答案 0 :(得分:0)

我一直在努力解决这个问题。我建议您尝试的第一件事是启用

copy_dynamic_libraries_to_binary

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

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

康斯坦丁