From 60466a5c7ddbf83895f773efe7b3c42def42c9d2 Mon Sep 17 00:00:00 2001 From: ekibun Date: Sun, 13 Sep 2020 22:50:14 +0800 Subject: [PATCH] test ffi --- example/lib/main.dart | 6 +++--- example/pubspec.lock | 7 ++++++ example/test/widget_test.dart | 27 +++++++++++++++++++++++ lib/flutter_qjs.dart | 6 +++--- pubspec.lock | 7 ++++++ pubspec.yaml | 1 + test/flutter_qjs_test.dart | 33 ++++++++++++++++++++++++++++ test/lib/CMakeLists.txt | 19 +++++++++++++++++ test/lib/ffi.cpp | 39 ++++++++++++++++++++++++++++++++++ test/lib/make.cmd | 5 +++++ windows/flutter_qjs_plugin.cpp | 6 ++---- 11 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 example/test/widget_test.dart create mode 100644 test/flutter_qjs_test.dart create mode 100644 test/lib/CMakeLists.txt create mode 100644 test/lib/ffi.cpp create mode 100644 test/lib/make.cmd diff --git a/example/lib/main.dart b/example/lib/main.dart index d11d17c..17c96df 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-08-08 08:16:51 * @LastEditors: ekibun - * @LastEditTime: 2020-08-27 20:39:32 + * @LastEditTime: 2020-09-06 19:44:32 */ import 'package:flutter/material.dart'; import 'dart:typed_data'; @@ -46,13 +46,13 @@ class TestPage extends StatefulWidget { class _TestPageState extends State { String resp; - FlutterJs engine; + FlutterQjs engine; CodeInputController _controller = CodeInputController(); _createEngine() async { if (engine != null) return; - engine = FlutterJs(); + engine = FlutterQjs(); await engine.setMethodHandler((String method, List arg) async { switch (method) { case "http": diff --git a/example/pubspec.lock b/example/pubspec.lock index 8f328fd..a69c242 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -57,6 +57,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0-nullsafety" + ffi: + dependency: transitive + description: + name: ffi + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" flutter: dependency: "direct main" description: flutter diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart new file mode 100644 index 0000000..a335416 --- /dev/null +++ b/example/test/widget_test.dart @@ -0,0 +1,27 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:flutter_qjs_example/main.dart'; + +void main() { + testWidgets('Verify Platform version', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); + + // Verify that platform version is retrieved. + expect( + find.byWidgetPredicate( + (Widget widget) => widget is Text && + widget.data.startsWith('Running on:'), + ), + findsOneWidget, + ); + }); +} diff --git a/lib/flutter_qjs.dart b/lib/flutter_qjs.dart index d7136c9..a43dbc2 100644 --- a/lib/flutter_qjs.dart +++ b/lib/flutter_qjs.dart @@ -3,7 +3,7 @@ * @Author: ekibun * @Date: 2020-08-08 08:29:09 * @LastEditors: ekibun - * @LastEditTime: 2020-08-28 10:45:14 + * @LastEditTime: 2020-09-06 13:03:56 */ import 'dart:async'; import 'dart:io'; @@ -19,9 +19,9 @@ typedef JsModuleHandler = Future Function(String name); class JsMethodHandlerNotImplement {} /// FlutterJs instance. -/// Each [FlutterJs] object creates a new thread that runs a simple js loop. +/// Each [FlutterQjs] object creates a new thread that runs a simple js loop. /// Make sure call `destroy` to terminate thread and release memory when you don't need it. -class FlutterJs { +class FlutterQjs { dynamic _engine; dynamic get pointer => _engine; diff --git a/pubspec.lock b/pubspec.lock index 6111eff..b68689c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -50,6 +50,13 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.1.0-nullsafety" + ffi: + dependency: "direct main" + description: + name: ffi + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" flutter: dependency: "direct main" description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index 4807e0f..c9b01c1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,6 +10,7 @@ environment: dependencies: flutter: sdk: flutter + ffi: 0.1.3 dev_dependencies: flutter_test: diff --git a/test/flutter_qjs_test.dart b/test/flutter_qjs_test.dart new file mode 100644 index 0000000..385a726 --- /dev/null +++ b/test/flutter_qjs_test.dart @@ -0,0 +1,33 @@ +/* + * @Description: + * @Author: ekibun + * @Date: 2020-09-06 13:02:46 + * @LastEditors: ekibun + * @LastEditTime: 2020-09-13 17:29:26 + */ +import 'dart:ffi'; +import 'package:ffi/ffi.dart'; + +void main() { + final DynamicLibrary qjsLib = DynamicLibrary.open("test/lib/build/Debug/ffi_library.dll"); + print(qjsLib); + // JSRuntime *js_NewRuntime(void); + final Pointer Function() jsNewRuntime = + qjsLib.lookup>("jsNewRuntime").asFunction(); + final rt = jsNewRuntime(); + print(rt); + // JSContext *js_NewContext(JSRuntime *rt); + final Pointer Function(Pointer rt) jsNewContext = + qjsLib.lookup>("jsNewContext").asFunction(); + final ctx = jsNewContext(rt); + print(ctx); + // JSValue *js_Eval(JSContext *ctx, const char *input, const char *filename, int eval_flags) + final Pointer Function(Pointer rt, Pointer input, Pointer filename, int evalFlags) jsEval = + qjsLib.lookup,Pointer, Int32)>>("jsEval").asFunction(); + final jsval = jsEval(ctx, Utf8.toUtf8("1+1"), Utf8.toUtf8(""), 0); + // const char *js_ToCString(JSContext *ctx, JSValue *val) + final Pointer Function(Pointer rt, Pointer val) jsToCString = + qjsLib.lookup Function(Pointer,Pointer)>>("jsToCString").asFunction(); + final str = Utf8.fromUtf8(jsToCString(ctx, jsval)); + print(str); +} diff --git a/test/lib/CMakeLists.txt b/test/lib/CMakeLists.txt new file mode 100644 index 0000000..4e2f7b7 --- /dev/null +++ b/test/lib/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.7 FATAL_ERROR) +project(ffi_library LANGUAGES CXX) +add_library(ffi_library SHARED ffi.cpp) + +# quickjs +set(QUICK_JS_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../cxx/quickjs) +file (STRINGS "${QUICK_JS_LIB_DIR}/VERSION" QUICKJS_VERSION) +add_library(libquickjs STATIC + ${QUICK_JS_LIB_DIR}/cutils.c + ${QUICK_JS_LIB_DIR}/libregexp.c + ${QUICK_JS_LIB_DIR}/libunicode.c + ${QUICK_JS_LIB_DIR}/quickjs.c +) + +project(libquickjs LANGUAGES C) +target_compile_options(libquickjs PRIVATE "-DCONFIG_VERSION=\"${QUICKJS_VERSION}\"") +target_compile_options(libquickjs PRIVATE "-DDUMP_LEAKS") + +target_link_libraries(ffi_library PRIVATE libquickjs) diff --git a/test/lib/ffi.cpp b/test/lib/ffi.cpp new file mode 100644 index 0000000..74e8c6b --- /dev/null +++ b/test/lib/ffi.cpp @@ -0,0 +1,39 @@ +/* + * @Description: + * @Author: ekibun + * @Date: 2020-09-06 18:32:45 + * @LastEditors: ekibun + * @LastEditTime: 2020-09-13 17:26:29 + */ +#include "../../cxx/quickjs/quickjs.h" +#include + +#ifdef _MSC_VER +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT __attribute__((visibility("default"))) +#endif + +extern "C" +{ + + DLLEXPORT JSRuntime *jsNewRuntime() + { + return JS_NewRuntime(); + } + + DLLEXPORT JSContext *jsNewContext(JSRuntime *rt) + { + return JS_NewContext(rt); + } + + DLLEXPORT JSValue *jsEval(JSContext *ctx, const char *input, const char *filename, int eval_flags) + { + return new JSValue{JS_Eval(ctx, input, strlen(input), filename, eval_flags)}; + } + + DLLEXPORT const char *jsToCString(JSContext *ctx, JSValue *val) + { + return JS_ToCString(ctx, *val); + } +} \ No newline at end of file diff --git a/test/lib/make.cmd b/test/lib/make.cmd new file mode 100644 index 0000000..094703f --- /dev/null +++ b/test/lib/make.cmd @@ -0,0 +1,5 @@ +cd %~dp0 +set CMAKE="C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" +set BUILD_DIR="./build" +%CMAKE% -S ./ -B %BUILD_DIR% +%CMAKE% --build %BUILD_DIR% --verbose \ No newline at end of file diff --git a/windows/flutter_qjs_plugin.cpp b/windows/flutter_qjs_plugin.cpp index 058775e..5508905 100644 --- a/windows/flutter_qjs_plugin.cpp +++ b/windows/flutter_qjs_plugin.cpp @@ -121,7 +121,7 @@ namespace qjs::Engine *engine = (qjs::Engine *)std::get(ValueOrNull(args, "engine")); std::string script = std::get(ValueOrNull(args, "script")); std::string name = std::get(ValueOrNull(args, "name")); - auto presult = result.release(); + std::shared_ptr> presult = std::move(result); engine->commit(qjs::EngineTask{ [script, name](qjs::Context &ctx) { return ctx.eval(script, name.c_str(), JS_EVAL_TYPE_GLOBAL); @@ -129,11 +129,9 @@ namespace [presult](qjs::Value resolve) { flutter::EncodableValue response = qjs::jsToDart(resolve); presult->Success(&response); - delete presult; }, [presult](qjs::Value reject) { presult->Error("FlutterJSException", qjs::getStackTrack(reject)); - delete presult; }}); } else if (method_call.method_name().compare("call") == 0) @@ -142,7 +140,7 @@ namespace qjs::Engine *engine = (qjs::Engine *)std::get(ValueOrNull(args, "engine")); qjs::JSValue *function = (qjs::JSValue *)std::get(ValueOrNull(args, "function")); flutter::EncodableList arguments = std::get(ValueOrNull(args, "arguments")); - auto presult = result.release(); + std::shared_ptr> presult = std::move(result); engine->commit(qjs::EngineTask{ [function, arguments](qjs::Context &ctx) { size_t argscount = arguments.size();