The samples_extension works OK with C library linkage but what about C++ libraries?
I have a class based C++ library I want to use as a native extension, so we have for example:-
class Connect {
open(...);
....
}
in C++ and I want a similar class in Dart.
Looking at dart_api.h and dart_native_api.h its not clear to me how I pass class pointers back and forth from C++ to Dart and how I invoke methods on them and tie this back to the Dart class instance. How does ResolveName work with connection->open() type calls or do we do this completely differently.
A native extension is a combination of: ActionScript classes. Native code. Native code is defined here as code that executes outside the runtime. For example, code that you write in C is native code.
Android applications can contain compiled, native libraries. Native libraries are code that the developer wrote and then compiled for a specific computer architecture. Most often, this means code that is written in C or C++.
Ruby native extensions are libraries written in C using the built-in functions of the RubyVM. Basically, it's C programming with a ton of functions and macros to interact with the virtual machine. Anything that can be achieved by using pure Ruby can also be implemented using the built-in instructions.
Dart is a new web programming language with libraries, a virtual machine, and tools. It's designed to help developers build fast, structured modern web apps. Dart compiles to JavaScript to run across the entire modern web. The VM is a Chrome feature to optimize Dart's performance.
Basic project that can get answers to your questions:
cpp_extension.cc
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#ifdef _WIN32
#include "windows.h"
#else
#include <stdbool.h>
#include <dlfcn.h>
#include <unistd.h>
#include <sys/mman.h>
#endif
#include "dart_api.h"
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool* auto_setup_scope);
DART_EXPORT Dart_Handle cpp_extension_Init(Dart_Handle parent_library) {
if (Dart_IsError(parent_library)) { return parent_library; }
Dart_Handle result_code = Dart_SetNativeResolver(parent_library, ResolveName);
if (Dart_IsError(result_code)) return result_code;
return Dart_Null();
}
Dart_Handle HandleError(Dart_Handle handle) {
if (Dart_IsError(handle)) Dart_PropagateError(handle);
return handle;
}
class Connection {
int* buffer;
bool opened;
public:
Connection() {
opened = false;
buffer = new int[1000000];
memset(buffer, 1, 1000000);
}
void close() {
opened = false;
}
void open(const char* connectionString) {
opened = true;
}
~Connection() {
delete buffer;
}
};
void ConnectionClose(Dart_NativeArguments arguments) {
Connection* connection;
Dart_Handle dh_handle;
Dart_EnterScope();
dh_handle = Dart_GetNativeArgument(arguments, 0);
connection = (Connection*)dh_handle;
connection->close();
Dart_Handle result = Dart_Null();
Dart_SetReturnValue(arguments, result);
Dart_ExitScope();
}
void ConnectionCreate(Dart_NativeArguments arguments) {
Connection* connection;
Dart_Handle result;
Dart_EnterScope();
connection = new Connection();
result = Dart_NewInteger((int64_t)connection);
Dart_SetReturnValue(arguments, result);
Dart_ExitScope();
}
void ConnectionPeerFinalizer(Dart_WeakPersistentHandle handle, void *peer) {
delete (Connection*) peer;
}
void ConnectionPeerRegister(Dart_NativeArguments arguments) {
int64_t peer;
Dart_Handle dh_object;
Dart_Handle dh_peer;
Dart_EnterScope();
dh_object = Dart_GetNativeArgument(arguments, 0);
dh_peer = Dart_GetNativeArgument(arguments, 1);
Dart_IntegerToInt64(dh_peer, &peer);
Dart_NewWeakPersistentHandle(dh_object, (void*)peer, ConnectionPeerFinalizer);
Dart_SetReturnValue(arguments, Dart_Null());
Dart_ExitScope();
}
void ConnectionOpen(Dart_NativeArguments arguments) {
Connection* connection;
const char* connectionString;
Dart_Handle dh_connectionString;
Dart_Handle dh_handle;
Dart_EnterScope();
dh_handle = Dart_GetNativeArgument(arguments, 0);
dh_connectionString = Dart_GetNativeArgument(arguments, 1);
Dart_StringToCString(dh_connectionString, &connectionString);
connection = (Connection*)dh_handle;
connection->open(connectionString);
Dart_Handle result = Dart_Null();
Dart_SetReturnValue(arguments, result);
Dart_ExitScope();
}
struct FunctionLookup {
const char* name;
Dart_NativeFunction function;
};
FunctionLookup function_list[] = {
{"ConnectionClose", ConnectionClose},
{"ConnectionCreate", ConnectionCreate},
{"ConnectionOpen", ConnectionOpen},
{"ConnectionPeerRegister", ConnectionPeerRegister},
{NULL, NULL}};
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool* auto_setup_scope) {
if (!Dart_IsString(name)) return NULL;
Dart_NativeFunction result = NULL;
Dart_EnterScope();
const char* cname;
HandleError(Dart_StringToCString(name, &cname));
for (int i=0; function_list[i].name != NULL; ++i) {
if (strcmp(function_list[i].name, cname) == 0) {
result = function_list[i].function;
break;
}
}
Dart_ExitScope();
return result;
}
cpp_extension.dart
library dart_and_cpp_classes.ext_cpp_extension;
import "dart-ext:cpp_extension";
class Connection {
final String connectionString;
int _handle;
bool _opened = false;
Connection(this.connectionString) {
_handle = _create();
_peerRegister(this, _handle);
}
bool get opened => _opened;
void close() {
_close(_handle);
_opened = false;
}
void open() {
_open(_handle, connectionString);
_opened = true;
}
int _create() native "ConnectionCreate";
void _close(int handle) native "ConnectionClose";
void _open(int handle, String connectionString) native "ConnectionOpen";
void _peerRegister(Object object, int handle) native "ConnectionPeerRegister";
}
use_cpp_extension.dart
import 'package:dart_and_cpp_classes/cpp_extension.dart';
void main() {
var count = 500;
var connections = [];
for(var i = 0; i < count; i++) {
var connection = new Connection("MYSQL");
connection.open();
connection.close();
connections.add(connection);
}
connections = null;
print("Done");
}
Here is basic (ready to use) package on github: https://github.com/mezoni/dart_and_cpp_classes
Other required files in this package.
Run:
P.S.
I am not C++ programmer.
Please, forgive me for any inaccuracies in this language.
OK, a bit of digging and I've sussed this now, I'm doing this in Dart :-
bool open() native 'Connection::open';
and in my resolver looking for the string 'Connection::open' then calling a native function. So, this means my native functions are named 'connectionOpen' and 'messageOpen' etc. so I can resolve these.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With