Я пытаюсь написать пакет-оболочку для кода C++, который выполняет анализ данных в нашем приложении. Я нашел этот отличный пост, который показывает основные шаги, необходимые для этого. Я больше кодер C/C++, поэтому я немного застрял и не понимаю, что я делаю неправильно?
Это анализы.hpp
#include <memory>
#include <vector>
struct int_array
{
int* array;
int len;
};
class cpp_analyses
{
public:
cpp_analyses();
~cpp_analyses() = default;
int_array get_header_index(int_array idx_list_input);
};
Соответствующий анализ.cpp
#include "analyses.hpp"
cpp_analyses::cpp_analyses()
{
}
int_array cpp_analyses::get_header_index(int_array idx_list_input)
{
int_array out;
out.array = new int[2];
out.len = 2;
out.array[0] = 1;
out.array[1] = 2;
return out;
}
Это анализ-адаптер.hpp
#include "analyses.hpp"
#define EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used))
EXPORT void* initialize_analyses();
EXPORT int_array analyses_get_index(void *ptr, struct int_array in_idx);
Соответствующий исходный файл analysis_adapter.cpp
#include "analyses-adapter.hpp"
void* initialize_analyses()
{
return new cpp_analyses;
}
int_array analyses_get_index(void *ptr, struct int_array in_idx)
{
auto typed_ptr = static_cast<cpp_analyses*>(ptr);
return typed_ptr->get_header_index(in_idx);
}
Со стороны дротика:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class IntArray extends Struct {
external Pointer<Int32> data;
@Int32()
external int length;
}
typedef _example_init_analyses = Pointer<Void> Function();
typedef _analyses_get_saccades_index = IntArray Function(Pointer<Void> obj, IntArray input);
class Analyses {
static late DynamicLibrary nativeApiLib;
external Pointer<Void> _nativeInstance;
external _analyses_index analyses_index;
Analyses() {
nativeApiLib =(DynamicLibrary.open('libanalyses.so')); // android and linux
_example_init_analyses _initialize_analyses = nativeApiLib.lookup<NativeFunction<_example_init_analyses>>('initialize_analyses').asFunction();
_nativeInstance = _initialize_analyses();
analyses_index = nativeApiLib.lookup<NativeFunction<_analyses_index>>('analyses_get_index').asFunction();
}
IntArray get_saccades_index(IntArray input)
{
return analyses_index(_nativeInstance, input);
}
}
Наконец в main.dart
import 'package:flutter/material.dart';
import 'package:analyses/analyses.dart';
void main() {
Analyses OBJ = new Analyses();
IntArray TMP = IntArray();
TMP.length = 2;
IntArray TMP_second = OBJ.get_index(TMP);
}
Весь код строится без проблем. Однако, когда я пытаюсь запустить код, он жалуется на то, что
#0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:222:5)
#1 Analyses._nativeInstance= (package:analyses/ncapp_analyses.dart)
Я не вижу, где я делаю что-то не так. Любая помощь будет принята с благодарностью! Спасибо
РЕДАКТИРОВАТЬ В соответствии с запросом, пожалуйста, посмотрите полную трассировку стека
Tried calling: _nativeInstance=
#0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:222:5)
#1 Analyses._nativeInstance= (package:analyses/analyses.dart)
#2 new Analyses (package:analyses/analyses.dart:22:17)
#3 main (package:analyses/main.dart:5:33)
#4 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:130:25)
#5 _rootRun (dart:async/zone.dart:1426:13)
#6 _CustomZone.run (dart:async/zone.dart:1328:19)
#7 _runZoned (dart:async/zone.dart:1861:10)
#8 runZonedGuarded (dart:async/zone.dart:1849:12)
#9 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:126:5)
#10 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#11 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
Если я уберу внешний перед Указатель _nativeInstance;, я не смогу скомпилировать:
ERROR: lib/ncapp_analyses.dart:16:23: Error: Field '_nativeInstance' should be initialized because its type 'Pointer<Void>' doesn't allow null.
ERROR: - 'Pointer' is from 'dart:ffi'.
ERROR: - 'Void' is from 'dart:ffi'.
ERROR: Pointer<Void> _nativeInstance;
ERROR: ^^^^^^^^^^^^^^^
@RichardHeap -> Я обновил вопрос. Извините за отсутствие информации.
Почему вы добавляете ключевое слово external в нескольких местах? Кроме того, ознакомьтесь с новым методом lookupFunction, который может улучшить читабельность.
Например, если я не поставлю «внешний» перед Pointer<Void> _nativeInstance;, код не скомпилируется, потому что _nativeInstance должен быть инициализирован и не может быть нулевым. Я поищу lookupFunction
Сделай это late.
Это работает! Большой!! Большое тебе спасибо. Пожалуйста, запишите свой ответ, чтобы я мог подтвердить правильность вашего решения.





Во-первых, вам нужно отделить класс Dart, представляющий общий объект, от класса Dart, который представляет ваш класс C++.
Первый будет содержать ссылку на разделяемую библиотеку и искомые функции; второй будет просто содержать Pointer<Void> для экземпляра вашего класса C++ - будет по одному экземпляру (и это будет то, что вы освобождаете, когда закончите с этим конкретным экземпляром класса C++).
Например:
import 'dart:ffi';
class SoLibrary {
factory SoLibrary() {
// make it a singleton
_instance ??= SoLibrary._();
return _instance!;
}
SoLibrary._() {
// todo - check for Platform type
_nativeApiLib = DynamicLibrary.open('libanalyses.so');
}
static SoLibrary? _instance;
late DynamicLibrary _nativeApiLib;
late final Pointer<Void> Function() _newAnalyses = _nativeApiLib
.lookupFunction<Pointer<Void> Function(), Pointer<Void> Function()>(
'initialize_analyses');
}
class Analyses {
Pointer<Void> _nativeInstance;
Analyses() : _nativeInstance = SoLibrary()._newAnalyses();
}
Спасибо за отличный ответ. Это явно намного читабельнее! И это работает :)
Можете ли вы включить больше трассировки стека? Какая линия бросает?