LINUX.ORG.RU

доступ к C struct из питона

 ,


0

1

Хочу получить доступ к сишным структурам из питона. И при этом не хочу мараться с ручным заданием полей структуры коих много. Да и структур не одна. Разбор полётов:

1) ctypes, struct в пролёте т.к. требуют ручной возни

2) cython тоже не умеет

3) раньше рекомендовали swig, но, оказалось, он не парсит структуры и работает на уровне указателей. Заглянуть в данные он не позволяет.

Есть ещё один вариант который подсказали на лоре, это llvm для получения abstract syntax tree (AST) с питоновскими биндингами. Нет ли способа проще, а? Ну или подскажите что-нить легковесное для парсинга C кода, если такое бывает.

★★★★★

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

в дебаг инфе есть структура типов. Если, например, лазить из gdb через питоновские привязки, то всё отлично работает как тебе нужно. Можно отрезать этот функционал и унести его в либу, если очень нужно.

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

пока, похоже, самый удобный способ, спасибо. Жаль нельзя выцепить только одну структуру, он всё конвертирует. Ну да ладно.

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

ааа, ну так подразумевается стандартное выравнивание. В общем, ctypesgen парсит хедеры и, похоже, делает как надо:

Была примерно такая структура:

struct perf_event_attr {
        /*
         * The MSB of the config word signifies if the rest contains cpu
         * specific (raw) counter configuration data, if unset, the next
         * 7 bits are an event type and the rest of the bits are the event
         * identifier.
         */
        __u64                   config;

        __u64                   irq_period;
        __u32                   record_type;
        __u32                   read_format;

        __u64                   disabled       :  1, /* off by default        */
                                inherit        :  1, /* children inherit it   */
                                pinned         :  1, /* must always be on PMU */
                                exclusive      :  1, /* only group on PMU     */
                                exclude_user   :  1, /* don't count user      */
                                exclude_kernel :  1, /* ditto kernel          */
                                exclude_hv     :  1, /* ditto hypervisor      */
                                exclude_idle   :  1, /* don't count when idle */
                                mmap           :  1, /* include mmap data     */
                                munmap         :  1, /* include munmap data   */
                                comm           :  1, /* include comm data     */

                                __reserved_1   : 52;

        __u32                   extra_config_len;
        __u32                   wakeup_events;  /* wakeup every n events */

        __u64                   __reserved_2;
        __u64                   __reserved_3;
};

Стало:

from ctypes import *

# /usr/include/linux/perf_event.h: 169
class struct_perf_event_attr(Structure):
    pass

struct_perf_event_attr._fields_ = [
    ('type', __u32),
    ('size', __u32),
    ('config', __u64),
    ('unnamed_1', union_anon_3),
    ('sample_type', __u64),
    ('read_format', __u64),
    ('disabled', __u64, 1),
    ('inherit', __u64, 1),
    ('pinned', __u64, 1),
    ('exclusive', __u64, 1),
    ('exclude_user', __u64, 1),
    ('exclude_kernel', __u64, 1),
    ('exclude_hv', __u64, 1),
    ('exclude_idle', __u64, 1),
    ('mmap', __u64, 1),
    ('comm', __u64, 1),
    ('freq', __u64, 1),
    ('inherit_stat', __u64, 1),
    ('enable_on_exec', __u64, 1),
    ('task', __u64, 1),
    ('watermark', __u64, 1),
    ('precise_ip', __u64, 2),
    ('mmap_data', __u64, 1),
    ('sample_id_all', __u64, 1),
    ('exclude_host', __u64, 1),
    ('exclude_guest', __u64, 1),
    ('__reserved_1', __u64, 43),
    ('unnamed_2', union_anon_4),
    ('bp_type', __u32),
    ('unnamed_3', union_anon_5),
    ('unnamed_4', union_anon_6),

    ...
]

Т.е. даже битовые поля и union понимает.

true_admin ★★★★★
() автор топика

А чем swig то не угодил? Ну то есть он там толстый слой всякой хрени наворачивает, но читать-писать поля структур можно и даже интроспекцию можно (тока она не через __dict__ а через словарь __swig_-чего-то-там делается).

Для С++ я делал одну приблуду, но она специфическая и требует ручной работы (для каждой структуры надо отдельно в макросе перечислить поля), но для С это не сработает...

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

На сколько я понял swig не парсит структуры вообще. Поэтому из питоновского кода обращаться к полям не получится.

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

python-ctypeslib

Это бомба, умеет выборочные структуры доставать и понимает типы. Я сначала xml стреманулся, но, похоже, работает отлично.

Спасибо.

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

На сколько я понял swig не парсит структуры вообще. Поэтому из питоновского кода обращаться к полям не получится.

О_О. Я наверное тупой, да и пишу тока на С++ (С-ей не знаю), в плюсах то он все парсит, даже мои изощренные шаблоны (если попросить)...

//test-sw.h
struct A{
	int x;
	float y;
	char z;
};
//test_sw.i
%module test_sw
%{
#include "test-sw.h"
%}
%include "test-sw.h"
~/tmp$ swig -python test_sw.i
~/tmp$ gcc -fPIC -shared -I/usr/include/python test_sw_wrap.c
~/tmp$ python
Python 2.6.6 (r266:84292, Dec 26 2010, 22:31:48) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from test_sw import *
>>> a = A()
>>> a.z
'\x00'
>>> a.x = 1
>>> a.x
1
>>> a.y = 3.5
>>> a.y
3.5

ЧЯНТД?;-)

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

SWIG - это ужоснах сравнению с няшным ctypeslib.

А оно для плюсов умеет шаблоны обрабатывать? Перегружать ф-ии по типу аргументов? И скажем есть общий хидер, есть две разных so-шки с этим хидером, оно может в питоне объект из одно so-шки сделанный сунуть в функцию другой so-шки?

Потому что swig все это умеет, и меня как то устраивает... хотя и глючит он местами, особенно с шаблонами и namespace.

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

А оно для плюсов умеет шаблоны обрабатывать?

Нет, насколько я знаю. Но у ТС нет такой задачи - ему нужны Си-структуры.

swig все это умеет, и меня как то устраивает... хотя и глючит он местами, особенно с шаблонами и namespace.

Когда надо месить память, состоящую из Си-структур (да и шаблонных Си++-структур), там всё плохо.

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

Нет, насколько я знаю. Но у ТС нет такой задачи - ему нужны Си-структуры.

Уффф... остаюсь на SWIG-e значит;-)))

Когда надо месить память, состоящую из Си-структур (да и шаблонных Си++-структур), там всё плохо.

А что именно плохо? SWIG умеет в С++ по референсу протаскивать в питон структуры (причем делает это изкоробки). Как он это делает ХЗ, но это работает, и даже слишком - структура по const ref оказывается открытой на запись.

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

А что именно плохо?

Когда пытаешься сделать pythonic-интерфейс, управление памятью превращается в шоу «Typemaps from Hell».

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

Чет я в этой жизни не понимаю... typemap юзал что бы нормально обрабатывались возвращаемые по ссылке базовые типы (что бы шаблон отдельный не делать), а пользовательские структуры шли по ссылке как есть... все прекрасно работает.

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

typemap юзал что бы нормально обрабатывались возвращаемые по ссылке базовые типы

А ты распарси гетерогенный Си-массив с заголовком в pythonic-объект - список, атрибуты с записью.

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

А вот этот мой боян читали же? ;-)

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

Там правда про плюсы, но не думаю что в С-ях что то сильно по другому будет.

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

А ты распарси гетерогенный Си-массив с заголовком в pythonic-объект - список, атрибуты с записью.

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

При таком интерфейсе, все спокойно разбирается SWIG-ом в список из коробки, и на запись оно будет работать.

А вот если скажем каждый элемент надо руками кастить (в С-ях)... дык это изначально содомия;-)

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

А вот если скажем каждый элемент надо руками кастить (в С-ях)... дык это изначально содомия;-)

Вот поэтому сверху делается красивый pythonic-интерфейс.

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

Э... ну тогда либо можно сделать набор ф-й для кастинга в С-ях, можно через макрос какой нить (и SWIG это съест), либо действительно упражняться с typemap... ИМНО первое более Ъ.

Ну или остается ctypeslib (если он это умеет). Но ИМНО это немножко... специфическая задача, и только на основе ее провала хаять SWIG я бы не стал;-)

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

специфическая задача, и только на основе ее провала хаять SWIG я бы не стал;-)

А задача интерфейса с Си-кодом в ctypes решается гораздо проще, чем в SWIG.

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

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

AIv ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.