Могу ли я вызвать функцию конструктора C ++ в dart ffi? - PullRequest
0 голосов
/ 04 мая 2020

Я новичок в ffi. Но я успешно использовал dart-ffi с вызовом функций.

Теперь я хотел бы использовать объект C ++ в dart ffi. Я не знаю, возможно ли это, но я попробовал вот так.

Прототипы вызова конструктора:

function_dart = lib
    .lookup<NativeFunction<function_native>>("constructor_function")
    .asFunction();

Но у меня есть: Failed to lookup symbol <constructor_function>, где я попробовал функцию конструктора с:

constructor_function
class::constructor_function
class::constructor_function(args)

Я сделал nm -gDC <lib>, и я вижу конструктор.

Помогите!

Спасибо

Ответы [ 2 ]

1 голос
/ 04 мая 2020

Dart ffi использует интерфейс C, поэтому вам нужно выполнить следующие действия:

Начать с класса C ++

Rect::Rect(int32_t width, int32_t height) {
  m_width = width;
  m_height = height;
}

void Rect::setWidth(int32_t width) {
  m_width = width;
}

void Rect::setHeight(int32_t height) {
  m_height = height;
}

int32_t Rect::area() {
  return m_width * m_height;
}

создать C заголовок адаптера

EXTERNC void* rect_init(int32_t width, int32_t height);
EXTERNC void rect_destroy(void *ptr);
EXTERNC int32_t rect_area(void *ptr);

и реализация

void* rect_init(int32_t width, int32_t height){
    return new Rect(width, height);
}

void rect_destroy(void *ptr){
    auto typed_ptr = static_cast<Rect*>(ptr);
    delete typed_ptr;
}

int32_t rect_area(void *ptr){
    auto typed_ptr = static_cast<Rect*>(ptr);
    return typed_ptr->area();
}

в Dart, создайте typedefs

typedef example_init_rect = Pointer<Void> Function(Int32 w, Int32 h);
typedef ExampleInitRect = Pointer<Void> Function(int w, int h);

typedef example_free_rect = Void Function(Pointer<Void> p);
typedef ExampleFreeRect = void Function(Pointer<Void> p);

typedef example_area_rect = Int32 Function(Pointer<Void> p);
typedef ExampleAreaRect = int Function(Pointer<Void> p);

и привяжите функции адаптера C. Наконец, вы можете создать класс Dart, который проксирует базовый класс C ++.

class NativeRect {
  Pointer<Void> _nativeInstance;

  NativeRect(int width, int height) {
    _nativeInstance = Example()._exInitRect(width, height);
  }

  void free() {
    Example()._exFreeRect(_nativeInstance);
  }

  int get area => Example()._exAreaRect(_nativeInstance);
}
0 голосов
/ 04 мая 2020

Компиляторы C ++ используют "искажение имен", чтобы гарантировать уникальность имен символов. Тот факт, что вам пришлось добавить опцию -C (или --demangle), чтобы он появился, является подсказкой.

Например, вот искаженный символ для some_class::some_class(int, std::string):

_ZN10some_classC2EiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE

Вам понадобится передать искаженное имя (а не деформированное имя), чтобы вызвать конструктор. Вам также нужно * сопоставить ABI для объекта (у ie есть указатель на память объекта в правильном регистре). Иногда это просто скрытый первый аргумент для конструктора, но не во всех ABI.

Если это вообще возможно, напишите функцию-оболочку C ++, которая создает объект для вас, и пометьте ее с помощью extern "C", чтобы вы не использовали Вам не нужно прыгать через эти обручи.

Например:

extern "C"
some_class* create_some_class(int x, const char * some_text) {
    return new some_class(x, some_text);
}

Теперь вы можете просто вызвать create_some_class из Dart с базовыми типами c, и вы получите указатель обратно к построенному объекту C ++. Если вы намереваетесь обернуть такой большой API, рассмотрите возможность перехода на что-то вроде SWIG, которое может автоматически генерировать эти оболочки.

...