Dart:如何在本机扩展中创建流

时间:2014-07-24 23:36:52

标签: dart dart-native-extension

在我的原生扩展中,我需要将流注入我的Dart控制台应用程序。在概念上非常相似 标准输入。如何创建暴露给控制台应用程序的本机Dart Stream对象?

1 个答案:

答案 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));
}