summaryrefslogtreecommitdiff
path: root/doc/api/addons.md
diff options
context:
space:
mode:
authorRobert Jefe Lindstaedt <robert.lindstaedt@gmail.com>2016-04-21 00:12:40 +0200
committerJames M Snell <jasnell@gmail.com>2016-04-20 16:34:27 -0700
commit0800c0aa7275bf389b157e1568fa61b59285ad86 (patch)
treea0b739491c4b0170fc333b1b57d61e6d7ae1ca58 /doc/api/addons.md
parentcff2a137f201604cbb3c4e54578b4ebfd20bcaf2 (diff)
downloadandroid-node-v8-0800c0aa7275bf389b157e1568fa61b59285ad86.tar.gz
android-node-v8-0800c0aa7275bf389b157e1568fa61b59285ad86.tar.bz2
android-node-v8-0800c0aa7275bf389b157e1568fa61b59285ad86.zip
doc: git mv to .md
* doc: rename .markdown references in content * doc: rename to .md in tools * doc: rename to .md in CONTRIBUTING.md PR-URL: https://github.com/nodejs/node/pull/4747 Reviewed-By: Myles Borins <myles.borins@gmail.com> Reviewed-By: techjeffharris Reviewed-By: Johan Bergström <bugs@bergstroem.nu> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
Diffstat (limited to 'doc/api/addons.md')
-rw-r--r--doc/api/addons.md1091
1 files changed, 1091 insertions, 0 deletions
diff --git a/doc/api/addons.md b/doc/api/addons.md
new file mode 100644
index 0000000000..4668bc546f
--- /dev/null
+++ b/doc/api/addons.md
@@ -0,0 +1,1091 @@
+# Addons
+
+Node.js Addons are dynamically-linked shared objects, written in C or C++, that
+can be loaded into Node.js using the [`require()`][require] function, and used
+just as if they were an ordinary Node.js module. They are used primarily to
+provide an interface between JavaScript running in Node.js and C/C++ libraries.
+
+At the moment, the method for implementing Addons is rather complicated,
+involving knowledge of several components and APIs :
+
+ - V8: the C++ library Node.js currently uses to provide the
+ JavaScript implementation. V8 provides the mechanisms for creating objects,
+ calling functions, etc. V8's API is documented mostly in the
+ `v8.h` header file (`deps/v8/include/v8.h` in the Node.js source
+ tree), which is also available [online][v8-docs].
+
+ - [libuv][]: The C library that implements the Node.js event loop, its worker
+ threads and all of the asynchronous behaviors of the platform. It also
+ serves as a cross-platform abstraction library, giving easy, POSIX-like
+ access across all major operating systems to many common system tasks, such
+ as interacting with the filesystem, sockets, timers and system events. libuv
+ also provides a pthreads-like threading abstraction that may be used to
+ power more sophisticated asynchronous Addons that need to move beyond the
+ standard event loop. Addon authors are encouraged to think about how to
+ avoid blocking the event loop with I/O or other time-intensive tasks by
+ off-loading work via libuv to non-blocking system operations, worker threads
+ or a custom use of libuv's threads.
+
+ - Internal Node.js libraries. Node.js itself exports a number of C/C++ APIs
+ that Addons can use &mdash; the most important of which is the
+ `node::ObjectWrap` class.
+
+ - Node.js includes a number of other statically linked libraries including
+ OpenSSL. These other libraries are located in the `deps/` directory in the
+ Node.js source tree. Only the V8 and OpenSSL symbols are purposefully
+ re-exported by Node.js and may be used to various extents by Addons.
+ See [Linking to Node.js' own dependencies][] for additional information.
+
+All of the following examples are available for [download][] and may
+be used as a starting-point for your own Addon.
+
+## Hello world
+
+This "Hello world" example is a simple Addon, written in C++, that is the
+equivalent of the following JavaScript code:
+
+```js
+module.exports.hello = () => 'world';
+```
+
+First, create the file `hello.cc`:
+
+```cpp
+// hello.cc
+#include <node.h>
+
+namespace demo {
+
+using v8::FunctionCallbackInfo;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+void Method(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ args.GetReturnValue().Set(String::NewFromUtf8(isolate, "world"));
+}
+
+void init(Local<Object> exports) {
+ NODE_SET_METHOD(exports, "hello", Method);
+}
+
+NODE_MODULE(addon, init)
+
+} // namespace demo
+```
+
+Note that all Node.js Addons must export an initialization function following
+the pattern:
+
+```cpp
+void Initialize(Local<Object> exports);
+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` must match the filename of the final binary (excluding
+the .node suffix).
+
+In the `hello.cc` example, then, the initialization function is `init` and the
+Addon module name is `addon`.
+
+### Building
+
+Once the source code has been written, it must be compiled into the binary
+`addon.node` file. To do so, create a file called `binding.gyp` in the
+top-level of the project describing the build configuration of your module
+using a JSON-like format. This file is used by [node-gyp][] -- a tool written
+specifically to compile Node.js Addons.
+
+```
+{
+ "targets": [
+ {
+ "target_name": "addon",
+ "sources": [ "hello.cc" ]
+ }
+ ]
+}
+```
+
+*Note: A version of the `node-gyp` utility is bundled and distributed with
+Node.js as part of `npm`. This version is not made directly available for
+developers to use and is intended only to support the ability to use the
+`npm install` command to compile and install Addons. Developers who wish to
+use `node-gyp` directly can install it using the command
+`npm install -g node-gyp`. See the `node-gyp` [installation instructions][] for
+more information, including platform-specific requirements.*
+
+Once the `binding.gyp` file has been created, use `node-gyp configure` to
+generate the appropriate project build files for the current platform. This
+will generate either a `Makefile` (on Unix platforms) or a `vcxproj` file
+(on Windows) in the `build/` directory.
+
+Next, invoke the `node-gyp build` command to generate the compiled `addon.node`
+file. This will be put into the `build/Release/` directory.
+
+When using `npm install` to install a Node.js Addon, npm uses its own bundled
+version of `node-gyp` to perform this same set of actions, generating a
+compiled version of the Addon for the user's platform on demand.
+
+Once built, the binary Addon can be used from within Node.js by pointing
+[`require()`][require] to the built `addon.node` module:
+
+```js
+// hello.js
+const addon = require('./build/Release/addon');
+
+console.log(addon.hello()); // 'world'
+```
+
+Please see the examples below for further information or
+<https://github.com/arturadib/node-qt> for an example in production.
+
+Because the exact path to the compiled Addon binary can vary depending on how
+it is compiled (i.e. sometimes it may be in `./build/Debug/`), Addons can use
+the [bindings][] package to load the compiled module.
+
+Note that while the `bindings` package implementation is more sophisticated
+in how it locates Addon modules, it is essentially using a try-catch pattern
+similar to:
+
+```js
+try {
+ return require('./build/Release/addon.node');
+} catch (err) {
+ return require('./build/Debug/addon.node');
+}
+```
+
+### Linking to Node.js' own dependencies
+
+Node.js uses a number of statically linked libraries such as V8, libuv and
+OpenSSL. All Addons are required to link to V8 and may link to any of the
+other dependencies as well. Typically, this is as simple as including
+the appropriate `#include <...>` statements (e.g. `#include <v8.h>`) and
+`node-gyp` will locate the appropriate headers automatically. However, there
+are a few caveats to be aware of:
+
+* When `node-gyp` runs, it will detect the specific release version of Node.js
+and download either the full source tarball or just the headers. If the full
+source is downloaded, Addons will have complete access to the full set of
+Node.js dependencies. However, if only the Node.js headers are downloaded, then
+only the symbols exported by Node.js will be available.
+
+* `node-gyp` can be run using the `--nodedir` flag pointing at a local Node.js
+source image. Using this option, the Addon will have access to the full set of
+dependencies.
+
+### Loading Addons using require()
+
+The filename extension of the compiled Addon binary is `.node` (as opposed
+to `.dll` or `.so`). The [`require()`][require] function is written to look for
+files with the `.node` file extension and initialize those as dynamically-linked
+libraries.
+
+When calling [`require()`][require], the `.node` extension can usually be
+omitted and Node.js will still find and initialize the Addon. One caveat,
+however, is that Node.js will first attempt to locate and load modules or
+JavaScript files that happen to share the same base name. For instance, if
+there is a file `addon.js` in the same directory as the binary `addon.node`,
+then [`require('addon')`][require] will give precedence to the `addon.js` file
+and load it instead.
+
+## Native Abstractions for Node.js
+
+Each of the examples illustrated in this document make direct use of the
+Node.js and V8 APIs for implementing Addons. It is important to understand
+that the V8 API can, and has, changed dramatically from one V8 release to the
+next (and one major Node.js release to the next). With each change, Addons may
+need to be updated and recompiled in order to continue functioning. The Node.js
+release schedule is designed to minimize the frequency and impact of such
+changes but there is little that Node.js can do currently to ensure stability
+of the V8 APIs.
+
+The [Native Abstractions for Node.js][] (or `nan`) provide a set of tools that
+Addon developers are recommended to use to keep compatibility between past and
+future releases of V8 and Node.js. See the `nan` [examples][] for an
+illustration of how it can be used.
+
+## Addon examples
+
+Following are some example Addons intended to help developers get started. The
+examples make use of the V8 APIs. Refer to the online [V8 reference][v8-docs]
+for help with the various V8 calls, and V8's [Embedder's Guide][] for an
+explanation of several concepts used such as handles, scopes, function
+templates, etc.
+
+Each of these examples using 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 additional
+filename to the `sources` array. For example:
+
+```
+"sources": ["addon.cc", "myexample.cc"]
+```
+
+Once the `binding.gyp` file is ready, the example Addons can be configured and
+built using `node-gyp`:
+
+```
+$ node-gyp configure build
+```
+
+
+### Function arguments
+
+Addons will typically expose objects and functions that can be accessed from
+JavaScript running within Node.js. When functions are invoked from JavaScript,
+the input arguments and return value must be mapped to and from the C/C++
+code.
+
+The following example illustrates how to read function arguments passed from
+JavaScript and how to return a result:
+
+```cpp
+// addon.cc
+#include <node.h>
+
+namespace demo {
+
+using v8::Exception;
+using v8::FunctionCallbackInfo;
+using v8::Isolate;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+// This is the implementation of the "add" method
+// Input arguments are passed using the
+// const FunctionCallbackInfo<Value>& args struct
+void Add(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ // Check the number of arguments passed.
+ if (args.Length() < 2) {
+ // Throw an Error that is passed back to JavaScript
+ isolate->ThrowException(Exception::TypeError(
+ String::NewFromUtf8(isolate, "Wrong number of arguments")));
+ return;
+ }
+
+ // Check the argument types
+ if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
+ isolate->ThrowException(Exception::TypeError(
+ String::NewFromUtf8(isolate, "Wrong arguments")));
+ return;
+ }
+
+ // Perform the operation
+ double value = args[0]->NumberValue() + args[1]->NumberValue();
+ Local<Number> num = Number::New(isolate, value);
+
+ // Set the return value (using the passed in
+ // FunctionCallbackInfo<Value>&)
+ args.GetReturnValue().Set(num);
+}
+
+void Init(Local<Object> exports) {
+ NODE_SET_METHOD(exports, "add", Add);
+}
+
+NODE_MODULE(addon, Init)
+
+} // namespace demo
+```
+
+Once compiled, the example Addon can be required and used from within Node.js:
+
+```js
+// test.js
+const addon = require('./build/Release/addon');
+
+console.log('This should be eight:', addon.add(3, 5));
+```
+
+
+### Callbacks
+
+It is common practice within Addons to pass JavaScript functions to a C++
+function and execute them from there. The following example illustrates how
+to invoke such callbacks:
+
+```cpp
+// addon.cc
+#include <node.h>
+
+namespace demo {
+
+using v8::Function;
+using v8::FunctionCallbackInfo;
+using v8::Isolate;
+using v8::Local;
+using v8::Null;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+void RunCallback(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ Local<Function> cb = Local<Function>::Cast(args[0]);
+ const unsigned argc = 1;
+ Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") };
+ cb->Call(Null(isolate), argc, argv);
+}
+
+void Init(Local<Object> exports, Local<Object> module) {
+ NODE_SET_METHOD(module, "exports", RunCallback);
+}
+
+NODE_MODULE(addon, Init)
+
+} // namespace demo
+```
+
+Note that this example uses a two-argument form of `Init()` that receives
+the full `module` object as the second argument. This allows the Addon
+to completely overwrite `exports` with a single function instead of
+adding the function as a property of `exports`.
+
+To test it, run the following JavaScript:
+
+```js
+// test.js
+const addon = require('./build/Release/addon');
+
+addon((msg) => {
+ console.log(msg); // 'hello world'
+});
+```
+
+Note that, in this example, the callback function is invoked synchronously.
+
+### Object factory
+
+Addons can create and return new objects from within a C++ function as
+illustrated in the following example. An object is created and returned with a
+property `msg` that echoes the string passed to `createObject()`:
+
+```cpp
+// addon.cc
+#include <node.h>
+
+namespace demo {
+
+using v8::FunctionCallbackInfo;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+void CreateObject(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ Local<Object> obj = Object::New(isolate);
+ obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString());
+
+ args.GetReturnValue().Set(obj);
+}
+
+void Init(Local<Object> exports, Local<Object> module) {
+ NODE_SET_METHOD(module, "exports", CreateObject);
+}
+
+NODE_MODULE(addon, Init)
+
+} // namespace demo
+```
+
+To test it in JavaScript:
+
+```js
+// test.js
+const addon = require('./build/Release/addon');
+
+var obj1 = addon('hello');
+var obj2 = addon('world');
+console.log(obj1.msg + ' ' + obj2.msg); // 'hello world'
+```
+
+
+### Function factory
+
+Another common scenario is creating JavaScript functions that wrap C++
+functions and returning those back to JavaScript:
+
+```cpp
+// addon.cc
+#include <node.h>
+
+namespace demo {
+
+using v8::Function;
+using v8::FunctionCallbackInfo;
+using v8::FunctionTemplate;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+void MyFunction(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world"));
+}
+
+void CreateFunction(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
+ Local<Function> fn = tpl->GetFunction();
+
+ // omit this to make it anonymous
+ fn->SetName(String::NewFromUtf8(isolate, "theFunction"));
+
+ args.GetReturnValue().Set(fn);
+}
+
+void Init(Local<Object> exports, Local<Object> module) {
+ NODE_SET_METHOD(module, "exports", CreateFunction);
+}
+
+NODE_MODULE(addon, Init)
+
+} // namespace demo
+```
+
+To test:
+
+```js
+// test.js
+const addon = require('./build/Release/addon');
+
+var fn = addon();
+console.log(fn()); // 'hello world'
+```
+
+
+### Wrapping C++ objects
+
+It is also possible to wrap C++ objects/classes in a way that allows new
+instances to be created using the JavaScript `new` operator:
+
+```cpp
+// addon.cc
+#include <node.h>
+#include "myobject.h"
+
+namespace demo {
+
+using v8::Local;
+using v8::Object;
+
+void InitAll(Local<Object> exports) {
+ MyObject::Init(exports);
+}
+
+NODE_MODULE(addon, InitAll)
+
+} // namespace demo
+```
+
+Then, in `myobject.h`, the wrapper class inherits from `node::ObjectWrap`:
+
+```cpp
+// myobject.h
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <node.h>
+#include <node_object_wrap.h>
+
+namespace demo {
+
+class MyObject : public node::ObjectWrap {
+ public:
+ static void Init(v8::Local<v8::Object> exports);
+
+ private:
+ explicit MyObject(double value = 0);
+ ~MyObject();
+
+ static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static v8::Persistent<v8::Function> constructor;
+ double value_;
+};
+
+} // namespace demo
+
+#endif
+```
+
+In `myobject.cc`, implement the various methods that are to be exposed.
+Below, the method `plusOne()` is exposed by adding it to the constructor's
+prototype:
+
+```cpp
+// myobject.cc
+#include "myobject.h"
+
+namespace demo {
+
+using v8::Function;
+using v8::FunctionCallbackInfo;
+using v8::FunctionTemplate;
+using v8::Isolate;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> MyObject::constructor;
+
+MyObject::MyObject(double value) : value_(value) {
+}
+
+MyObject::~MyObject() {
+}
+
+void MyObject::Init(Local<Object> exports) {
+ Isolate* isolate = exports->GetIsolate();
+
+ // Prepare constructor template
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
+ tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+
+ // Prototype
+ NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
+
+ constructor.Reset(isolate, tpl->GetFunction());
+ exports->Set(String::NewFromUtf8(isolate, "MyObject"),
+ tpl->GetFunction());
+}
+
+void MyObject::New(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ if (args.IsConstructCall()) {
+ // Invoked as constructor: `new MyObject(...)`
+ double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
+ MyObject* obj = new MyObject(value);
+ obj->Wrap(args.This());
+ args.GetReturnValue().Set(args.This());
+ } else {
+ // Invoked as plain function `MyObject(...)`, turn into construct call.
+ const int argc = 1;
+ Local<Value> argv[argc] = { args[0] };
+ Local<Function> cons = Local<Function>::New(isolate, constructor);
+ args.GetReturnValue().Set(cons->NewInstance(argc, argv));
+ }
+}
+
+void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
+ obj->value_ += 1;
+
+ args.GetReturnValue().Set(Number::New(isolate, obj->value_));
+}
+
+} // namespace demo
+```
+
+To build this example, the `myobject.cc` file must be added to the
+`binding.gyp`:
+
+```
+{
+ "targets": [
+ {
+ "target_name": "addon",
+ "sources": [
+ "addon.cc",
+ "myobject.cc"
+ ]
+ }
+ ]
+}
+```
+
+Test it with:
+
+```js
+// test.js
+const 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
+
+Alternatively, it is possible to use a factory pattern to avoid explicitly
+creating object instances using the JavaScript `new` operator:
+
+```js
+var obj = addon.createObject();
+// instead of:
+// var obj = new addon.Object();
+```
+
+First, the `createObject()` method is implemented in `addon.cc`:
+
+```cpp
+// addon.cc
+#include <node.h>
+#include "myobject.h"
+
+namespace demo {
+
+using v8::FunctionCallbackInfo;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+void CreateObject(const FunctionCallbackInfo<Value>& args) {
+ MyObject::NewInstance(args);
+}
+
+void InitAll(Local<Object> exports, Local<Object> module) {
+ MyObject::Init(exports->GetIsolate());
+
+ NODE_SET_METHOD(module, "exports", CreateObject);
+}
+
+NODE_MODULE(addon, InitAll)
+
+} // namespace demo
+```
+
+In `myobject.h`, the static method `NewInstance()` is added to handle
+instantiating the object. This method takes the place of using `new` in
+JavaScript:
+
+```cpp
+// myobject.h
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <node.h>
+#include <node_object_wrap.h>
+
+namespace demo {
+
+class MyObject : public node::ObjectWrap {
+ public:
+ static void Init(v8::Isolate* isolate);
+ static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
+
+ private:
+ explicit MyObject(double value = 0);
+ ~MyObject();
+
+ static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static v8::Persistent<v8::Function> constructor;
+ double value_;
+};
+
+} // namespace demo
+
+#endif
+```
+
+The implementation in `myobject.cc` is similar to the previous example:
+
+```cpp
+// myobject.cc
+#include <node.h>
+#include "myobject.h"
+
+namespace demo {
+
+using v8::Function;
+using v8::FunctionCallbackInfo;
+using v8::FunctionTemplate;
+using v8::Isolate;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> MyObject::constructor;
+
+MyObject::MyObject(double value) : value_(value) {
+}
+
+MyObject::~MyObject() {
+}
+
+void MyObject::Init(Isolate* isolate) {
+ // Prepare constructor template
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
+ tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+
+ // Prototype
+ NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
+
+ constructor.Reset(isolate, tpl->GetFunction());
+}
+
+void MyObject::New(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ if (args.IsConstructCall()) {
+ // Invoked as constructor: `new MyObject(...)`
+ double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
+ MyObject* obj = new MyObject(value);
+ obj->Wrap(args.This());
+ args.GetReturnValue().Set(args.This());
+ } else {
+ // Invoked as plain function `MyObject(...)`, turn into construct call.
+ const int argc = 1;
+ Local<Value> argv[argc] = { args[0] };
+ Local<Function> cons = Local<Function>::New(isolate, constructor);
+ args.GetReturnValue().Set(cons->NewInstance(argc, argv));
+ }
+}
+
+void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ const unsigned argc = 1;
+ Local<Value> argv[argc] = { args[0] };
+ Local<Function> cons = Local<Function>::New(isolate, constructor);
+ Local<Object> instance = cons->NewInstance(argc, argv);
+
+ args.GetReturnValue().Set(instance);
+}
+
+void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
+ obj->value_ += 1;
+
+ args.GetReturnValue().Set(Number::New(isolate, obj->value_));
+}
+
+} // namespace demo
+```
+
+Once again, to build this example, the `myobject.cc` file must be added to the
+`binding.gyp`:
+
+```
+{
+ "targets": [
+ {
+ "target_name": "addon",
+ "sources": [
+ "addon.cc",
+ "myobject.cc"
+ ]
+ }
+ ]
+}
+```
+
+Test it with:
+
+```js
+// test.js
+const createObject = require('./build/Release/addon');
+
+var obj = createObject(10);
+console.log(obj.plusOne()); // 11
+console.log(obj.plusOne()); // 12
+console.log(obj.plusOne()); // 13
+
+var obj2 = 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, it is possible to pass
+wrapped objects around by unwrapping them with the Node.js helper function
+`node::ObjectWrap::Unwrap`. The following examples shows a function `add()`
+that can take two `MyObject` objects as input arguments:
+
+```cpp
+// addon.cc
+#include <node.h>
+#include <node_object_wrap.h>
+#include "myobject.h"
+
+namespace demo {
+
+using v8::FunctionCallbackInfo;
+using v8::Isolate;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+void CreateObject(const FunctionCallbackInfo<Value>& args) {
+ MyObject::NewInstance(args);
+}
+
+void Add(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
+ args[0]->ToObject());
+ MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
+ args[1]->ToObject());
+
+ double sum = obj1->value() + obj2->value();
+ args.GetReturnValue().Set(Number::New(isolate, sum));
+}
+
+void InitAll(Local<Object> exports) {
+ MyObject::Init(exports->GetIsolate());
+
+ NODE_SET_METHOD(exports, "createObject", CreateObject);
+ NODE_SET_METHOD(exports, "add", Add);
+}
+
+NODE_MODULE(addon, InitAll)
+
+} // namespace demo
+```
+
+In `myobject.h`, a new public method is added to allow access to private values
+after unwrapping the object.
+
+```cpp
+// myobject.h
+#ifndef MYOBJECT_H
+#define MYOBJECT_H
+
+#include <node.h>
+#include <node_object_wrap.h>
+
+namespace demo {
+
+class MyObject : public node::ObjectWrap {
+ public:
+ static void Init(v8::Isolate* isolate);
+ static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
+ inline double value() const { return value_; }
+
+ private:
+ explicit MyObject(double value = 0);
+ ~MyObject();
+
+ static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static v8::Persistent<v8::Function> constructor;
+ double value_;
+};
+
+} // namespace demo
+
+#endif
+```
+
+The implementation of `myobject.cc` is similar to before:
+
+```cpp
+// myobject.cc
+#include <node.h>
+#include "myobject.h"
+
+namespace demo {
+
+using v8::Function;
+using v8::FunctionCallbackInfo;
+using v8::FunctionTemplate;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> MyObject::constructor;
+
+MyObject::MyObject(double value) : value_(value) {
+}
+
+MyObject::~MyObject() {
+}
+
+void MyObject::Init(Isolate* isolate) {
+ // Prepare constructor template
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
+ tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+
+ constructor.Reset(isolate, tpl->GetFunction());
+}
+
+void MyObject::New(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ if (args.IsConstructCall()) {
+ // Invoked as constructor: `new MyObject(...)`
+ double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
+ MyObject* obj = new MyObject(value);
+ obj->Wrap(args.This());
+ args.GetReturnValue().Set(args.This());
+ } else {
+ // Invoked as plain function `MyObject(...)`, turn into construct call.
+ const int argc = 1;
+ Local<Value> argv[argc] = { args[0] };
+ Local<Function> cons = Local<Function>::New(isolate, constructor);
+ args.GetReturnValue().Set(cons->NewInstance(argc, argv));
+ }
+}
+
+void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+
+ const unsigned argc = 1;
+ Local<Value> argv[argc] = { args[0] };
+ Local<Function> cons = Local<Function>::New(isolate, constructor);
+ Local<Object> instance = cons->NewInstance(argc, argv);
+
+ args.GetReturnValue().Set(instance);
+}
+
+} // namespace demo
+```
+
+Test it with:
+
+```js
+// test.js
+const 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
+```
+
+### AtExit hooks
+
+An "AtExit" hook is a function that is invoked after the Node.js event loop
+has ended by before the JavaScript VM is terminated and Node.js shuts down.
+"AtExit" hooks are registered using the `node::AtExit` API.
+
+#### void AtExit(callback, args)
+
+* `callback`: `void (*)(void*)` - A pointer to the function to call at exit.
+* `args`: `void*` - A pointer to pass to the callback at exit.
+
+Registers exit hooks that run after the event loop has ended but before the VM
+is killed.
+
+AtExit takes two parameters: a pointer to a callback function to run at exit,
+and a pointer to untyped context data to be passed to that callback.
+
+Callbacks are run in last-in first-out order.
+
+The following `addon.cc` implements AtExit:
+
+```cpp
+// addon.cc
+#undef NDEBUG
+#include <assert.h>
+#include <stdlib.h>
+#include <node.h>
+
+namespace demo {
+
+using node::AtExit;
+using v8::HandleScope;
+using v8::Isolate;
+using v8::Local;
+using v8::Object;
+
+static char cookie[] = "yum yum";
+static int at_exit_cb1_called = 0;
+static int at_exit_cb2_called = 0;
+
+static void at_exit_cb1(void* arg) {
+ Isolate* isolate = static_cast<Isolate*>(arg);
+ HandleScope scope(isolate);
+ Local<Object> obj = Object::New(isolate);
+ assert(!obj.IsEmpty()); // assert VM is still alive
+ assert(obj->IsObject());
+ at_exit_cb1_called++;
+}
+
+static void at_exit_cb2(void* arg) {
+ assert(arg == static_cast<void*>(cookie));
+ at_exit_cb2_called++;
+}
+
+static void sanity_check(void*) {
+ assert(at_exit_cb1_called == 1);
+ assert(at_exit_cb2_called == 2);
+}
+
+void init(Local<Object> exports) {
+ AtExit(sanity_check);
+ AtExit(at_exit_cb2, cookie);
+ AtExit(at_exit_cb2, cookie);
+ AtExit(at_exit_cb1, exports->GetIsolate());
+}
+
+NODE_MODULE(addon, init);
+
+} // namespace demo
+```
+
+Test in JavaScript by running:
+
+```js
+// test.js
+const addon = require('./build/Release/addon');
+```
+
+[bindings]: https://github.com/TooTallNate/node-bindings
+[download]: https://github.com/nodejs/node-addon-examples
+[Embedder's Guide]: https://developers.google.com/v8/embed
+[examples]: https://github.com/nodejs/nan/tree/master/examples/
+[installation instructions]: https://github.com/nodejs/node-gyp#installation
+[libuv]: https://github.com/libuv/libuv
+[Linking to Node.js' own dependencies]: #addons_linking_to_node_js_own_dependencies
+[Native Abstractions for Node.js]: https://github.com/nodejs/nan
+[node-gyp]: https://github.com/nodejs/node-gyp
+[require]: globals.html#globals_require
+[v8-docs]: https://v8docs.nodesource.com/