在我的原生扩展中,我需要将流注入我的Dart控制台应用程序。在概念上非常相似 标准输入。如何创建暴露给控制台应用程序的本机Dart Stream对象?
答案 0 :(得分:2)
我试图为你创建一个示例并将其放在github上。
https://github.com/mezoni/native_extension_with_stream
如果您希望在行动中看到它,您应该编译并运行。
位于bin/makefile.dart
的构建脚本。
位于bin/example_use_sample_extension.dart
的示例脚本。
如果您只想查看源代码示例,可以在下面看到它。
<强> example_use_sample_extension.dart 强>
import "package:lists/lists.dart";
import "package:native_extension_with_stream/sample_extension.dart";
void main() {
print("Range from 0 to 5");
var stream = NativeStream.createStream(new RangeList(0, 5));
stream.listen((data) {
print(data);
}, onDone: () {
print("Collection from -5 to 5 with step 2");
var stream = NativeStream.createStream(new StepList(-5, 5, 2));
stream.listen((data) {
print(data);
});
});
}
<强> sample_extension.dart 强>
library native_extension_with_stream.sample_extension;
import "dart-ext:sample_extension";
import "dart:async";
class NativeStream {
static Stream<int> createStream(Iterable<int> collection) {
if (collection == null) {
throw new ArgumentError("collection: $collection");
}
return _createStream(collection);
}
static Stream<int> _createStream(Iterable<int> collection) native
"CreateStream";
}
<强> sample_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 sample_extension_Init(Dart_Handle parent_library) {
if (Dart_IsError(parent_library)) { return parent_library; }
Dart_Handle result_code = Dart_SetNativeResolver(parent_library, ResolveName, NULL);
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;
}
void CreateStream(Dart_NativeArguments arguments) {
Dart_Handle collection;
Dart_Handle library_async;
Dart_Handle library_core;
Dart_Handle result;
Dart_Handle stream;
Dart_Handle type_int;
Dart_Handle type_stream;
Dart_Handle url_async;
Dart_Handle url_core;
Dart_EnterScope();
collection = Dart_GetNativeArgument(arguments, 0);
url_async = Dart_NewStringFromCString("dart:async");
url_core = Dart_NewStringFromCString("dart:core");
library_async = Dart_LookupLibrary(url_async);
library_core = Dart_LookupLibrary(url_core);
type_int = Dart_GetType(library_core, Dart_NewStringFromCString("int"), 0, NULL);
type_stream = Dart_GetType(library_core, Dart_NewStringFromCString("Stream"), 0, NULL);
stream = Dart_New(type_stream, Dart_NewStringFromCString("fromIterable"), 1, &collection);
Dart_SetReturnValue(arguments, stream);
Dart_ExitScope();
}
struct FunctionLookup {
const char* name;
Dart_NativeFunction function;
};
FunctionLookup function_list[] = {
{"CreateStream", CreateStream},
{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;
}
P.S。
以下是构建脚本的源代码:
<强> makefile.dart 强>
import "dart:io";
import "package:ccompilers/ccompilers.dart";
import "package:build_tools/build_shell.dart";
import "package:build_tools/build_tools.dart";
import "package:file_utils/file_utils.dart";
import "package:patsubst/top_level.dart";
void main(List<String> args) {
const String PROJECT_NAME = "sample_extension";
const String LIBNAME_LINUX = "lib$PROJECT_NAME.so";
const String LIBNAME_MACOS = "lib$PROJECT_NAME.dylib";
const String LIBNAME_WINDOWS = "$PROJECT_NAME.dll";
// Determine operating system
var os = Platform.operatingSystem;
// Setup Dart SDK bitness for extension
var bits = DartSDK.getVmBits();
// Compiler options
var compilerDefine = {};
var compilerInclude = ['$DART_SDK/bin', '$DART_SDK/include'];
// Linker options
var linkerLibpath = <String>[];
// OS dependent parameters
var libname = "";
var objExtension = "";
switch (os) {
case "linux":
libname = LIBNAME_LINUX;
objExtension = ".o";
break;
case "macos":
libname = LIBNAME_MACOS;
objExtension = ".o";
break;
case "windows":
libname = LIBNAME_WINDOWS;
objExtension = ".obj";
break;
default:
print("Unsupported operating system: $os");
exit(-1);
}
// http://dartbug.com/20119
var bug20119 = Platform.script;
// Set working directory
FileUtils.chdir("../lib/src");
// C++ files
var cppFiles = FileUtils.glob("*.cc");
if (os != "windows") {
cppFiles = FileUtils.exclude(cppFiles, "sample_extension_dllmain_win.cc");
}
cppFiles = cppFiles.map((e) => FileUtils.basename(e));
// Object files
var objFiles = patsubst("%.cc", "%${objExtension}").replaceAll(cppFiles);
// Makefile
// Target: default
target("default", ["build"], null, description: "Build and clean.");
// Target: build
target("build", ["clean_all", "compile_link", "clean"], (Target t, Map args) {
print("The ${t.name} successful.");
}, description: "Build '$PROJECT_NAME'.");
// Target: compile_link
target("compile_link", [libname], (Target t, Map args) {
print("The ${t.name} successful.");
}, description: "Compile and link '$PROJECT_NAME'.");
// Target: clean
target("clean", [], (Target t, Map args) {
FileUtils.rm(["*.exp", "*.lib", "*.o", "*.obj"], force: true);
print("The ${t.name} successful.");
}, description: "Deletes all intermediate files.", reusable: true);
// Target: clean_all
target("clean_all", ["clean"], (Target t, Map args) {
FileUtils.rm([libname], force: true);
print("The ${t.name} successful.");
}, description: "Deletes all intermediate and output files.", reusable: true);
// Compile on Posix
rule("%.o", ["%.cc"], (Target t, Map args) {
var args = new CommandLineArguments();
var compiler = new Gpp();
args.add('-c');
args.addAll(['-fPIC', '-Wall']);
args.add('-m32', test: bits == 32);
args.add('-m64', test: bits == 64);
args.addAll(compilerInclude, prefix: '-I');
args.addKeys(compilerDefine, prefix: '-D');
args.addAll(t.sources);
return compiler.run(args.arguments).exitCode;
});
// Compile on Windows
rule("%.obj", ["%.cc"], (Target t, Map args) {
var args = new CommandLineArguments();
var compiler = new Msvc(bits: bits);
args.add('/c');
args.addAll(t.sources);
args.addAll(compilerInclude, prefix: '-I');
args.addKeys(compilerDefine, prefix: '-D');
args.addKey('DART_SHARED_LIB', null, prefix: '-D');
return compiler.run(args.arguments).exitCode;
});
// Link on Linux
file(LIBNAME_LINUX, objFiles, (Target t, Map args) {
var args = new CommandLineArguments();
var linker = new Gcc();
args.addAll(t.sources);
args.add('-m32', test: bits == 32);
args.add('-m64', test: bits == 64);
args.addAll(linkerLibpath, prefix: '-L');
args.add('-shared');
args.addAll(['-o', t.name]);
return linker.run(args.arguments).exitCode;
});
// Link on Macos
file(LIBNAME_MACOS, objFiles, (Target t, Map args) {
var args = new CommandLineArguments();
var linker = new Gcc();
args.addAll(t.sources);
args.add('-m32', test: bits == 32);
args.add('-m64', test: bits == 64);
args.addAll(linkerLibpath, prefix: '-L');
args.addAll(['-dynamiclib', '-undefined', 'dynamic_lookup']);
args.addAll(['-o', t.name]);
return linker.run(args.arguments).exitCode;
});
// Link on Windows
file(LIBNAME_WINDOWS, objFiles, (Target t, Map args) {
var args = new CommandLineArguments();
var linker = new Mslink(bits: bits);
args.add('/DLL');
args.addAll(t.sources);
args.addAll(['dart.lib']);
args.addAll(linkerLibpath, prefix: '/LIBPATH:');
args.add('$DART_SDK/bin', prefix: '/LIBPATH:');
args.add(t.name, prefix: '/OUT:');
return linker.run(args.arguments).exitCode;
});
new BuildShell().run(args).then((exitCode) => exit(exitCode));
}