LINUX.ORG.RU

python extension module: как правильно преобразовать стуктуру Си в класс Python'а ?

 ,


2

2

Доброго времени суток

Есть сторонняя сишная библиотека, которую кровь из носу нужно использовать из python

К сожалению, сразу уровень «хардкор»:

  • функции получения информации хотят на входе указатель на структуру. Т.е. выделить память нужного размера требуется до вызова
  • поля структуры разные и интересные, включая unsigned long long

есть полный магии swig, который может автоматом сгенерить wrapper и модуль. с некоторыми недостатками

  • поля типа unsigned long long возвращает в питон в виде <Swig Object of type 'u_longlong_t *' at 0xa00000000127990>, который ни во что не удаётся перевести ( int(result.field), ctypes.c_ulonglong(result.field) при нескольких вызовах подряд дают разный результат ). Ок, правлю созданный сишный wrapper, чтобы он правильно приводил тип и возвращал resultobj = SWIG_From_int((unsigned long long)(result));
  • функции swig обернул как есть, т.е. в function1(pointer,size) всё ещё нужно указывать размер области памяти. причём размер сишной структуры я из python не знаю как получить. ок, правлю созданный wrapper, чтобы он самостоятельно подставлял правильный size, игнорируя переданный параметр

этим в принципе можно пользоваться после ручных правок

Но чисто для общего развития, а можно ли вручную создать такой extension без использования swig? Т.е. чтобы на стороне питона операции шли исключительно с объектами? Когда память под структуру инициализируется в конструкторе питоньего объекта, а фукнции можно передать объект, и она корректно возьмёт из его внутренностей структуру?

чтение официальной доки идёт через кровь и слёзы (дано забыл си), но пока я в упор не вижу там похожих примеров, всё на уровне helloworld

★★★★★

Конечно, можно без swig. Только, возможно, придется познакомиться с особенностями работы потоничьего GC, который, внезапно, основан на подсчете ссылок. Нет, это не каламбур. Это констатация факта. По своему это даже удобно для написания расширений к питону на системных языках типа С и Rust (через обертку на C). Настоящий GC, но с подсчетом ссылок.

Если вам не нужен GC, то написание расширения не так уж и сложно. Документация та самая.

dave ★★★★★ ()

Но чисто для общего развития, а можно ли вручную создать такой extension без использования swig?

Это самый верный путь. Главное помнить, что это С, и что важно не налажать со счетчиками ссылок в питоновских объектах.

но пока я в упор не вижу там похожих примеров, всё на уровне helloworld

https://docs.python.org/3/extending/newtypes_tutorial.html

Serral ()

http://a-iv.ru/pyart/cpp2py.pdf

функции получения информации хотят на входе указатель на структуру. Т.е. выделить память нужного размера требуется до вызова

Не распарсил, можно пример?

Насчёт лонга гляну, сам как то обычно интами обходился

AntonI ()
Последнее исправление: AntonI (всего исправлений: 1)

У меня под SWIG 3.08 типы полей структуры size_t и unsigned long long работают из коробки (кастуются к питоновскому long).

Но чисто для общего развития, а можно ли вручную создать такой extension без использования swig?

Можно, но это гемор. Хотя кроме SWIG есть еще какие то системы биндинга, я их не помню. SWIG хорош когда нужно малой кровью забиндить много сишного кода, или когда сишный код меняется а че то в прокладке адаптировать руками лень. Если кода мало и есть много каких то экзотических ситуаций - да, возможно вместо SWIG лучше взять что то другое. Но я пока не уверен что это Ваш случай…

Т.е. чтобы на стороне питона операции шли исключительно с объектами? Когда память под структуру инициализируется в конструкторе питоньего объекта, а фукнции можно передать объект, и она корректно возьмёт из его внутренностей структуру?

Есть две крайности - можно как Вы написали собрать в питоне объект (питоний) и отдать его сишной функции, которая через PyAPI его разберет. Это потребует много букв, PyAPI очень многословен, кроме того может потечь память (как @Serral и @dave выше писали).

Можно на стороне питона через struct упаковать данные в строку отвечающую сишной структуре (если знаете как она устроена) и отдать сишной функции которая просто возьмет содержимое строки и кастанет указатель на него к нужному типу. Букв меньше, но нужно знать как все уложено в структуре.

AntonI ()
Последнее исправление: AntonI (всего исправлений: 2)

можно ли вручную создать такой extension без использования swig?

Конечно можно. Я вообще не знаю swig, но extension для python делать могу, там легко всё, используй cython.

fsb4000 ★★★ ()
Ответ на: комментарий от AntonI

@dave, @Serral, @AntonI, @Sahas, @fsb4000

спасибо, буду пробовать

да, на утечки памяти мне придётся обращать внимание, т.к. пишу агент мониторинга, который будет работать постоянно

перенести структуру на уровень питона видимо не выход, т.к. мне придётся вручную поддерживать разные версии структур для разных версий ОС

параллельно буду читать документацию к swig, вдруг удастся объяснить ему ,что именно мне нужно поменять при автоматической генерации

router ★★★★★ ()
Ответ на: комментарий от AntonI

У меня под SWIG 3.08 типы полей структуры size_t и unsigned long long работают из коробки (кастуются к питоновскому long).

Странно. возможно дело в оси ( aix ) или endianes. пробовал swig 3.0.11 и вручную собранный последний 4.0.1, без разницы. python 3.7.0

попробую пересобрать через gcc вместо ibm xlc, вдруг что изменится

router ★★★★★ ()
Ответ на: комментарий от router

Э… От оси это вроде не должно зависеть, это чисто проблемы внутрисвигового парсинга. Вот всякие uintXX_t он сходу не ест.

Если Вы выложите (или кинете мне как то) структуру которую биндите я у себя попробую.

ЗЫ ещё финт ушами - свиг можно запускать на другой машине под другой осью, а уже его выхлоп копировать куда надо и там собирать. Правда надо убедиться что при запуске свига всякие дефайны правильно стоят (как на целевой машине). В общем это кросс-свигизация, я так делаю когда на целевой машине свига вообще нет.

Ну гляньте пдф которую я выше выкладывал, она в смысле обзора возможностей того как заставить свиг работать в чем то лучше чем доки (короче), хотя и десятилетней давности.

AntonI ()
Последнее исправление: AntonI (всего исправлений: 1)
Ответ на: комментарий от AntonI

Блиин, я идиот. Был невнимателен, в хедере библиотеки так и написано «u_longlong_t»

Огромное спасибо за pdf, сразу нашлось решение - просто добавить typedef в конфиг для swig

typedef unsigned long long u_longlong_t;
router ★★★★★ ()
Ответ на: комментарий от router

u_longlong_t

Ух какие затейники эти разработчики:-)

Для враппинга стандартных вещей (которые не работают из коробки) в свиг в .и-файл нужно подключать всякие string.i, stdint.i и пр.

Ну и есть очень мощный механизм typemap-ов, я к сожалению в нем слабо разбираюсь.

А вот в память сишного объекта напрямую из питона лажу и свиговую систему типов хакал. Если что то не заводится с типами можно для начала глазами глянуть TYPES TABLE во _wrap.cxx

В общем если что зовите:-) Удачи!

AntonI ()