如何使用 Bazel 使用包含单例变量的公共共享库创建“py_extension”?

How to create `py_extension`s with common shared libraries containing singleton variables using Bazel?

提问人:ingomueller.net 提问时间:11/16/2023 最后编辑:ingomueller.net 更新时间:11/20/2023 访问量:32

问:

我正在尝试使用 Bazel 创建两个原生 Python 模块,它们共享大量现有库(LLVM 和 MLIR)——包括跨两个扩展的单例变量。在一个简单的例子中,共享两个库将如下所示:

pyext1.so ---.
              >---> somelib ---> somefile.cpp (static int somevariable)
pyext2.so ---`

我用于两个扩展和.如果我理解正确的话,被编译成一个目标文件,该文件转发到任何依赖于它的目标,所以这两个扩展最终都包含该目标文件。我可以验证事实确实如此:它们都包含标有(对于 BSS 数据部分)的相应符号。py_extensioncc_librarysomelibsomefile.cppcc_librarynmB

这样做的问题是,由于 Python 似乎链接了它的原生库,因此这两个扩展看不到另一个扩展的符号,因此有两个 .由于它们应该是单例,因此代码会中断。somevariable

我发现生成一个包含通用代码的共享库可以(部分)解决问题:cc_binary

pyext1.so ---.
              >---> somelib.so ---> somelib ---> somefile.cpp (static int somevariable)
pyext2.so ---`

现在,Python 仍然链接这两个扩展,而不会使它们的符号彼此可见,但变量存在于 中,其加载方式使其符号对双方都可见。如愿以偿,现在只有一个实例,我的代码可以工作。somelib.sosomevariable

我的问题是:如何将此模式应用于我可能无法更改的大量库?更准确地说:如何创建一个共享库,其中包含其依赖项的所有符号,而该库的使用者包含它们?

在上面的简单示例中,我的文件大致如下所示:BUILD

cc_binary(
    name = "somelib.so",
    linkshared = 1,
    deps = [":somelib"],
)

cc_library(
    name = "somelib",
    src = ["somefile.cpp", "somefile.hpp"],
    deps = [
      # ...
    ],
    alwayslink = 1,
)

这里很重要:它确保所有符号最终都出现在库中,即使它们没有在库本身中使用。但是,这不会影响 中的符号。我怎样才能做到这一点?alwayslinksomefile.cppsomelib.sodeps

请注意,我不能简单地把我所依赖的所有目标都放在一起。它们不仅来自我可能无法更改的大型外部项目,而且更重要的是,这还不够:使用上述模式,消费者需要依赖 ,但也需要依赖 。如果它们依赖于这些符号,并且这些符号被标记为这些符号,那么这些库中的符号最终也会出现在消费者中alwayslinksomelib.sosomefile.hppdepsdepsalwayslink

我认为我需要的是一种仅获取 的消费者的标头和/或仅获取 of 的对象文件的方法,以便我可以将它们包装到另一个文件中,并仅用 .我该如何实现?(一种方法是像这里一样手动完成),但是 (1) 我至少有数百个甚至数千个依赖目标,并且 (2) 可能无法更改下游项目。somelib.sodepssomelibcc_libraryalwayslink

更新:另一个非解决方案是使用(这是实验性的)。该规则确保每个对象文件只被编译到一个共享库中,并且仍然向消费者提供所有头文件,这听起来很有希望。但是,它不能被 、 或 使用,它们抱怨它创建的目标。cc_shared_librarycc_librarycc_binarypy_extensiondoes not have mandatory providers: 'CcInfo'

Python C++ 链接器 Bazel

评论


答: 暂无答案