Skip to main content

node-addon-api


Installation

curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - \
&& sudo apt-get install -y nodejs
mkdir test \
&& cd test \
&& npm init
sudo npm install -g node-gyp
npm install node-addon-api

Setup

<package>
├── binding.gyp
├── index.js
├── node_modules
│ └── node-addon-api
│ └── ...
├── package.json
├── package-lock.json
├── test
│ └── ...
├── .clang-format
└── c_src
├── funcs.cpp
├── funcs.h
├── funcs_wrapper.cpp
├── funcs_wrapper.h
└── <target>.cpp

package.json

package.json
{
"name": "<package>",

# ...

"gypfile": true,

# ...

"scripts": {
"install": "node-gyp rebuild",
"build": "node-gyp rebuild --verbose",
"clean": "node-gyp clean",
"cf": "clang-format -style=file -i -verbose c_src/*"
},

# ...

"dependencies": {
"node-addon-api": "*",
},

# ...
}

binding.gyp

binding.gyp
{
"targets": [
{
"target_name": "<target>",
"include_dirs": ["<!@(node -p \"require('node-addon-api').include\")"],
"dependencies": ["<!(node -p \"require('node-addon-api').gyp\")"],
"cflags!": ["-fno-exceptions"],
"cflags_cc!": ["-fno-exceptions"],
"cflags": [],
"cflags_cc": [],
"defines": [],
"sources": [
"c_src/funcs.cpp",
"c_src/funcs.h",
"c_src/funcs_wrapper.cpp",
"c_src/funcs_wrapper.h",
"c_src/<target>.cpp",
],
"libraries": [
# "/usr/lib/libxxx.so"
]
}
]
}
caution

target_name에 '-' 등은 들어갈 수 없습니다.

index.js
module.exports = require('./build/Release/<target>');

Wrapper

c_src/funcs.h
#pragma once

#include <string>

std::string hello(void);
int add(int a, int b);
c_src/funcs.cpp
#include "funcs.h"

std::string hello(void) { return "Hello World!"; }

int add(int a, int b) { return a + b; }
c_src/funcs_wrapper.h
#pragma once

#include <napi.h>

Napi::Object init_funcs(Napi::Env env, Napi::Object exports);

Napi::String hello_wrapper(const Napi::CallbackInfo &info);
Napi::Number add_wrapper(const Napi::CallbackInfo &info);
c_src/funcs_wrapper.cpp
#include "funcs.h"
#include "funcs_wrapper.h"

Napi::Object init_funcs(Napi::Env env, Napi::Object exports) {
exports.Set("hello", Napi::Function::New(env, hello_wrapper));
exports.Set("add", Napi::Function::New(env, add_wrapper));

return exports;
}

Napi::String hello_wrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();

return Napi::String::New(env, hello());
}

Napi::Number add_wrapper(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();

if(info.Length() < 2 || ! info[0].IsNumber() || ! info[1].IsNumber()) {
Napi::TypeError::New(env,
"Arguments must be (int a, int b) such as (1, 2).")
.ThrowAsJavaScriptException();
}

// Implicit type conversion
int a = info[0].As<Napi::Number>();
int b = info[1].As<Napi::Number>();

return Napi::Number::New(env, add(a, b));
}
c_src/<target>.cpp
#include "funcs_wrapper.h"

#include <napi.h>

Napi::Object init_all(Napi::Env env, Napi::Object exports) {
return init_funcs(env, exports);
}

NODE_API_MODULE(NODE_GYP_MODULE_NAME, init_all)

Build

npm run build

Test

test/test.js
const addon = require('../build/Release/<target>');

console.log('wrapper info', addon);

console.log(addon.hello());
console.log(addon.add(1, 2));
$ node test/test.js
wrapper info { hello: [Function], add: [Function] }
Hello World!
3

Reference