# Addons Addons are dynamically linked shared objects. They can provide glue to C and C++ libraries. The API (at the moment) is rather complex, involving knowledge of several libraries: - V8 JavaScript, a C++ library. Used for interfacing with JavaScript: creating objects, calling functions, etc. Documented mostly in the `v8.h` header file (`deps/v8/include/v8.h` in the Node source tree), which is also available [online](http://izs.me/v8-docs/main.html). - [libuv](https://github.com/joyent/libuv), C event loop library. Anytime one needs to wait for a file descriptor to become readable, wait for a timer, or wait for a signal to received one will need to interface with libuv. That is, if you perform any I/O, libuv will need to be used. - Internal Node libraries. Most importantly is the `node::ObjectWrap` class which you will likely want to derive from. - Others. Look in `deps/` for what else is available. Node statically compiles all its dependencies into the executable. When compiling your module, you don't need to worry about linking to any of these libraries. ## Hello world To get started let's make a small Addon which is the C++ equivalent of the following JavaScript code: exports.hello = function() { return 'world'; }; First we create a file `hello.cc`: #include #include using namespace v8; Handle Method(const Arguments& args) { HandleScope scope; return scope.Close(String::New("world")); } void init(Handle target) { target->Set(String::NewSymbol("hello"), FunctionTemplate::New(Method)->GetFunction()); } NODE_MODULE(hello, init) Note that all Node addons must export an initialization function: void Initialize (Handle target); NODE_MODULE(module_name, Initialize) There is no semi-colon after `NODE_MODULE` as it's not a function (see `node.h`). The `module_name` needs to match the filename of the final binary (minus the .node suffix). The source code needs to be built into `hello.node`, the binary Addon. To do this we create a file called `binding.gyp` which describes the configuration to build your module in a JSON-like format. This file gets compiled by [node-gyp](https://github.com/TooTallNate/node-gyp). { "targets": [ { "target_name": "hello", "sources": [ "hello.cc" ] } ] } The next step is to generate the appropriate project build files for the current platform. Use `node-gyp configure` for that. Now you will have either a `Makefile` (on Unix platforms) or a `vcxproj` file (on Windows) in the `build/` directory. Next invoke the `node-gyp build` command. Now you have your compiled `.node` bindings file! The compiled bindings end up in `build/Release/`. You can now use the binary addon in a Node project `hello.js` by pointing `require` to the recently built `hello.node` module: var addon = require('./build/Release/hello'); console.log(addon.hello()); // 'world' Please see patterns below for further information or for an example in production. ## Addon patterns Below are some addon patterns to help you get started. Consult the online [v8 reference](http://izs.me/v8-docs/main.html) for help with the various v8 calls, and v8's [Embedder's Guide](http://code.google.com/apis/v8/embed.html) for an explanation of several concepts used such as handles, scopes, function templates, etc. In order to use these examples you need to compile them using `node-gyp`. Create the following `binding.gyp` file: { "targets": [ { "target_name": "addon", "sources": [ "addon.cc" ] } ] } In cases where there is more than one `.cc` file, simply add the file name to the `sources` array, e.g.: "sources": ["addon.cc", "myexample.cc"] Now that you have your `binding.gyp` ready, you can configure and build the addon: $ node-gyp configure build ### Function arguments The following pattern illustrates how to read arguments from JavaScript function calls and return a result. This is the main and only needed source `addon.cc`: #define BUILDING_NODE_EXTENSION #include using namespace v8; Handle Add(const Arguments& args) { HandleScope scope; if (args.Length() < 2) { ThrowException(Exception::TypeError(String::New("Wrong number of arguments"))); return scope.Close(Undefined()); } if (!args[0]->IsNumber() || !args[1]->IsNumber()) { ThrowException(Exception::TypeError(String::New("Wrong arguments"))); return scope.Close(Undefined()); } Local num = Number::New(args[0]->NumberValue() + args[1]->NumberValue()); return scope.Close(num); } void Init(Handle target) { target->Set(String::NewSymbol("add"), FunctionTemplate::New(Add)->GetFunction()); } NODE_MODULE(addon, Init) You can test it with the following JavaScript snippet: var addon = require('./build/Release/addon'); console.log( 'This should be eight:', addon.add(3,5) ); ### Callbacks You can pass JavaScript functions to a C++ function and execute them from there. Here's `addon.cc`: #define BUILDING_NODE_EXTENSION #include using namespace v8; Handle RunCallback(const Arguments& args) { HandleScope scope; Local cb = Local::Cast(args[0]); const unsigned argc = 1; Local argv[argc] = { Local::New(String::New("hello world")) }; cb->Call(Context::GetCurrent()->Global(), argc, argv); return scope.Close(Undefined()); } void Init(Handle target) { target->Set(String::NewSymbol("runCallback"), FunctionTemplate::New(RunCallback)->GetFunction()); } NODE_MODULE(addon, Init) To test it run the following JavaScript snippet: var addon = require('./build/Release/addon'); addon.runCallback(function(msg){ console.log(msg); // 'hello world' }); ### Object factory You can create and return new objects from within a C++ function with this `addon.cc` pattern, which returns an object with property `msg` that echoes the string passed to `createObject()`: #define BUILDING_NODE_EXTENSION #include using namespace v8; Handle CreateObject(const Arguments& args) { HandleScope scope; Local obj = Object::New(); obj->Set(String::NewSymbol("msg"), args[0]->ToString()); return scope.Close(obj); } void Init(Handle target) { target->Set(String::NewSymbol("createObject"), FunctionTemplate::New(CreateObject)->GetFunction()); } NODE_MODULE(addon, Init) To test it in JavaScript: var addon = require('./build/Release/addon'); var obj1 = addon.createObject('hello'); var obj2 = addon.createObject('world'); console.log(obj1.msg+' '+obj2.msg); // 'hello world' ### Function factory This pattern illustrates how to create and return a JavaScript function that wraps a C++ function: #define BUILDING_NODE_EXTENSION #include using namespace v8; Handle MyFunction(const Arguments& args) { HandleScope scope; return scope.Close(String::New("hello world")); } Handle CreateFunction(const Arguments& args) { HandleScope scope; Local tpl = FunctionTemplate::New(MyFunction); Local fn = tpl->GetFunction(); fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous return scope.Close(fn); } void Init(Handle target) { target->Set(String::NewSymbol("createFunction"), FunctionTemplate::New(CreateFunction)->GetFunction()); } NODE_MODULE(addon, Init) To test: var addon = require('./build/Release/addon'); var fn = addon.createFunction(); console.log(fn()); // 'hello world' ### Wrapping C++ objects Here we will create a wrapper for a C++ object/class `MyObject` that can be instantiated in JavaScript through the `new` operator. First prepare the main module `addon.cc`: #define BUILDING_NODE_EXTENSION #include #include "myobject.h" using namespace v8; void InitAll(Handle target) { MyObject::Init(target); } NODE_MODULE(addon, InitAll) Then in `myobject.h` make your wrapper inherit from `node::ObjectWrap`: #ifndef MYOBJECT_H #define MYOBJECT_H #include class MyObject : public node::ObjectWrap { public: static void Init(v8::Handle target); private: MyObject(); ~MyObject(); static v8::Handle New(const v8::Arguments& args); static v8::Handle PlusOne(const v8::Arguments& args); double counter_; }; #endif And in `myobject.cc` implement the various methods that you want to expose. Here we expose the method `plusOne` by adding it to the constructor's prototype: #define BUILDING_NODE_EXTENSION #include #include "myobject.h" using namespace v8; MyObject::MyObject() {}; MyObject::~MyObject() {}; void MyObject::Init(Handle target) { // Prepare constructor template Local tpl = FunctionTemplate::New(New); tpl->SetClassName(String::NewSymbol("MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), FunctionTemplate::New(PlusOne)->GetFunction()); Persistent constructor = Persistent::New(tpl->GetFunction()); target->Set(String::NewSymbol("MyObject"), constructor); } Handle MyObject::New(const Arguments& args) { HandleScope scope; MyObject* obj = new MyObject(); obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); obj->Wrap(args.This()); return args.This(); } Handle MyObject::PlusOne(const Arguments& args) { HandleScope scope; MyObject* obj = ObjectWrap::Unwrap(args.This()); obj->counter_ += 1; return scope.Close(Number::New(obj->counter_)); } Test it with: var addon = require('./build/Release/addon'); var obj = new addon.MyObject(10); console.log( obj.plusOne() ); // 11 console.log( obj.plusOne() ); // 12 console.log( obj.plusOne() ); // 13 ### Factory of wrapped objects This is useful when you want to be able to create native objects without explicitly instantiating them with the `new` operator in JavaScript, e.g. var obj = addon.createObject(); // instead of: // var obj = new addon.Object(); Let's register our `createObject` method in `addon.cc`: #define BUILDING_NODE_EXTENSION #include #include "myobject.h" using namespace v8; Handle CreateObject(const Arguments& args) { HandleScope scope; return scope.Close(MyObject::NewInstance(args)); } void InitAll(Handle target) { MyObject::Init(); target->Set(String::NewSymbol("createObject"), FunctionTemplate::New(CreateObject)->GetFunction()); } NODE_MODULE(addon, InitAll) In `myobject.h` we now introduce the static method `NewInstance` that takes care of instantiating the object (i.e. it does the job of `new` in JavaScript): #define BUILDING_NODE_EXTENSION #ifndef MYOBJECT_H #define MYOBJECT_H #include class MyObject : public node::ObjectWrap { public: static void Init(); static v8::Handle NewInstance(const v8::Arguments& args); private: MyObject(); ~MyObject(); static v8::Persistent constructor; static v8::Handle New(const v8::Arguments& args); static v8::Handle PlusOne(const v8::Arguments& args); double counter_; }; #endif The implementation is similar to the above in `myobject.cc`: #define BUILDING_NODE_EXTENSION #include #include "myobject.h" using namespace v8; MyObject::MyObject() {}; MyObject::~MyObject() {}; Persistent MyObject::constructor; void MyObject::Init() { // Prepare constructor template Local tpl = FunctionTemplate::New(New); tpl->SetClassName(String::NewSymbol("MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), FunctionTemplate::New(PlusOne)->GetFunction()); constructor = Persistent::New(tpl->GetFunction()); } Handle MyObject::New(const Arguments& args) { HandleScope scope; MyObject* obj = new MyObject(); obj->counter_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); obj->Wrap(args.This()); return args.This(); } Handle MyObject::NewInstance(const Arguments& args) { HandleScope scope; const unsigned argc = 1; Handle argv[argc] = { args[0] }; Local instance = constructor->NewInstance(argc, argv); return scope.Close(instance); } Handle MyObject::PlusOne(const Arguments& args) { HandleScope scope; MyObject* obj = ObjectWrap::Unwrap(args.This()); obj->counter_ += 1; return scope.Close(Number::New(obj->counter_)); } Test it with: var addon = require('./build/Release/addon'); var obj = addon.createObject(10); console.log( obj.plusOne() ); // 11 console.log( obj.plusOne() ); // 12 console.log( obj.plusOne() ); // 13 var obj2 = addon.createObject(20); console.log( obj2.plusOne() ); // 21 console.log( obj2.plusOne() ); // 22 console.log( obj2.plusOne() ); // 23 ### Passing wrapped objects around In addition to wrapping and returning C++ objects, you can pass them around by unwrapping them with Node's `node::ObjectWrap::Unwrap` helper function. In the following `addon.cc` we introduce a function `add()` that can take on two `MyObject` objects: #define BUILDING_NODE_EXTENSION #include #include "myobject.h" using namespace v8; Handle CreateObject(const Arguments& args) { HandleScope scope; return scope.Close(MyObject::NewInstance(args)); } Handle Add(const Arguments& args) { HandleScope scope; MyObject* obj1 = node::ObjectWrap::Unwrap( args[0]->ToObject()); MyObject* obj2 = node::ObjectWrap::Unwrap( args[1]->ToObject()); double sum = obj1->Val() + obj2->Val(); return scope.Close(Number::New(sum)); } void InitAll(Handle target) { MyObject::Init(); target->Set(String::NewSymbol("createObject"), FunctionTemplate::New(CreateObject)->GetFunction()); target->Set(String::NewSymbol("add"), FunctionTemplate::New(Add)->GetFunction()); } NODE_MODULE(addon, InitAll) To make things interesting we introduce a public method in `myobject.h` so we can probe private values after unwrapping the object: #define BUILDING_NODE_EXTENSION #ifndef MYOBJECT_H #define MYOBJECT_H #include class MyObject : public node::ObjectWrap { public: static void Init(); static v8::Handle NewInstance(const v8::Arguments& args); double Val() const { return val_; } private: MyObject(); ~MyObject(); static v8::Persistent constructor; static v8::Handle New(const v8::Arguments& args); double val_; }; #endif The implementation of `myobject.cc` is similar as before: #define BUILDING_NODE_EXTENSION #include #include "myobject.h" using namespace v8; MyObject::MyObject() {}; MyObject::~MyObject() {}; Persistent MyObject::constructor; void MyObject::Init() { // Prepare constructor template Local tpl = FunctionTemplate::New(New); tpl->SetClassName(String::NewSymbol("MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); constructor = Persistent::New(tpl->GetFunction()); } Handle MyObject::New(const Arguments& args) { HandleScope scope; MyObject* obj = new MyObject(); obj->val_ = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); obj->Wrap(args.This()); return args.This(); } Handle MyObject::NewInstance(const Arguments& args) { HandleScope scope; const unsigned argc = 1; Handle argv[argc] = { args[0] }; Local instance = constructor->NewInstance(argc, argv); return scope.Close(instance); } Test it with: var addon = require('./build/Release/addon'); var obj1 = addon.createObject(10); var obj2 = addon.createObject(20); var result = addon.add(obj1, obj2); console.log(result); // 30