• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# C++ addons
2
3<!--introduced_in=v0.10.0-->
4<!-- type=misc -->
5
6_Addons_ are dynamically-linked shared objects written in C++. The
7[`require()`][require] function can load addons as ordinary Node.js modules.
8Addons provide an interface between JavaScript and C/C++ libraries.
9
10There are three options for implementing addons: N-API, nan, or direct
11use of internal V8, libuv and Node.js libraries. Unless there is a need for
12direct access to functionality which is not exposed by N-API, use N-API.
13Refer to [C/C++ addons with N-API](n-api.html) for more information on N-API.
14
15When not using N-API, implementing addons is complicated,
16involving knowledge of several components and APIs:
17
18* V8: the C++ library Node.js uses to provide the
19  JavaScript implementation. V8 provides the mechanisms for creating objects,
20  calling functions, etc. V8's API is documented mostly in the
21  `v8.h` header file (`deps/v8/include/v8.h` in the Node.js source
22  tree), which is also available [online][v8-docs].
23
24* [libuv][]: The C library that implements the Node.js event loop, its worker
25  threads and all of the asynchronous behaviors of the platform. It also
26  serves as a cross-platform abstraction library, giving easy, POSIX-like
27  access across all major operating systems to many common system tasks, such
28  as interacting with the filesystem, sockets, timers, and system events. libuv
29  also provides a pthreads-like threading abstraction that may be used to
30  power more sophisticated asynchronous addons that need to move beyond the
31  standard event loop. Addon authors are encouraged to think about how to
32  avoid blocking the event loop with I/O or other time-intensive tasks by
33  off-loading work via libuv to non-blocking system operations, worker threads
34  or a custom use of libuv's threads.
35
36* Internal Node.js libraries. Node.js itself exports C++ APIs that addons can
37  use, the most important of which is the `node::ObjectWrap` class.
38
39* Node.js includes other statically linked libraries including OpenSSL. These
40  other libraries are located in the `deps/` directory in the Node.js source
41  tree. Only the libuv, OpenSSL, V8 and zlib symbols are purposefully
42  re-exported by Node.js and may be used to various extents by addons. See
43  [Linking to libraries included with Node.js][] for additional information.
44
45All of the following examples are available for [download][] and may
46be used as the starting-point for an addon.
47
48## Hello world
49
50This "Hello world" example is a simple addon, written in C++, that is the
51equivalent of the following JavaScript code:
52
53```js
54module.exports.hello = () => 'world';
55```
56
57First, create the file `hello.cc`:
58
59```cpp
60// hello.cc
61#include <node.h>
62
63namespace demo {
64
65using v8::FunctionCallbackInfo;
66using v8::Isolate;
67using v8::Local;
68using v8::NewStringType;
69using v8::Object;
70using v8::String;
71using v8::Value;
72
73void Method(const FunctionCallbackInfo<Value>& args) {
74  Isolate* isolate = args.GetIsolate();
75  args.GetReturnValue().Set(String::NewFromUtf8(
76      isolate, "world", NewStringType::kNormal).ToLocalChecked());
77}
78
79void Initialize(Local<Object> exports) {
80  NODE_SET_METHOD(exports, "hello", Method);
81}
82
83NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
84
85}  // namespace demo
86```
87
88All Node.js addons must export an initialization function following
89the pattern:
90
91```cpp
92void Initialize(Local<Object> exports);
93NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)
94```
95
96There is no semi-colon after `NODE_MODULE` as it's not a function (see
97`node.h`).
98
99The `module_name` must match the filename of the final binary (excluding
100the `.node` suffix).
101
102In the `hello.cc` example, then, the initialization function is `Initialize`
103and the addon module name is `addon`.
104
105When building addons with `node-gyp`, using the macro `NODE_GYP_MODULE_NAME` as
106the first parameter of `NODE_MODULE()` will ensure that the name of the final
107binary will be passed to `NODE_MODULE()`.
108
109### Context-aware addons
110
111There are environments in which Node.js addons may need to be loaded multiple
112times in multiple contexts. For example, the [Electron][] runtime runs multiple
113instances of Node.js in a single process. Each instance will have its own
114`require()` cache, and thus each instance will need a native addon to behave
115correctly when loaded via `require()`. From the addon's perspective, this means
116that it must support multiple initializations.
117
118A context-aware addon can be constructed by using the macro
119`NODE_MODULE_INITIALIZER`, which expands to the name of a function which Node.js
120will expect to find when it loads an addon. An addon can thus be initialized as
121in the following example:
122
123```cpp
124using namespace v8;
125
126extern "C" NODE_MODULE_EXPORT void
127NODE_MODULE_INITIALIZER(Local<Object> exports,
128                        Local<Value> module,
129                        Local<Context> context) {
130  /* Perform addon initialization steps here. */
131}
132```
133
134Another option is to use the macro `NODE_MODULE_INIT()`, which will also
135construct a context-aware addon. Unlike `NODE_MODULE()`, which is used to
136construct an addon around a given addon initializer function,
137`NODE_MODULE_INIT()` serves as the declaration of such an initializer to be
138followed by a function body.
139
140The following three variables may be used inside the function body following an
141invocation of `NODE_MODULE_INIT()`:
142
143* `Local<Object> exports`,
144* `Local<Value> module`, and
145* `Local<Context> context`
146
147The choice to build a context-aware addon carries with it the responsibility of
148carefully managing global static data. Since the addon may be loaded multiple
149times, potentially even from different threads, any global static data stored
150in the addon must be properly protected, and must not contain any persistent
151references to JavaScript objects. The reason for this is that JavaScript
152objects are only valid in one context, and will likely cause a crash when
153accessed from the wrong context or from a different thread than the one on which
154they were created.
155
156The context-aware addon can be structured to avoid global static data by
157performing the following steps:
158* Define a class which will hold per-addon-instance data and which has a static
159member of the form
160  ```cpp
161  static void DeleteInstance(void* data) {
162    // Cast `data` to an instance of the class and delete it.
163  }
164  ```
165* Heap-allocate an instance of this class in the addon initializer. This can be
166accomplished using the `new` keyword.
167* Call `node::AddEnvironmentCleanupHook()`, passing it the above-created
168instance and a pointer to `DeleteInstance()`. This will ensure the instance is
169deleted when the environment is torn down.
170* Store the instance of the class in a `v8::External`, and
171* Pass the `v8::External` to all methods exposed to JavaScript by passing it
172to `v8::FunctionTemplate::New()` or `v8::Function::New()` which creates the
173native-backed JavaScript functions. The third parameter of
174`v8::FunctionTemplate::New()` or `v8::Function::New()`  accepts the
175`v8::External` and makes it available in the native callback using the
176`v8::FunctionCallbackInfo::Data()` method.
177
178This will ensure that the per-addon-instance data reaches each binding that can
179be called from JavaScript. The per-addon-instance data must also be passed into
180any asynchronous callbacks the addon may create.
181
182The following example illustrates the implementation of a context-aware addon:
183
184```cpp
185#include <node.h>
186
187using namespace v8;
188
189class AddonData {
190 public:
191  explicit AddonData(Isolate* isolate):
192      call_count(0) {
193    // Ensure this per-addon-instance data is deleted at environment cleanup.
194    node::AddEnvironmentCleanupHook(isolate, DeleteInstance, this);
195  }
196
197  // Per-addon data.
198  int call_count;
199
200  static void DeleteInstance(void* data) {
201    delete static_cast<AddonData*>(data);
202  }
203};
204
205static void Method(const v8::FunctionCallbackInfo<v8::Value>& info) {
206  // Retrieve the per-addon-instance data.
207  AddonData* data =
208      reinterpret_cast<AddonData*>(info.Data().As<External>()->Value());
209  data->call_count++;
210  info.GetReturnValue().Set((double)data->call_count);
211}
212
213// Initialize this addon to be context-aware.
214NODE_MODULE_INIT(/* exports, module, context */) {
215  Isolate* isolate = context->GetIsolate();
216
217  // Create a new instance of `AddonData` for this instance of the addon and
218  // tie its life cycle to that of the Node.js environment.
219  AddonData* data = new AddonData(isolate);
220
221  // Wrap the data in a `v8::External` so we can pass it to the method we
222  // expose.
223  Local<External> external = External::New(isolate, data);
224
225  // Expose the method `Method` to JavaScript, and make sure it receives the
226  // per-addon-instance data we created above by passing `external` as the
227  // third parameter to the `FunctionTemplate` constructor.
228  exports->Set(context,
229               String::NewFromUtf8(isolate, "method", NewStringType::kNormal)
230                  .ToLocalChecked(),
231               FunctionTemplate::New(isolate, Method, external)
232                  ->GetFunction(context).ToLocalChecked()).FromJust();
233}
234```
235
236#### Worker support
237<!-- YAML
238changes:
239  - version: v12.19.0
240    pr-url: https://github.com/nodejs/node/pull/34572
241    description: Cleanup hooks may now be asynchronous.
242-->
243
244In order to be loaded from multiple Node.js environments,
245such as a main thread and a Worker thread, an add-on needs to either:
246
247* Be an N-API addon, or
248* Be declared as context-aware using `NODE_MODULE_INIT()` as described above
249
250In order to support [`Worker`][] threads, addons need to clean up any resources
251they may have allocated when such a thread exists. This can be achieved through
252the usage of the `AddEnvironmentCleanupHook()` function:
253
254```cpp
255void AddEnvironmentCleanupHook(v8::Isolate* isolate,
256                               void (*fun)(void* arg),
257                               void* arg);
258```
259
260This function adds a hook that will run before a given Node.js instance shuts
261down. If necessary, such hooks can be removed before they are run using
262`RemoveEnvironmentCleanupHook()`, which has the same signature. Callbacks are
263run in last-in first-out order.
264
265If necessary, there is an additional pair of `AddEnvironmentCleanupHook()`
266and `RemoveEnvironmentCleanupHook()` overloads, where the cleanup hook takes a
267callback function. This can be used for shutting down asynchronous resources,
268such as any libuv handles registered by the addon.
269
270The following `addon.cc` uses `AddEnvironmentCleanupHook`:
271
272```cpp
273// addon.cc
274#include <assert.h>
275#include <stdlib.h>
276#include <node.h>
277
278using node::AddEnvironmentCleanupHook;
279using v8::HandleScope;
280using v8::Isolate;
281using v8::Local;
282using v8::Object;
283
284// Note: In a real-world application, do not rely on static/global data.
285static char cookie[] = "yum yum";
286static int cleanup_cb1_called = 0;
287static int cleanup_cb2_called = 0;
288
289static void cleanup_cb1(void* arg) {
290  Isolate* isolate = static_cast<Isolate*>(arg);
291  HandleScope scope(isolate);
292  Local<Object> obj = Object::New(isolate);
293  assert(!obj.IsEmpty());  // assert VM is still alive
294  assert(obj->IsObject());
295  cleanup_cb1_called++;
296}
297
298static void cleanup_cb2(void* arg) {
299  assert(arg == static_cast<void*>(cookie));
300  cleanup_cb2_called++;
301}
302
303static void sanity_check(void*) {
304  assert(cleanup_cb1_called == 1);
305  assert(cleanup_cb2_called == 1);
306}
307
308// Initialize this addon to be context-aware.
309NODE_MODULE_INIT(/* exports, module, context */) {
310  Isolate* isolate = context->GetIsolate();
311
312  AddEnvironmentCleanupHook(isolate, sanity_check, nullptr);
313  AddEnvironmentCleanupHook(isolate, cleanup_cb2, cookie);
314  AddEnvironmentCleanupHook(isolate, cleanup_cb1, isolate);
315}
316```
317
318Test in JavaScript by running:
319
320```js
321// test.js
322require('./build/Release/addon');
323```
324
325### Building
326
327Once the source code has been written, it must be compiled into the binary
328`addon.node` file. To do so, create a file called `binding.gyp` in the
329top-level of the project describing the build configuration of the module
330using a JSON-like format. This file is used by [node-gyp][], a tool written
331specifically to compile Node.js addons.
332
333```json
334{
335  "targets": [
336    {
337      "target_name": "addon",
338      "sources": [ "hello.cc" ]
339    }
340  ]
341}
342```
343
344A version of the `node-gyp` utility is bundled and distributed with
345Node.js as part of `npm`. This version is not made directly available for
346developers to use and is intended only to support the ability to use the
347`npm install` command to compile and install addons. Developers who wish to
348use `node-gyp` directly can install it using the command
349`npm install -g node-gyp`. See the `node-gyp` [installation instructions][] for
350more information, including platform-specific requirements.
351
352Once the `binding.gyp` file has been created, use `node-gyp configure` to
353generate the appropriate project build files for the current platform. This
354will generate either a `Makefile` (on Unix platforms) or a `vcxproj` file
355(on Windows) in the `build/` directory.
356
357Next, invoke the `node-gyp build` command to generate the compiled `addon.node`
358file. This will be put into the `build/Release/` directory.
359
360When using `npm install` to install a Node.js addon, npm uses its own bundled
361version of `node-gyp` to perform this same set of actions, generating a
362compiled version of the addon for the user's platform on demand.
363
364Once built, the binary addon can be used from within Node.js by pointing
365[`require()`][require] to the built `addon.node` module:
366
367```js
368// hello.js
369const addon = require('./build/Release/addon');
370
371console.log(addon.hello());
372// Prints: 'world'
373```
374
375Because the exact path to the compiled addon binary can vary depending on how
376it is compiled (i.e. sometimes it may be in `./build/Debug/`), addons can use
377the [bindings][] package to load the compiled module.
378
379While the `bindings` package implementation is more sophisticated in how it
380locates addon modules, it is essentially using a `try…catch` pattern similar to:
381
382```js
383try {
384  return require('./build/Release/addon.node');
385} catch (err) {
386  return require('./build/Debug/addon.node');
387}
388```
389
390### Linking to libraries included with Node.js
391
392Node.js uses statically linked libraries such as V8, libuv and OpenSSL. All
393addons are required to link to V8 and may link to any of the other dependencies
394as well. Typically, this is as simple as including the appropriate
395`#include <...>` statements (e.g. `#include <v8.h>`) and `node-gyp` will locate
396the appropriate headers automatically. However, there are a few caveats to be
397aware of:
398
399* When `node-gyp` runs, it will detect the specific release version of Node.js
400and download either the full source tarball or just the headers. If the full
401source is downloaded, addons will have complete access to the full set of
402Node.js dependencies. However, if only the Node.js headers are downloaded, then
403only the symbols exported by Node.js will be available.
404
405* `node-gyp` can be run using the `--nodedir` flag pointing at a local Node.js
406source image. Using this option, the addon will have access to the full set of
407dependencies.
408
409### Loading addons using `require()`
410
411The filename extension of the compiled addon binary is `.node` (as opposed
412to `.dll` or `.so`). The [`require()`][require] function is written to look for
413files with the `.node` file extension and initialize those as dynamically-linked
414libraries.
415
416When calling [`require()`][require], the `.node` extension can usually be
417omitted and Node.js will still find and initialize the addon. One caveat,
418however, is that Node.js will first attempt to locate and load modules or
419JavaScript files that happen to share the same base name. For instance, if
420there is a file `addon.js` in the same directory as the binary `addon.node`,
421then [`require('addon')`][require] will give precedence to the `addon.js` file
422and load it instead.
423
424## Native abstractions for Node.js
425
426Each of the examples illustrated in this document directly use the
427Node.js and V8 APIs for implementing addons. The V8 API can, and has, changed
428dramatically from one V8 release to the next (and one major Node.js release to
429the next). With each change, addons may need to be updated and recompiled in
430order to continue functioning. The Node.js release schedule is designed to
431minimize the frequency and impact of such changes but there is little that
432Node.js can do to ensure stability of the V8 APIs.
433
434The [Native Abstractions for Node.js][] (or `nan`) provide a set of tools that
435addon developers are recommended to use to keep compatibility between past and
436future releases of V8 and Node.js. See the `nan` [examples][] for an
437illustration of how it can be used.
438
439## N-API
440
441> Stability: 2 - Stable
442
443N-API is an API for building native addons. It is independent from
444the underlying JavaScript runtime (e.g. V8) and is maintained as part of
445Node.js itself. This API will be Application Binary Interface (ABI) stable
446across versions of Node.js. It is intended to insulate addons from
447changes in the underlying JavaScript engine and allow modules
448compiled for one version to run on later versions of Node.js without
449recompilation. Addons are built/packaged with the same approach/tools
450outlined in this document (node-gyp, etc.). The only difference is the
451set of APIs that are used by the native code. Instead of using the V8
452or [Native Abstractions for Node.js][] APIs, the functions available
453in the N-API are used.
454
455Creating and maintaining an addon that benefits from the ABI stability
456provided by N-API carries with it certain
457[implementation considerations](n-api.html#n_api_implications_of_abi_stability).
458
459To use N-API in the above "Hello world" example, replace the content of
460`hello.cc` with the following. All other instructions remain the same.
461
462```cpp
463// hello.cc using N-API
464#include <node_api.h>
465
466namespace demo {
467
468napi_value Method(napi_env env, napi_callback_info args) {
469  napi_value greeting;
470  napi_status status;
471
472  status = napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &greeting);
473  if (status != napi_ok) return nullptr;
474  return greeting;
475}
476
477napi_value init(napi_env env, napi_value exports) {
478  napi_status status;
479  napi_value fn;
480
481  status = napi_create_function(env, nullptr, 0, Method, nullptr, &fn);
482  if (status != napi_ok) return nullptr;
483
484  status = napi_set_named_property(env, exports, "hello", fn);
485  if (status != napi_ok) return nullptr;
486  return exports;
487}
488
489NAPI_MODULE(NODE_GYP_MODULE_NAME, init)
490
491}  // namespace demo
492```
493
494The functions available and how to use them are documented in
495[C/C++ addons with N-API](n-api.html).
496
497## Addon examples
498
499Following are some example addons intended to help developers get started. The
500examples use the V8 APIs. Refer to the online [V8 reference][v8-docs]
501for help with the various V8 calls, and V8's [Embedder's Guide][] for an
502explanation of several concepts used such as handles, scopes, function
503templates, etc.
504
505Each of these examples using the following `binding.gyp` file:
506
507```json
508{
509  "targets": [
510    {
511      "target_name": "addon",
512      "sources": [ "addon.cc" ]
513    }
514  ]
515}
516```
517
518In cases where there is more than one `.cc` file, simply add the additional
519filename to the `sources` array:
520
521```json
522"sources": ["addon.cc", "myexample.cc"]
523```
524
525Once the `binding.gyp` file is ready, the example addons can be configured and
526built using `node-gyp`:
527
528```console
529$ node-gyp configure build
530```
531
532### Function arguments
533
534Addons will typically expose objects and functions that can be accessed from
535JavaScript running within Node.js. When functions are invoked from JavaScript,
536the input arguments and return value must be mapped to and from the C/C++
537code.
538
539The following example illustrates how to read function arguments passed from
540JavaScript and how to return a result:
541
542```cpp
543// addon.cc
544#include <node.h>
545
546namespace demo {
547
548using v8::Exception;
549using v8::FunctionCallbackInfo;
550using v8::Isolate;
551using v8::Local;
552using v8::NewStringType;
553using v8::Number;
554using v8::Object;
555using v8::String;
556using v8::Value;
557
558// This is the implementation of the "add" method
559// Input arguments are passed using the
560// const FunctionCallbackInfo<Value>& args struct
561void Add(const FunctionCallbackInfo<Value>& args) {
562  Isolate* isolate = args.GetIsolate();
563
564  // Check the number of arguments passed.
565  if (args.Length() < 2) {
566    // Throw an Error that is passed back to JavaScript
567    isolate->ThrowException(Exception::TypeError(
568        String::NewFromUtf8(isolate,
569                            "Wrong number of arguments",
570                            NewStringType::kNormal).ToLocalChecked()));
571    return;
572  }
573
574  // Check the argument types
575  if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
576    isolate->ThrowException(Exception::TypeError(
577        String::NewFromUtf8(isolate,
578                            "Wrong arguments",
579                            NewStringType::kNormal).ToLocalChecked()));
580    return;
581  }
582
583  // Perform the operation
584  double value =
585      args[0].As<Number>()->Value() + args[1].As<Number>()->Value();
586  Local<Number> num = Number::New(isolate, value);
587
588  // Set the return value (using the passed in
589  // FunctionCallbackInfo<Value>&)
590  args.GetReturnValue().Set(num);
591}
592
593void Init(Local<Object> exports) {
594  NODE_SET_METHOD(exports, "add", Add);
595}
596
597NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
598
599}  // namespace demo
600```
601
602Once compiled, the example addon can be required and used from within Node.js:
603
604```js
605// test.js
606const addon = require('./build/Release/addon');
607
608console.log('This should be eight:', addon.add(3, 5));
609```
610
611### Callbacks
612
613It is common practice within addons to pass JavaScript functions to a C++
614function and execute them from there. The following example illustrates how
615to invoke such callbacks:
616
617```cpp
618// addon.cc
619#include <node.h>
620
621namespace demo {
622
623using v8::Context;
624using v8::Function;
625using v8::FunctionCallbackInfo;
626using v8::Isolate;
627using v8::Local;
628using v8::NewStringType;
629using v8::Null;
630using v8::Object;
631using v8::String;
632using v8::Value;
633
634void RunCallback(const FunctionCallbackInfo<Value>& args) {
635  Isolate* isolate = args.GetIsolate();
636  Local<Context> context = isolate->GetCurrentContext();
637  Local<Function> cb = Local<Function>::Cast(args[0]);
638  const unsigned argc = 1;
639  Local<Value> argv[argc] = {
640      String::NewFromUtf8(isolate,
641                          "hello world",
642                          NewStringType::kNormal).ToLocalChecked() };
643  cb->Call(context, Null(isolate), argc, argv).ToLocalChecked();
644}
645
646void Init(Local<Object> exports, Local<Object> module) {
647  NODE_SET_METHOD(module, "exports", RunCallback);
648}
649
650NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
651
652}  // namespace demo
653```
654
655This example uses a two-argument form of `Init()` that receives the full
656`module` object as the second argument. This allows the addon to completely
657overwrite `exports` with a single function instead of adding the function as a
658property of `exports`.
659
660To test it, run the following JavaScript:
661
662```js
663// test.js
664const addon = require('./build/Release/addon');
665
666addon((msg) => {
667  console.log(msg);
668// Prints: 'hello world'
669});
670```
671
672In this example, the callback function is invoked synchronously.
673
674### Object factory
675
676Addons can create and return new objects from within a C++ function as
677illustrated in the following example. An object is created and returned with a
678property `msg` that echoes the string passed to `createObject()`:
679
680```cpp
681// addon.cc
682#include <node.h>
683
684namespace demo {
685
686using v8::Context;
687using v8::FunctionCallbackInfo;
688using v8::Isolate;
689using v8::Local;
690using v8::NewStringType;
691using v8::Object;
692using v8::String;
693using v8::Value;
694
695void CreateObject(const FunctionCallbackInfo<Value>& args) {
696  Isolate* isolate = args.GetIsolate();
697  Local<Context> context = isolate->GetCurrentContext();
698
699  Local<Object> obj = Object::New(isolate);
700  obj->Set(context,
701           String::NewFromUtf8(isolate,
702                               "msg",
703                               NewStringType::kNormal).ToLocalChecked(),
704                               args[0]->ToString(context).ToLocalChecked())
705           .FromJust();
706
707  args.GetReturnValue().Set(obj);
708}
709
710void Init(Local<Object> exports, Local<Object> module) {
711  NODE_SET_METHOD(module, "exports", CreateObject);
712}
713
714NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
715
716}  // namespace demo
717```
718
719To test it in JavaScript:
720
721```js
722// test.js
723const addon = require('./build/Release/addon');
724
725const obj1 = addon('hello');
726const obj2 = addon('world');
727console.log(obj1.msg, obj2.msg);
728// Prints: 'hello world'
729```
730
731### Function factory
732
733Another common scenario is creating JavaScript functions that wrap C++
734functions and returning those back to JavaScript:
735
736```cpp
737// addon.cc
738#include <node.h>
739
740namespace demo {
741
742using v8::Context;
743using v8::Function;
744using v8::FunctionCallbackInfo;
745using v8::FunctionTemplate;
746using v8::Isolate;
747using v8::Local;
748using v8::NewStringType;
749using v8::Object;
750using v8::String;
751using v8::Value;
752
753void MyFunction(const FunctionCallbackInfo<Value>& args) {
754  Isolate* isolate = args.GetIsolate();
755  args.GetReturnValue().Set(String::NewFromUtf8(
756      isolate, "hello world", NewStringType::kNormal).ToLocalChecked());
757}
758
759void CreateFunction(const FunctionCallbackInfo<Value>& args) {
760  Isolate* isolate = args.GetIsolate();
761
762  Local<Context> context = isolate->GetCurrentContext();
763  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
764  Local<Function> fn = tpl->GetFunction(context).ToLocalChecked();
765
766  // omit this to make it anonymous
767  fn->SetName(String::NewFromUtf8(
768      isolate, "theFunction", NewStringType::kNormal).ToLocalChecked());
769
770  args.GetReturnValue().Set(fn);
771}
772
773void Init(Local<Object> exports, Local<Object> module) {
774  NODE_SET_METHOD(module, "exports", CreateFunction);
775}
776
777NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
778
779}  // namespace demo
780```
781
782To test:
783
784```js
785// test.js
786const addon = require('./build/Release/addon');
787
788const fn = addon();
789console.log(fn());
790// Prints: 'hello world'
791```
792
793### Wrapping C++ objects
794
795It is also possible to wrap C++ objects/classes in a way that allows new
796instances to be created using the JavaScript `new` operator:
797
798```cpp
799// addon.cc
800#include <node.h>
801#include "myobject.h"
802
803namespace demo {
804
805using v8::Local;
806using v8::Object;
807
808void InitAll(Local<Object> exports) {
809  MyObject::Init(exports);
810}
811
812NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
813
814}  // namespace demo
815```
816
817Then, in `myobject.h`, the wrapper class inherits from `node::ObjectWrap`:
818
819```cpp
820// myobject.h
821#ifndef MYOBJECT_H
822#define MYOBJECT_H
823
824#include <node.h>
825#include <node_object_wrap.h>
826
827namespace demo {
828
829class MyObject : public node::ObjectWrap {
830 public:
831  static void Init(v8::Local<v8::Object> exports);
832
833 private:
834  explicit MyObject(double value = 0);
835  ~MyObject();
836
837  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
838  static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
839
840  double value_;
841};
842
843}  // namespace demo
844
845#endif
846```
847
848In `myobject.cc`, implement the various methods that are to be exposed.
849Below, the method `plusOne()` is exposed by adding it to the constructor's
850prototype:
851
852```cpp
853// myobject.cc
854#include "myobject.h"
855
856namespace demo {
857
858using v8::Context;
859using v8::Function;
860using v8::FunctionCallbackInfo;
861using v8::FunctionTemplate;
862using v8::Isolate;
863using v8::Local;
864using v8::NewStringType;
865using v8::Number;
866using v8::Object;
867using v8::ObjectTemplate;
868using v8::String;
869using v8::Value;
870
871MyObject::MyObject(double value) : value_(value) {
872}
873
874MyObject::~MyObject() {
875}
876
877void MyObject::Init(Local<Object> exports) {
878  Isolate* isolate = exports->GetIsolate();
879  Local<Context> context = isolate->GetCurrentContext();
880
881  Local<ObjectTemplate> addon_data_tpl = ObjectTemplate::New(isolate);
882  addon_data_tpl->SetInternalFieldCount(1);  // 1 field for the MyObject::New()
883  Local<Object> addon_data =
884      addon_data_tpl->NewInstance(context).ToLocalChecked();
885
886  // Prepare constructor template
887  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New, addon_data);
888  tpl->SetClassName(String::NewFromUtf8(
889      isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
890  tpl->InstanceTemplate()->SetInternalFieldCount(1);
891
892  // Prototype
893  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
894
895  Local<Function> constructor = tpl->GetFunction(context).ToLocalChecked();
896  addon_data->SetInternalField(0, constructor);
897  exports->Set(context, String::NewFromUtf8(
898      isolate, "MyObject", NewStringType::kNormal).ToLocalChecked(),
899               constructor).FromJust();
900}
901
902void MyObject::New(const FunctionCallbackInfo<Value>& args) {
903  Isolate* isolate = args.GetIsolate();
904  Local<Context> context = isolate->GetCurrentContext();
905
906  if (args.IsConstructCall()) {
907    // Invoked as constructor: `new MyObject(...)`
908    double value = args[0]->IsUndefined() ?
909        0 : args[0]->NumberValue(context).FromMaybe(0);
910    MyObject* obj = new MyObject(value);
911    obj->Wrap(args.This());
912    args.GetReturnValue().Set(args.This());
913  } else {
914    // Invoked as plain function `MyObject(...)`, turn into construct call.
915    const int argc = 1;
916    Local<Value> argv[argc] = { args[0] };
917    Local<Function> cons =
918        args.Data().As<Object>()->GetInternalField(0).As<Function>();
919    Local<Object> result =
920        cons->NewInstance(context, argc, argv).ToLocalChecked();
921    args.GetReturnValue().Set(result);
922  }
923}
924
925void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
926  Isolate* isolate = args.GetIsolate();
927
928  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
929  obj->value_ += 1;
930
931  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
932}
933
934}  // namespace demo
935```
936
937To build this example, the `myobject.cc` file must be added to the
938`binding.gyp`:
939
940```json
941{
942  "targets": [
943    {
944      "target_name": "addon",
945      "sources": [
946        "addon.cc",
947        "myobject.cc"
948      ]
949    }
950  ]
951}
952```
953
954Test it with:
955
956```js
957// test.js
958const addon = require('./build/Release/addon');
959
960const obj = new addon.MyObject(10);
961console.log(obj.plusOne());
962// Prints: 11
963console.log(obj.plusOne());
964// Prints: 12
965console.log(obj.plusOne());
966// Prints: 13
967```
968
969The destructor for a wrapper object will run when the object is
970garbage-collected. For destructor testing, there are command-line flags that
971can be used to make it possible to force garbage collection. These flags are
972provided by the underlying V8 JavaScript engine. They are subject to change
973or removal at any time. They are not documented by Node.js or V8, and they
974should never be used outside of testing.
975
976### Factory of wrapped objects
977
978Alternatively, it is possible to use a factory pattern to avoid explicitly
979creating object instances using the JavaScript `new` operator:
980
981```js
982const obj = addon.createObject();
983// instead of:
984// const obj = new addon.Object();
985```
986
987First, the `createObject()` method is implemented in `addon.cc`:
988
989```cpp
990// addon.cc
991#include <node.h>
992#include "myobject.h"
993
994namespace demo {
995
996using v8::FunctionCallbackInfo;
997using v8::Isolate;
998using v8::Local;
999using v8::Object;
1000using v8::String;
1001using v8::Value;
1002
1003void CreateObject(const FunctionCallbackInfo<Value>& args) {
1004  MyObject::NewInstance(args);
1005}
1006
1007void InitAll(Local<Object> exports, Local<Object> module) {
1008  MyObject::Init(exports->GetIsolate());
1009
1010  NODE_SET_METHOD(module, "exports", CreateObject);
1011}
1012
1013NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
1014
1015}  // namespace demo
1016```
1017
1018In `myobject.h`, the static method `NewInstance()` is added to handle
1019instantiating the object. This method takes the place of using `new` in
1020JavaScript:
1021
1022```cpp
1023// myobject.h
1024#ifndef MYOBJECT_H
1025#define MYOBJECT_H
1026
1027#include <node.h>
1028#include <node_object_wrap.h>
1029
1030namespace demo {
1031
1032class MyObject : public node::ObjectWrap {
1033 public:
1034  static void Init(v8::Isolate* isolate);
1035  static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
1036
1037 private:
1038  explicit MyObject(double value = 0);
1039  ~MyObject();
1040
1041  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
1042  static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
1043  static v8::Global<v8::Function> constructor;
1044  double value_;
1045};
1046
1047}  // namespace demo
1048
1049#endif
1050```
1051
1052The implementation in `myobject.cc` is similar to the previous example:
1053
1054```cpp
1055// myobject.cc
1056#include <node.h>
1057#include "myobject.h"
1058
1059namespace demo {
1060
1061using node::AddEnvironmentCleanupHook;
1062using v8::Context;
1063using v8::Function;
1064using v8::FunctionCallbackInfo;
1065using v8::FunctionTemplate;
1066using v8::Global;
1067using v8::Isolate;
1068using v8::Local;
1069using v8::NewStringType;
1070using v8::Number;
1071using v8::Object;
1072using v8::String;
1073using v8::Value;
1074
1075// Warning! This is not thread-safe, this addon cannot be used for worker
1076// threads.
1077Global<Function> MyObject::constructor;
1078
1079MyObject::MyObject(double value) : value_(value) {
1080}
1081
1082MyObject::~MyObject() {
1083}
1084
1085void MyObject::Init(Isolate* isolate) {
1086  // Prepare constructor template
1087  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
1088  tpl->SetClassName(String::NewFromUtf8(
1089      isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
1090  tpl->InstanceTemplate()->SetInternalFieldCount(1);
1091
1092  // Prototype
1093  NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
1094
1095  Local<Context> context = isolate->GetCurrentContext();
1096  constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1097
1098  AddEnvironmentCleanupHook(isolate, [](void*) {
1099    constructor.Reset();
1100  }, nullptr);
1101}
1102
1103void MyObject::New(const FunctionCallbackInfo<Value>& args) {
1104  Isolate* isolate = args.GetIsolate();
1105  Local<Context> context = isolate->GetCurrentContext();
1106
1107  if (args.IsConstructCall()) {
1108    // Invoked as constructor: `new MyObject(...)`
1109    double value = args[0]->IsUndefined() ?
1110        0 : args[0]->NumberValue(context).FromMaybe(0);
1111    MyObject* obj = new MyObject(value);
1112    obj->Wrap(args.This());
1113    args.GetReturnValue().Set(args.This());
1114  } else {
1115    // Invoked as plain function `MyObject(...)`, turn into construct call.
1116    const int argc = 1;
1117    Local<Value> argv[argc] = { args[0] };
1118    Local<Function> cons = Local<Function>::New(isolate, constructor);
1119    Local<Object> instance =
1120        cons->NewInstance(context, argc, argv).ToLocalChecked();
1121    args.GetReturnValue().Set(instance);
1122  }
1123}
1124
1125void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
1126  Isolate* isolate = args.GetIsolate();
1127
1128  const unsigned argc = 1;
1129  Local<Value> argv[argc] = { args[0] };
1130  Local<Function> cons = Local<Function>::New(isolate, constructor);
1131  Local<Context> context = isolate->GetCurrentContext();
1132  Local<Object> instance =
1133      cons->NewInstance(context, argc, argv).ToLocalChecked();
1134
1135  args.GetReturnValue().Set(instance);
1136}
1137
1138void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
1139  Isolate* isolate = args.GetIsolate();
1140
1141  MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
1142  obj->value_ += 1;
1143
1144  args.GetReturnValue().Set(Number::New(isolate, obj->value_));
1145}
1146
1147}  // namespace demo
1148```
1149
1150Once again, to build this example, the `myobject.cc` file must be added to the
1151`binding.gyp`:
1152
1153```json
1154{
1155  "targets": [
1156    {
1157      "target_name": "addon",
1158      "sources": [
1159        "addon.cc",
1160        "myobject.cc"
1161      ]
1162    }
1163  ]
1164}
1165```
1166
1167Test it with:
1168
1169```js
1170// test.js
1171const createObject = require('./build/Release/addon');
1172
1173const obj = createObject(10);
1174console.log(obj.plusOne());
1175// Prints: 11
1176console.log(obj.plusOne());
1177// Prints: 12
1178console.log(obj.plusOne());
1179// Prints: 13
1180
1181const obj2 = createObject(20);
1182console.log(obj2.plusOne());
1183// Prints: 21
1184console.log(obj2.plusOne());
1185// Prints: 22
1186console.log(obj2.plusOne());
1187// Prints: 23
1188```
1189
1190### Passing wrapped objects around
1191
1192In addition to wrapping and returning C++ objects, it is possible to pass
1193wrapped objects around by unwrapping them with the Node.js helper function
1194`node::ObjectWrap::Unwrap`. The following examples shows a function `add()`
1195that can take two `MyObject` objects as input arguments:
1196
1197```cpp
1198// addon.cc
1199#include <node.h>
1200#include <node_object_wrap.h>
1201#include "myobject.h"
1202
1203namespace demo {
1204
1205using v8::Context;
1206using v8::FunctionCallbackInfo;
1207using v8::Isolate;
1208using v8::Local;
1209using v8::Number;
1210using v8::Object;
1211using v8::String;
1212using v8::Value;
1213
1214void CreateObject(const FunctionCallbackInfo<Value>& args) {
1215  MyObject::NewInstance(args);
1216}
1217
1218void Add(const FunctionCallbackInfo<Value>& args) {
1219  Isolate* isolate = args.GetIsolate();
1220  Local<Context> context = isolate->GetCurrentContext();
1221
1222  MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
1223      args[0]->ToObject(context).ToLocalChecked());
1224  MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
1225      args[1]->ToObject(context).ToLocalChecked());
1226
1227  double sum = obj1->value() + obj2->value();
1228  args.GetReturnValue().Set(Number::New(isolate, sum));
1229}
1230
1231void InitAll(Local<Object> exports) {
1232  MyObject::Init(exports->GetIsolate());
1233
1234  NODE_SET_METHOD(exports, "createObject", CreateObject);
1235  NODE_SET_METHOD(exports, "add", Add);
1236}
1237
1238NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
1239
1240}  // namespace demo
1241```
1242
1243In `myobject.h`, a new public method is added to allow access to private values
1244after unwrapping the object.
1245
1246```cpp
1247// myobject.h
1248#ifndef MYOBJECT_H
1249#define MYOBJECT_H
1250
1251#include <node.h>
1252#include <node_object_wrap.h>
1253
1254namespace demo {
1255
1256class MyObject : public node::ObjectWrap {
1257 public:
1258  static void Init(v8::Isolate* isolate);
1259  static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
1260  inline double value() const { return value_; }
1261
1262 private:
1263  explicit MyObject(double value = 0);
1264  ~MyObject();
1265
1266  static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
1267  static v8::Global<v8::Function> constructor;
1268  double value_;
1269};
1270
1271}  // namespace demo
1272
1273#endif
1274```
1275
1276The implementation of `myobject.cc` is similar to before:
1277
1278```cpp
1279// myobject.cc
1280#include <node.h>
1281#include "myobject.h"
1282
1283namespace demo {
1284
1285using node::AddEnvironmentCleanupHook;
1286using v8::Context;
1287using v8::Function;
1288using v8::FunctionCallbackInfo;
1289using v8::FunctionTemplate;
1290using v8::Global;
1291using v8::Isolate;
1292using v8::Local;
1293using v8::NewStringType;
1294using v8::Object;
1295using v8::String;
1296using v8::Value;
1297
1298// Warning! This is not thread-safe, this addon cannot be used for worker
1299// threads.
1300Global<Function> MyObject::constructor;
1301
1302MyObject::MyObject(double value) : value_(value) {
1303}
1304
1305MyObject::~MyObject() {
1306}
1307
1308void MyObject::Init(Isolate* isolate) {
1309  // Prepare constructor template
1310  Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
1311  tpl->SetClassName(String::NewFromUtf8(
1312      isolate, "MyObject", NewStringType::kNormal).ToLocalChecked());
1313  tpl->InstanceTemplate()->SetInternalFieldCount(1);
1314
1315  Local<Context> context = isolate->GetCurrentContext();
1316  constructor.Reset(isolate, tpl->GetFunction(context).ToLocalChecked());
1317
1318  AddEnvironmentCleanupHook(isolate, [](void*) {
1319    constructor.Reset();
1320  }, nullptr);
1321}
1322
1323void MyObject::New(const FunctionCallbackInfo<Value>& args) {
1324  Isolate* isolate = args.GetIsolate();
1325  Local<Context> context = isolate->GetCurrentContext();
1326
1327  if (args.IsConstructCall()) {
1328    // Invoked as constructor: `new MyObject(...)`
1329    double value = args[0]->IsUndefined() ?
1330        0 : args[0]->NumberValue(context).FromMaybe(0);
1331    MyObject* obj = new MyObject(value);
1332    obj->Wrap(args.This());
1333    args.GetReturnValue().Set(args.This());
1334  } else {
1335    // Invoked as plain function `MyObject(...)`, turn into construct call.
1336    const int argc = 1;
1337    Local<Value> argv[argc] = { args[0] };
1338    Local<Function> cons = Local<Function>::New(isolate, constructor);
1339    Local<Object> instance =
1340        cons->NewInstance(context, argc, argv).ToLocalChecked();
1341    args.GetReturnValue().Set(instance);
1342  }
1343}
1344
1345void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
1346  Isolate* isolate = args.GetIsolate();
1347
1348  const unsigned argc = 1;
1349  Local<Value> argv[argc] = { args[0] };
1350  Local<Function> cons = Local<Function>::New(isolate, constructor);
1351  Local<Context> context = isolate->GetCurrentContext();
1352  Local<Object> instance =
1353      cons->NewInstance(context, argc, argv).ToLocalChecked();
1354
1355  args.GetReturnValue().Set(instance);
1356}
1357
1358}  // namespace demo
1359```
1360
1361Test it with:
1362
1363```js
1364// test.js
1365const addon = require('./build/Release/addon');
1366
1367const obj1 = addon.createObject(10);
1368const obj2 = addon.createObject(20);
1369const result = addon.add(obj1, obj2);
1370
1371console.log(result);
1372// Prints: 30
1373```
1374
1375[`Worker`]: worker_threads.html#worker_threads_class_worker
1376[Electron]: https://electronjs.org/
1377[Embedder's Guide]: https://github.com/v8/v8/wiki/Embedder's%20Guide
1378[Linking to libraries included with Node.js]: #addons_linking_to_libraries_included_with_node_js
1379[Native Abstractions for Node.js]: https://github.com/nodejs/nan
1380[bindings]: https://github.com/TooTallNate/node-bindings
1381[download]: https://github.com/nodejs/node-addon-examples
1382[examples]: https://github.com/nodejs/nan/tree/master/examples/
1383[installation instructions]: https://github.com/nodejs/node-gyp#installation
1384[libuv]: https://github.com/libuv/libuv
1385[node-gyp]: https://github.com/nodejs/node-gyp
1386[require]: modules.html#modules_require_id
1387[v8-docs]: https://v8docs.nodesource.com/
1388