Передача объектов между библиотеками в Python CFFI - PullRequest
0 голосов
/ 04 марта 2019

Если я создаю новую структуру с cffi.FFI.new, как я могу передать ее в функцию из другого FFI, который имеет такое же определение структуры?

У меня есть базовая структура C, которой я являюсьиспользование в Python через пакет cffi, который я хочу передать различным функциям, сгенерированным и скомпилированным cffi во время выполнения.Однако я не знаю, как заставить сгенерированные функции использовать одно и то же определение структуры, чтобы я мог передавать объекты между ними.cffi не нравится, когда создается объект с одним FFI и передается в функцию из другого FFI.

Вот упрощенный исполняемый пример определения структуры и создания экземпляра в Python:

from cffi import FFI

common_header = """
typedef struct {
  int32_t a;
  double b;
} my_struct;
"""

# FFI for building objects
ffibuilder = FFI()
ffibuilder.cdef(common_header)

# Build an object in Python
my_object = ffibuilder.new('my_struct*')
my_object.a = 3
my_object.b = 2.0

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

# Builder for functions generated at runtime
def build_library(header: str, source: str):
    from tempfile import TemporaryDirectory

    ffitemp = FFI()

    ffitemp.cdef(common_header + header)

    ffitemp.set_source('_temp', source)

    with TemporaryDirectory() as temp_dir:
        lib_path = ffitemp.compile(tmpdir=temp_dir)

        lib = ffitemp.dlopen(lib_path)

    return lib.func


# Use function
header = """
int func(my_struct *A);
"""

source = """
typedef struct {
  int32_t a;
  double b;
} my_struct;

int func(my_struct *A) {
    return A -> a;
}
"""

func = build_library(header, source)

Когда я пытаюсьПередавая экземпляры моей структуры в функцию, я получаю сообщение об ошибке, говорящее о том, что структура, которую я передаю, не совпадает с типом, принятым функцией.

# Use function
a = func(my_object)
print(a)

TypeError: initializer for ctype 'my_struct *' appears indeed to be 
'my_struct *', the types are different (check that you are not e.g. 
mixing up different ffi instances)

Ошибка довольно ясна, почемуэто несчастноМне не нравится, что я построил my_object с использованием ffibuilder и передал его функции, определенной в другом FFI, который имеет свое собственное определение типа my_struct.

Как мнеполучить компиляцию сгенерированных функций для совместного использования определения структуры с центральной FFI?

1 Ответ

0 голосов
/ 07 марта 2019

Вы можете использовать FFI.include, чтобы включить источник и определения одного FFI экземпляра в другой.Объекты, созданные с включенным FFI, могут передаваться функциям в FFI, в который они были включены.

Обратите внимание, что включенное определение не может быть продублировано в более поздних FFI.Кроме того, FFI может быть включено только в том случае, если на него был вызван set_source.Это верно, даже если вам нужен только заголовок;в этом случае просто установите в качестве источника пустую строку.

Здесь задается пустой источник на главном FFI:

from cffi import FFI

common_header = """
typedef struct {
  int32_t a;
  double b;
} my_struct;
"""

# FFI for building objects
ffibuilder = FFI()
ffibuilder.cdef(common_header)
ffibuilder.set_source('_main', '')  # <-- Set empty source

А здесь включается основной FFIв листе FFI:

# Builder for functions generated at runtime
def build_library(header: str, source: str):
    from tempfile import TemporaryDirectory

    ffitemp = FFI()

    ffitemp.include(ffibuilder)  # <-- include main FFI

    ffitemp.cdef(header)

    ffitemp.set_source('_temp', source)

    with TemporaryDirectory() as temp_dir:
        lib_path = ffitemp.compile(tmpdir=temp_dir)

        lib = ffitemp.dlopen(lib_path)

    return lib.func
...