Расширение Python (Boost.Python & Py ++) и путаница - PullRequest
2 голосов
/ 30 января 2012

Я обертываю проект C ++ с Py ++ / Boost.Python под Windows и Linux. Все в Windows работает нормально, но я немного смущен поведением в Linux. Проект C ++ встроен в одну общую библиотеку, которая называется libsimif, но я бы хотел разделить его на 3 отдельных модуля расширения. Для простоты я буду обсуждать только два из них, поскольку поведение третьего идентично. Первое, называемое хранилище, содержит определения структур данных. Он не зависит от чего-либо определенного в двух других модулях расширения. Второй модуль, control, использует структуры данных, которые определены в хранилище. Что касается C ++, то заголовки и исходные файлы для хранения и управления находятся в совершенно разных каталогах. Я пробовал несколько различных конфигураций для создания расширений, но единственное, что осталось неизменным, это то, что для хранилища я генерирую оболочки Py ++ только для заголовков, включенных в каталог хранилища, и только собираю исходные файлы в этом каталоге вместе с Py ++ сгенерированные источники. То же самое для контрольного расширения.

Текущая конфигурация, которую я использую и работает, передается в libsimif в виде библиотеки конструктору distutils.Extension. Затем, перед запуском Python, я должен убедиться, что libsimif находится в LD_LIBRARY_PATH. Затем я могу запустить 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 Python 2.6.6 на x64 RHEL6. Gcc версия 4.4.6
  • x64 Python 2.6.5 на x64 RHEL5. Gcc версия 4.1.2

1 Ответ

1 голос
/ 05 февраля 2012

Оказывается, это было на самом деле из-за странности с тем, как генерируется регистрационный код Boost.Python при использовании balance_split_module в Py ++.balance_split_module в основном разбивает весь регистрационный код на фиксированное количество исходных файлов, каждый со своей собственной функцией регистрации.Исходные файлы именуются с использованием имени расширения и сгенерированного номера файла (например, _.cpp, но суть в том, что фактические функции, которые они содержат, не содержат имя расширения и являются просто простым register_1 (), register_2 () и т. Д.Это найти и найти, когда вы импортируете только один модуль или не делаете символы модуля глобальными. В этом случае происходит то, что когда вы устанавливаете RTLD_GLOBAL, первый модуль успешно импортирует, но затем все последующие модули будут вызывать функции регистрации.которые были загружены как часть исходного модуля.

...