Node.js에 따르면,
Node.js 애드온은 C++에 의해 작성된 동적 링크 공유 객체로, require() 함수를 사용하여 Node.js로 불러올 수 있으며 일반 Node.js 모듈처럼 사용할 수 있습니다. 이 애드온은 C/C++ 라이브러리와 Node.js에서 작동하는 자바스크립트 간의 인터페이스를 제공합니다. |
nodejs 애드온을 사용하는 이유는 크게 다음과 같습니다.
1. JS 스스로 사용하기 어려운 네이티브 api들에 접근하고 싶을 때
2. C/C++에서 작성된 서드 파티 라이브러리와 통합하고 싶고, 이를 Node.js에서 직접 사용하고 싶을 때
3. 성능 이슈로 인해 C++ 모듈로 재작성하고 싶을 때
이 글에서는 N-API에 대해 설명하고 C/C++ 기반의 NodeJS 애드온을 구축하기 위한 사용법에 대해 설명합니다.
전체 소스코드는 https://github.com/master-atul/blog-addons-example 에서 확인할 수 있습니다.
N-API는 무엇인가?
N-API는 네이티브 애드온을 빌드하기 위한 API입니다. N-API는 자바스크립트 런타임으로부터 독립적입니다 (예: V8). 그리고 Node.js의 일부로 유지됩니다. 이 API는 ABI로 작동되어 모든 Node.js 버전에 안정성을 제공합니다. 또한, 자바스크립트 엔진의 변화로부터 안정성을 제공하도록 설계되었으며, 재컴파일 없이 Node.js의 다른 버전에서도 정상적으로 작동할 수 있도록 합니다.
ABI란? 응용프로그램과 운영체제, 응용 프로그램과 라이브러리 사이에 필요한 저수준 인터페이스. API와 유사하지만 API보다 ABI가 저수준으로, API는 소스코드에서 사용되고, ABI는 바이너리에서 호환이 됩니다. |
본질적으로, N-API는 C 또는 C++를 사용하여 NodeJS 애드온을 빌드할 수 있도록 해주고 이를 통해 빌드한 애드온은 NodeJS의 다른 버전, 환경에서 비정상 작동을 하지 않습니다.
N-API는 Node v10의 안정적인 API입니다. N-API는 Node v8과 v9에서 실험중인 기능이었습니다.
우리는 node-addon-api패키지를 사용할 것입니다. (https://github.com/nodejs/node-addon-api) 이는 N-API를 위한 헤더만 존재하는 C++ 래퍼 클래스들을 포함하는 패키지입니다. (기본적으로, C++ 오브젝트 모델을 제공하고 낮은 오버헤드에서 예외 처리 구문을 제공합니다.)
코딩 해보기
1. 명령 프롬프트를 관리자 권한으로 열어줍니다.
2. yarn이 설치되지 않았다면 "npm install -g yarn"으로 yarn을 글로벌 모드로 설치합니다.
3. "yarn global add windows-build-tools"로 윈도우 빌드 도구를 설치합니다. (npm은 비정상 작동됨)
4. 프로젝트 용 폴더를 생성한 후에 터미널에서 해당 폴더로 이동한 후 npm init으로 프로젝트를 초기화 해줍니다.
5. package.json에 "gypfile": true 를 추가해줍니다.
6. binding.gyp 파일을 생성한 후에 다음과 같이 입력합니다.
{
"targets": [
{
"target_name": "hello",
"sources": [ "hello.cc" ]
}
]
}
7. 터미널에 "npm install -g node-gyp"로 node-gyp 모듈을 글로벌 모드로 설치합니다.
8. 터미널에 "npm install --save bindings"로 바인딩 모듈을 설치합니다. (모듈을 쉽게 불러올 수 있음)
9. hello.cc 파일을 생성한 후에 다음과 같이 입력합니다.
#include <node_api.h>
#include <assert.h>
napi_value Method(napi_env env, napi_callback_info info) {
napi_status status;
napi_value world;
status = napi_create_string_utf8(env, "world", 5, &world);
assert(status == napi_ok);
return world;
}
#define DECLARE_NAPI_METHOD(name, func) \
{ name, 0, func, 0, 0, 0, napi_default, 0 }
napi_value Init(napi_env env, napi_value exports) {
napi_status status;
napi_property_descriptor desc = DECLARE_NAPI_METHOD("hello", Method); //INFO: 메소드 정의
status = napi_define_properties(env, exports, 1, &desc);
assert(status == napi_ok);
return exports;
}
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
10. hello.js 파일을 생성한 후에 다음과 같이 입력합니다.
var addon = require('bindings')('hello');
console.log(addon.hello()); // 'world'
11. 터미널에 "node-gyp configure"를 입력하여 빌드 환경을 구성합니다. build 폴더가 생성된 것을 확인할 수 있습니다.
12. package.json은 다음과 같은 내용을 담아야 합니다. (필수: private-> 미연에 퍼블리싱 방지, gypfile)
{
"name": "example_n-api",
"version": "1.0.0",
"description": "",
"main": "hello.js",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"gypfile": true,
"license": "ISC",
"dependencies": {
"bindings": "^1.5.0"
}
}
13. 터미널에 "node-gyp build"를 입력하면 build/Release/에 hello.node 파일이 생성된 것을 확인할 수 있습니다.
14. 터미널에서 "node ./hello.js"를 입력하면 hello.node 파일이 호출되어 world 라는 내용을 출력합니다.
15. 추가적으로, 실행 파일에서 .node 파일을 실행하는 것을 확인하기 위해 "npm install -g pkg"를 입력하여 pkg를 설치합니다.
16. 패키징을 하기 위해 package.json에 다음과 같은 내용을 추가합니다. (node는 10버전일 경우를 가정하였습니다.)
{
scripts": {
"pkg-win-x64": "pkg . --targets node10-win-x64 --output ./build/app.exe"
},
"bin": {
"app": "./hello.js"
},
}
17. 터미널에 "npm run pkg-win-x64"를 입력하여 패키징을 수행합니다. 결과적으로 build 폴더에 app.exe 파일이 생성된 것을 확인할 수 있습니다.
18. build/Release 폴더 내의 hello.node를 build 폴더로 복사한 후에 (복사 안해도 됨) 터미널에서 ./app.exe를 실행하면 world가 출력되는 것을 확인할 수 있습니다.
N-API에 대한 자세한 정보는 https://nodejs.org/api/n-api.html 를 참조하세요.
p.s. 현재 N-API의 C++ 래핑 버전인 Node-Addon-API도 테스트 해보았는데, 파이썬 인코딩 문제로 빌드가 되지 않고 있습니다.
예제: https://github.com/nodejs/node-addon-examples
'컴퓨터 공학 > JavaScript' 카테고리의 다른 글
[초간단] Visual Studio Code에서 Vue.js 설치하기 (0) | 2019.11.14 |
---|---|
Node.js UTF-8 데이터 CSV 파일 저장시 한글 깨짐 문제 (0) | 2019.11.14 |
Vue.js에서 라우터 URI에 파라미터 전달하기 (0) | 2019.04.14 |
Electron-vue 관련 링크 모음 (1) | 2019.04.12 |
[단순코드] Node.js 로거 모듈 winston/winston-daily-rotate-file 초기화 (0) | 2019.04.06 |