我可以在 dart ffi 中调用 C++ 构造函数吗?
Can I call a C++ constructor function in dart ffi?
我是 ffi 新手。但是我成功地使用了带有函数调用的dart-ffi。
现在,我想在 dart ffi 中使用 C++ 对象。不知道可不可以,我是这样试的
构造函数调用的原型是:
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>
,我可以看到构造函数。
求助!
编辑 1 : @Botje, @Richard-Heap
我正在尝试使用 OpenCV 中的 VideoCapture 实例。
我已按照 Botje 的回答中的说明进行操作。
所以我创建了一个库,如下所示:
bind.hpp :
#ifndef BIND_HPP
# define BIND_HPP
#include <opencv2/videoio.hpp>
extern "C" {
cv::VideoCapture *cvCreateVideoCapture(char *filename, int apiPreference);
}
#endif
bind.cpp :
#include "bind.hpp"
cv::VideoCapture *createVideoCapture(char *filename, int apiPreference) {
return new cv::VideoCapture(filename, apiPreference);
}
我用来编译的命令:
g++ -c bind.cpp -lopencv -o bind.o
g++ bind.o -shared -o bind.so
我得到:dart: symbol lookup error: ./lib/src/bind.so: undefined symbol: _ZN2cv12VideoCaptureC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi
下一步,是使用 VideoCapture 实例的方法。
谢谢
C++ 编译器使用 "name mangling" 来确保符号名称是唯一的。您必须添加 -C
选项(或 --demangle
)才能显示的事实是一个提示。
例如,这里是 some_class::some_class(int, std::string)
的错位符号:
_ZN10some_classC2EiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
您需要传递经过修饰的名称(而不是经过修饰的名称)才能调用构造函数。您将还 需要匹配对象的 ABI(即在正确的寄存器中有一个指向对象内存的指针)。有时这只是构造函数的隐藏第一个参数,但并非在所有 ABI 中都如此。
如果可能的话,编写一个 C++ 包装函数来为您构造对象并用 extern "C"
标记它,这样您就不必跳过这些环节。
例如:
extern "C"
some_class* create_some_class(int x, const char * some_text) {
return new some_class(x, some_text);
}
您现在可以使用基本类型从 Dart 中简单地调用 create_some_class
,您将得到一个指向构造的 C++ 对象的指针。
如果你打算像这样包装一个大的 API,请考虑迁移到像 SWIG 这样可以自动生成这些包装器的东西。
Dart ffi 使用的是C接口,所以你要适配如下。
从 C++ 开始 class
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 适配器 header
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 中,创建 typedef
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 适配器函数。最后,您可以创建一个代理底层 C++ class.
的 Dart class
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);
}
我是 ffi 新手。但是我成功地使用了带有函数调用的dart-ffi。
现在,我想在 dart ffi 中使用 C++ 对象。不知道可不可以,我是这样试的
构造函数调用的原型是:
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>
,我可以看到构造函数。
求助!
编辑 1 : @Botje, @Richard-Heap
我正在尝试使用 OpenCV 中的 VideoCapture 实例。
我已按照 Botje 的回答中的说明进行操作。
所以我创建了一个库,如下所示:
bind.hpp :
#ifndef BIND_HPP
# define BIND_HPP
#include <opencv2/videoio.hpp>
extern "C" {
cv::VideoCapture *cvCreateVideoCapture(char *filename, int apiPreference);
}
#endif
bind.cpp :
#include "bind.hpp"
cv::VideoCapture *createVideoCapture(char *filename, int apiPreference) {
return new cv::VideoCapture(filename, apiPreference);
}
我用来编译的命令:
g++ -c bind.cpp -lopencv -o bind.o
g++ bind.o -shared -o bind.so
我得到:dart: symbol lookup error: ./lib/src/bind.so: undefined symbol: _ZN2cv12VideoCaptureC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEi
下一步,是使用 VideoCapture 实例的方法。
谢谢
C++ 编译器使用 "name mangling" 来确保符号名称是唯一的。您必须添加 -C
选项(或 --demangle
)才能显示的事实是一个提示。
例如,这里是 some_class::some_class(int, std::string)
的错位符号:
_ZN10some_classC2EiNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE
您需要传递经过修饰的名称(而不是经过修饰的名称)才能调用构造函数。您将还 需要匹配对象的 ABI(即在正确的寄存器中有一个指向对象内存的指针)。有时这只是构造函数的隐藏第一个参数,但并非在所有 ABI 中都如此。
如果可能的话,编写一个 C++ 包装函数来为您构造对象并用 extern "C"
标记它,这样您就不必跳过这些环节。
例如:
extern "C"
some_class* create_some_class(int x, const char * some_text) {
return new some_class(x, some_text);
}
您现在可以使用基本类型从 Dart 中简单地调用 create_some_class
,您将得到一个指向构造的 C++ 对象的指针。
如果你打算像这样包装一个大的 API,请考虑迁移到像 SWIG 这样可以自动生成这些包装器的东西。
Dart ffi 使用的是C接口,所以你要适配如下。
从 C++ 开始 class
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 适配器 header
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 中,创建 typedef
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 适配器函数。最后,您可以创建一个代理底层 C++ class.
的 Dart classclass 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);
}