Dart で プログラムを書く場合、 Package 不足を感じることがあると思います。
そのような場合、 他言語のPackage を 移植することになると思います。
Dart と 拡張機能については、
Flutter Cordova Dart:io Html5 WASM などなど
意外とパターンが多いので、10回くらいに分けて、紹介していきます。
今回は、Dart:ioでの、拡張方法を見ていきます。
Mac で DartからC言語で書かれた関数を読んでみる。
C言語側の関数を用意する
int calcSum(int x, int y)
{
return x+y;
}
足し算をする関数です。これを、Dartから読んでみます。
単純な関数ですが、この関数を実現できれば、他の関数も同様の方法で、
実現できると思います。
Dart側のインターフェイスを用意する
library libhello;
import 'dart-ext:hello';
int sum(int x, int y) native "sum";
C言語 の関数に対応する Dartのメソッドを用意します。
C言語側でDLLを作成する
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "include/dart_api.h"
#include "include/dart_native_api.h"
int calcSum(int x, int y)
{
return x+y;
}
//
// https://www.dartlang.org/articles/dart-vm/native-extensions
//
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool *auto_setup_scope);
DART_EXPORT Dart_Handle hello_Init(Dart_Handle parent_library)
{
printf(">> called hello_init\n");
if (Dart_IsError(parent_library))
{
printf(">>>> error in parent_library\n");
return parent_library;
}
Dart_Handle result_code = Dart_SetNativeResolver(parent_library, ResolveName, NULL);
if (Dart_IsError(result_code))
{
printf(">>>> error in result code\n");
return result_code;
}
return Dart_Null();
}
void sum(Dart_NativeArguments arguments)
{
printf(">> called sum\n");
Dart_EnterScope();
Dart_Handle arg1 = Dart_GetNativeArgument(arguments, 0);
Dart_Handle arg2 = Dart_GetNativeArgument(arguments, 1);
int64_t x;
int64_t y;
if (Dart_IsError(Dart_IntegerToInt64(arg1, &x)))
{
Dart_ThrowException(Dart_NewStringFromCString("error at x\n"));
}
if (Dart_IsError(Dart_IntegerToInt64(arg2, &y)))
{
Dart_ThrowException(Dart_NewStringFromCString("error at y\n"));
}
printf(">>>> x=%lld y=%lld\n", x, y);
Dart_SetReturnValue(arguments, Dart_NewInteger(calcSum(x,y)));
Dart_ExitScope();
}
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool *auto_setup_scope)
{
printf(">> called resolve name\n");
if (!Dart_IsString(name))
{
return NULL;
}
if (auto_setup_scope == NULL)
{
return NULL;
}
Dart_NativeFunction result = NULL;
Dart_EnterScope();
const char *cname;
Dart_StringToCString(name, &cname);
if (0 == strcmp(cname, "sum"))
{
result = sum;
}
Dart_ExitScope();
return result;
}
と、こんな感じです。
初期化時に、DART_EXPORT Dart_Handle {ライブラリー名}_Init(Dart_Handle parent_library)
が呼ばれる事と、
Dart_NativeFunction ResolveName(Dart_Handle name, int argc, bool *auto_setup_scope)
にて、関数名と実際に動作する関数を結びつける事がわかれば、そんなに難しいコードでもないと思います。
サンプルコードのビルド For Mac
mkdir build
cd build
cmake ..
make .
cd ..
cp ./build/libhello.dylib ./
dart main.dart
として、 CMake を 実行してみてください。
無事、Dart VM から呼び出せる MAC 用の DLL が作成されます。
PS
Flutter に 関しては、 Dart Native Extension は、 サポートされていません。
FFI が 検討されています。
次回
「Windows でビルド」 or 「非同期メソッドについて」 or 「Dart と WASM との 連携」 or 「FFI」 について解説します。