gpt4 book ai didi

Python 扩展(Boost.Python & Py++)和 dlopen 混淆

转载 作者:太空宇宙 更新时间:2023-11-04 06:24:48 24 4
gpt4 key购买 nike

我在 Windows 和 Linux 下用 Py++/Boost.Python 包装一个 C++ 项目。 Windows 中的一切都运行良好,但我对 Linux 中的行为有点困惑。 C++ 项目内置于一个名为 libsimif 的共享库中,但我想将其拆分为 3 个独立的扩展模块。为简单起见,我将只讨论其中的两个,因为第三个的行为是相同的。第一个称为存储,包含数据结构的定义。它不依赖于其他两个扩展模块中定义的任何内容。第二个模块,控制,使用在存储中定义的数据结构。在 C++ 方面,用于存储和控制的头文件和源文件位于完全不同的目录中。我尝试了多种不同的配置来构建扩展,但一直保持一致的是,对于存储,我只为存储目录中包含的 header 生成 Py++ 包装器,并且只在该目录中构建源文件以及Py++ 生成的源代码。控件扩展也是如此。

我正在使用的当前配置可以将 libsimif 作为库传递给 distutils.Extension 构造函数。然后在启动 Python 之前,我需要确保在 LD_LIBRARY_PATH 中找到 libsimif。然后我可以启动 Python 并导入任一模块(或从它们导入),一切都按预期进行。以下是此工作配置的一些示例输出:

>>> import ast.simif.model_io.storage as storage
>>> import ast.simif.model_io.control as control
>>> dir(storage)
['DiscreteStore', 'PulseStore', 'RtStore', 'SerialStore', 'SharedMemoryBuilder', 'SharedMemoryDeleter', 'SpaceWireStore', '__doc__', '__file__', '__name__', '__package__']
>>> dir(control)
['DiscreteController', 'ModelIoController', 'PulseController', 'RtController', 'SerialController', 'SpaceWireController', '__doc__', '__file__', '__name__', '__package__']
>>> storage.__file__
'ast/simif/model_io/storage.so'
>>> control.__file__
'ast/simif/model_io/control.so'

如您所见,这两个模块都有自己的共享库和独特的符号集。现在这就是我感到困惑的原因。在 Linux 中,我们总是将 dlopen 标志设置为包括 RTLD_NOW 和 RTLD_GLOBAL。如果我这样做,就会发生以下情况:

>>> import sys
>>> import DLFCN
>>> sys.setdlopenflags(DLFCN.RTLD_NOW | DLFCN.RTLD_GLOBAL)
>>> import ast.simif.model_io.storage as storage
>>> import ast.simif.model_io.control as control
__main__:1: RuntimeWarning: to-Python converter for DiscreteStore::FrameData already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for PulseStore::FrameData already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for RtStore::Link already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for RtStore::FrameData already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for RtStore::RtData already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for SerialStore::FrameData already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for SharedMemoryBuilder already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for SharedMemoryDeleter already registered; second conversion method ignored.
>>> dir(storage)
['DiscreteStore', 'PulseStore', 'RtStore', 'SerialStore', 'SharedMemoryBuilder', 'SharedMemoryDeleter', 'SpaceWireStore', '__doc__', '__file__', '__name__', '__package__']
>>> dir(control)
['DiscreteStore', 'PulseStore', 'RtStore', 'SerialStore', 'SharedMemoryBuilder', 'SharedMemoryDeleter', '__doc__', '__file__', '__name__', '__package__']
>>> storage.__file__
'ast/simif/model_io/storage.so'
>>> control.__file__
'ast/simif/model_io/control.so'

所以,这里存储导入正常,但控制提示一堆重复注册。然后在检查模块时,控制完全错误。这就像它试图导入存储两次,即使 file 报告了正确的共享库。也许不足为奇,如果我在存储之前更改导入顺序和导入控制,就会发生以下情况:

>>> import sys
>>> import DLFCN
>>> sys.setdlopenflags(DLFCN.RTLD_NOW | DLFCN.RTLD_GLOBAL)
>>> import ast.simif.model_io.control as control
>>> dir(control)
['DiscreteController', 'ModelIoController', 'PulseController', 'RtController', 'SerialController', 'SpaceWireController', '__doc__', '__file__', '__name__', '__package__']
>>> import ast.simif.model_io.storage as storage
__main__:1: RuntimeWarning: to-Python converter for DiscreteController already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for PulseController already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for RtController already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for SerialController already registered; second conversion method ignored.
__main__:1: RuntimeWarning: to-Python converter for SpaceWireController already registered; second conversion method ignored.
>>> dir(storage)
['DiscreteController', 'ModelIoController', 'PulseController', 'RtController', 'SerialController', 'SpaceWireController', 'SpaceWireStore', '__doc__', '__file__', '__name__', '__package__']

类似的行为,但现在存储导入是 FUBAR。有人知道这里发生了什么吗?

我正在使用:

  • x64 RHEL6 上的 x64 Python 2.6.6。 Gcc 版本 4.4.6
  • x64 RHEL5 上的 x64 Python 2.6.5。 Gcc 版本 4.1.2

最佳答案

事实证明,这实际上是由于在 Py++ 中使用 balanced_split_module 时生成 Boost.Python 注册代码的方式的怪癖。 balanced_split_module 基本上将所有注册代码拆分成固定数量的源文件,每个源文件都有自己的注册功能。源文件使用扩展名加上生成的文件号命名(例如 _.cpp,但问题是它们包含的实际函数不包含扩展名,只是简单的 register_1()、register_2() 等.当您只导入单个模块或不使模块的符号全局化时,这就是查找和花花公子。在这种情况下发生的情况是,当您设置 RTLD_GLOBAL 时,第一个模块导入成功,但随后所有后续模块将调用注册函数作为初始模块的一部分加载。

关于Python 扩展(Boost.Python & Py++)和 dlopen 混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9058840/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com