Node.js のモジュールをC++で書く際のメモ(1)
Node.jsのモジュールをC++で書く際に調べたことをメモ。
ソース
とりあえず練習で書いてみた。
#include <v8.h> #include <node.h> #include <iostream> using namespace v8; class Hello: node::ObjectWrap { public: static void Init(const Handle<Object> target) { HandleScope scope; Local < FunctionTemplate > t = FunctionTemplate::New(New); t->InstanceTemplate()->SetInternalFieldCount(1); NODE_SET_PROTOTYPE_METHOD(t, "say", Say); target->Set(String::New("Hello"), t->GetFunction()); } private: Hello() { } void Say(const char *str) { std::cout << "Hello " << str << "\n"; } static Handle<Value> New(const Arguments& args) { HandleScope scope; if (!args.IsConstructCall()) return args.Callee()->NewInstance(); try { (new Hello())->Wrap(args.This()); } catch (const char *msg) { return ThrowException(Exception::Error(String::New(msg))); } return args.This(); } static Handle<Value> Say(const Arguments& args) { HandleScope scope; Unwrap<Hello> (args.This())->Say(*String::Utf8Value(args[0])); return Undefined(); } }; extern "C" void init(Handle<Object> target) { Hello::Init(target); }
ポイント
- Node.js のモジュールは必ず以下のシグネチャをもつinit関数を備えなければならない
extern 'C' void init (Handle<Object> target)
- node::ObjectWrapを継承
- (new Hello())->Wrap(args.This());でC++オブジェクトをJavaScriptオブジェクトでラップ
- メソッドを呼ぶ際は、 Unwrap
(args.This())->Say(*String::Utf8Value(args[0]));のようにする
- JavaScriptから呼ぶメソッドのシグネチャは以下
static v8::Handle<v8::Value> Foo(const v8::Arguments& args);
- v8::HandleScopeはV8のガベージコレクション制御のためのクラス
- 関数テンプレートにコンストラクタ、メソッドを登録。
//コンストラクタはHello::New Local < FunctionTemplate > t = FunctionTemplate::New(Hello::New); //フィールドの数を指定今回は1 t->InstanceTemplate()->SetInternalFieldCount(1); //Hello::SayがJavaScriptのsayメソッドで呼び出されるように設定 NODE_SET_PROTOTYPE_METHOD(t, "say", Hello::Say); //JavScript オブジェクトにシンボル"Hello"を設定。これがJavaScriptオブジェクトのプロトタイプになる。 target->Set(String::New("Hello"), t->GetFunction());
ビルド
ビルドにはNode.jsに付属するnode-wafを使用する。
まずは、wscriptを作成する。以下のファイルをソースと同じディレクトリにwscriptとして作成する。
srcdir = '.' blddir = 'build' VERSION = '0.0.1' def set_options(opt): opt.tool_options('compiler_cxx') def configure(conf): conf.check_tool('compiler_cxx') conf.check_tool('node_addon') def build(bld): obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') obj.target = 'hello' obj.source = 'hello.cc'
そして、 ビルドを行う。
$ node-waf configure && node-waf
ビルドが成功すれば ./build/default/hello.nodeが作成されているはず。
動作確認
以下のスクリプトで動作を確認。
var Hello = require('./build/default/hello').Hello; var hello = new Hello(); hello.say('World');
実行。
$ node hello.js Hello World
とりあえず、今日はここまで。