2

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

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

>>> 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。海合会版本 4.4.6
  • x64 RHEL5 上的 x64 Python 2.6.5。海合会版本 4.1.2
4

1 回答 1

1

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

于 2012-02-05T07:26:13.370 回答