ホームページ >ウェブフロントエンド >jsチュートリアル >Node.js_node.js を使用して他のプログラムの拡張機能を作成する基本的な方法

Node.js_node.js を使用して他のプログラムの拡張機能を作成する基本的な方法

WBOY
WBOYオリジナル
2016-05-16 15:53:261221ブラウズ

開始する準備ができました

まず、次のディレクトリ構造を使用して、node-notify フォルダーを作成します。

コードをコピー コードは次のとおりです:

.
|-- build/ # ここに拡張機能がビルドされます。
|-- デモ/
| `--demo.js # これは拡張機能をテストするためのデモ Node.js スクリプトです。
|-- src/
| `--node_gtknotify.cpp # これは、C から JavaScript へのマッピングを行う場所です。
`-- wscript # これは、node-waf
によって使用されるビルド構成です。

この美しい外観のツリーは、汎用ツリーを使用して生成されています。

次に、テスト スクリプト demo.js を作成し、拡張機能の API がどのようなものであるべきかを事前に決定しましょう。

// This loads our extension on the notify variable.
// It will only load a constructor function, notify.notification().
var notify = require("../build/default/gtknotify.node"); // path to our extension
 
var notification = new notify.notification();
notification.title = "Notification title";
notification.icon = "emblem-default"; // see /usr/share/icons/gnome/16x16
notification.send("Notification message");

Node.js 拡張機能の作成
初期化メソッド

Node.js 拡張機能を作成するには、node::ObjectWrap を継承する C クラスを作成する必要があります。 ObjectWrap は、JavaScript との対話を容易にするパブリック メソッドを実装しています

まずクラスの基本的なフレームワークを書きましょう:

#include <v8.h> // v8 is the Javascript engine used by QNode
#include <node.h>
// We will need the following libraries for our GTK+ notification
#include <string>
#include <gtkmm.h>
#include <libnotifymm.h>
 
using namespace v8;
 
class Gtknotify : node::ObjectWrap {
 private:
 public:
  Gtknotify() {}
  ~Gtknotify() {}
  static void Init(Handle<Object> target) {
   // This is what Node will call when we load the extension through require(), see boilerplate code below.
  }
};
 
/*
 * WARNING: Boilerplate code ahead.
 *
 * See https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/ & http://www.freebsd.org/cgi/man.cgi&#63;query=dlsym
 * 
 * Thats it for actual interfacing with v8, finally we need to let Node.js know how to dynamically load our code.
 * Because a Node.js extension can be loaded at runtime from a shared object, we need a symbol that the dlsym function can find,
 * so we do the following: 
 */
 
v8::Persistent<FunctionTemplate> Gtknotify::persistent_function_template;
extern "C" { // Cause of name mangling in C++, we use extern C here
 static void init(Handle<Object> target) {
  Gtknotify::Init(target);
 }
 // @see http://github.com/ry/node/blob/v0.2.0/src/node.h#L101
 NODE_MODULE(gtknotify, init);
}

次に、次のコードを Init() メソッドに書き込む必要があります:

コンストラクターを宣言し、ターゲット変数にバインドします。 var n = require("notification"); は notification() を n:n.notification() にバインドします。

// Wrap our C++ New() method so that it's accessible from Javascript
  // This will be called by the new operator in Javascript, for example: new notification();
  v8::Local<FunctionTemplate> local_function_template = v8::FunctionTemplate::New(New);
   
  // Make it persistent and assign it to persistent_function_template which is a static attribute of our class.
  Gtknotify::persistent_function_template = v8::Persistent<FunctionTemplate>::New(local_function_template);
   
  // Each JavaScript object keeps a reference to the C++ object for which it is a wrapper with an internal field.
  Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since a constructor function only references 1 object
  // Set a "class" name for objects created with our constructor
  Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification"));
   
  // Set the "notification" property of our target variable and assign it to our constructor function
  target->Set(String::NewSymbol("notification"), Gtknotify::persistent_function_template->GetFunction());

宣言属性: n.title および n.icon.

  // Set property accessors
  // SetAccessor arguments: Javascript property name, C++ method that will act as the getter, C++ method that will act as the setter
  Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("title"), GetTitle, SetTitle);
  Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("icon"), GetIcon, SetIcon);
  // For instance, n.title = "foo" will now call SetTitle("foo"), n.title will now call GetTitle()

プロトタイプメソッドを宣言します: n.send()

  // This is a Node macro to help bind C++ methods to Javascript methods (see https://github.com/joyent/node/blob/v0.2.0/src/node.h#L34)
  // Arguments: our constructor function, Javascript method name, C++ method name
  NODE_SET_PROTOTYPE_METHOD(Gtknotify::persistent_function_template, "send", Send);

これで、Init() メソッドは次のようになります:

// Our constructor
static v8::Persistent<FunctionTemplate> persistent_function_template;
 
static void Init(Handle<Object> target) {
 v8::HandleScope scope; // used by v8 for garbage collection
 
 // Our constructor
 v8::Local<FunctionTemplate> local_function_template = v8::FunctionTemplate::New(New);
 Gtknotify::persistent_function_template = v8::Persistent<FunctionTemplate>::New(local_function_template);
 Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since this is a constructor function
 Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification"));
 
 // Our getters and setters
 Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("title"), GetTitle, SetTitle);
 Gtknotify::persistent_function_template->InstanceTemplate()->SetAccessor(String::New("icon"), GetIcon, SetIcon);
 
 // Our methods
 NODE_SET_PROTOTYPE_METHOD(Gtknotify::persistent_function_template, "send", Send);
 
 // Binding our constructor function to the target variable
 target->Set(String::NewSymbol("notification"), Gtknotify::persistent_function_template->GetFunction());
}

あとは、Init メソッドで使用する C メソッド (New、GetTitle、SetTitle、GetIcon、SetIcon、Send) を記述するだけです

コンストラクターメソッド: New()

New() メソッドは、カスタム クラス (Gtknotify オブジェクト) の新しいインスタンスを作成し、いくつかの初期値を設定して、そのオブジェクトの JavaScript ハンドラーを返します。これは、new 演算子を使用してコンストラクターを呼び出す JavaScript の予期される動作です。

 
std::string title;
std::string icon;
 
// new notification()
static Handle<Value> New(const Arguments& args) {
 HandleScope scope;
 Gtknotify* gtknotify_instance = new Gtknotify();
 // Set some default values
 gtknotify_instance->title = "Node.js";
 gtknotify_instance->icon = "terminal";
 
 // Wrap our C++ object as a Javascript object
 gtknotify_instance->Wrap(args.This());
 
 return args.This();
}
getters 和 setters: GetTitle(), SetTitle(), GetIcon(), SetIcon()

以下の内容は、主に C と JavaScript (v8) の間で値を変換する定型的なコードです。

// this.title
static v8::Handle<Value> GetTitle(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
 // Extract the C++ request object from the JavaScript wrapper.
 Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder());
 return v8::String::New(gtknotify_instance->title.c_str());
}
// this.title=
static void SetTitle(Local<String> property, Local<Value> value, const AccessorInfo& info) {
 Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder());
 v8::String::Utf8Value v8str(value);
 gtknotify_instance->title = *v8str;
}
// this.icon
static v8::Handle<Value> GetIcon(v8::Local<v8::String> property, const v8::AccessorInfo& info) {
 // Extract the C++ request object from the JavaScript wrapper.
 Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder());
 return v8::String::New(gtknotify_instance->icon.c_str());
}
// this.icon=
static void SetIcon(Local<String> property, Local<Value> value, const AccessorInfo& info) {
 Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder());
 v8::String::Utf8Value v8str(value);
 gtknotify_instance->icon = *v8str;
}

プロトタイプメソッド: Send()

まず、C オブジェクトの this 参照を抽出し、次にオブジェクトのプロパティを使用して通知を構築し、表示します。

// this.send()
static v8::Handle<Value> Send(const Arguments& args) {
 v8::HandleScope scope;
 // Extract C++ object reference from "this"
 Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(args.This());
 
 // Convert first argument to V8 String
 v8::String::Utf8Value v8str(args[0]);
 
 // For more info on the Notify library: http://library.gnome.org/devel/libnotify/0.7/NotifyNotification.html
 Notify::init("Basic");
 // Arguments: title, content, icon
 Notify::Notification n(gtknotify_instance->title.c_str(), *v8str, gtknotify_instance->icon.c_str()); // *v8str points to the C string it wraps
 // Display the notification
 n.show();
 // Return value
 return v8::Boolean::New(true);
}

拡張機能をコンパイルします

node-waf は、waf の基本パッケージである Node 拡張機能をコンパイルするために使用されるビルド ツールです。ビルド プロセスは、wscript と呼ばれるファイルを通じて構成できます。

def set_options(opt):
 opt.tool_options("compiler_cxx")
 
def configure(conf):
 conf.check_tool("compiler_cxx")
 conf.check_tool("node_addon")
 # This will tell the compiler to link our extension with the gtkmm and libnotifymm libraries.
 conf.check_cfg(package='gtkmm-2.4', args='--cflags --libs', uselib_store='LIBGTKMM')
 conf.check_cfg(package='libnotifymm-1.0', args='--cflags --libs', uselib_store='LIBNOTIFYMM')
 
def build(bld):
 obj = bld.new_task_gen("cxx", "shlib", "node_addon")
 obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
 # This is the name of our extension.
 obj.target = "gtknotify"
 obj.source = "src/node_gtknotify.cpp"
 obj.uselib = ['LIBGTKMM', 'LIBNOTIFYMM']

ビルドを開始する準備ができたので、最上位ディレクトリで次のコマンドを実行します。


ノード WAF の構成 && ノード WAF のビルド

すべてがうまくいけば、./build/default/gtknotify.node にあるコンパイルされた拡張機能を取得します。試してみましょう:

$ node
> var notif = require('./build/default/gtknotify.node');
> n = new notif.notification();
{ icon: 'terminal', title: 'Node.js' }
> n.send("Hello World!");
true

上記のコードは、画面の右上隅に通知メッセージを表示します。

npm パッケージにパッケージ化されます

これは非常に素晴らしいことですが、取り組みの結果を Node コミュニティとどのように共有しますか? これが npm の主な目的であり、拡張と配布を容易にすることです。

npm を使用して拡張機能をパッケージ化するのは非常に簡単です。拡張機能の情報を含むファイル package.json を最上位のディレクトリに作成するだけです。

{
 // 扩展的名称 (不要在名称中包含node 或者 js, 这是隐式关键字).
 // 这是通过require() 导入扩展的名称.
 
 "name" : "notify",
 
 // Version should be http://semver.org/ compliant
 
 "version" : "v0.1.0"
 
 // 这些脚本将在调用npm安装和npm卸载的时候运行.
 
 , "scripts" : {
   "preinstall" : "node-waf configure && node-waf build"
   , "preuninstall" : "rm -rf build/*"
  }
 
 // 这是构建我们扩展的相对路径.
 
 , "main" : "build/default/gtknotify.node"
 
 // 以下是可选字段:
 
 , "description" : "Description of the extension...."
 , "homepage" : "https://github.com/olalonde/node-notify"
 , "author" : {
   "name" : "Olivier Lalonde"
   , "email" : "olalonde@gmail.com"
   , "url" : "http://www.syskall.com/"
  }
 , "repository" : {
   "type" : "git"
   , "url" : "https://github.com/olalonde/node-notify.git"
  }
}
package.json 形式の詳細については、npm help json からドキュメントを入手できます。ほとんどのフィールドはオプションであることに注意してください。

これで、最上位ディレクトリで npm install を実行して、新しい npm パッケージをインストールできるようになります。すべてがうまくいけば、拡張機能 var Notice = require('your package name'); をロードできるはずです。 npm link。このコマンドを使用すると、開発ディレクトリへのリンクを作成できるため、コードを変更するたびにインストール/アンインストールする必要がなくなります。
クールな拡張機能を作成し、中央の npm リポジトリでオンラインで公開するとします。まず、アカウントを作成する必要があります。


下一步, 回到你的根目录编码并且运行:

 
$ npm publish

就是这样, 你的包现在已经可以被任何人通过npm install 你的包名命令来安装了.

 

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。