검색결과 리스트
add-on에 해당되는 글 1건
- 2012.09.26 [펌] nodejs(V8) C/C++ Add-on 작성 관련(in Windows) (4)
원본은 http://namoda.springnote.com/pages/11493094 입니다.
스프링노트가 종료 예정이라서 부득불하게 글을 가져왔습니다 -_-;;;;;;
윤인성님이 지은 '모던 웹을 위한 Node.js 프로그래밍'책을 보다가
부록C에 있는 바이너리 모듈 부분을 보다가 '이번 장에서 다루는 내용은 윈도에서 작업이 불가능합니다'라는 글이 있었다.
왜 윈도우는 안될까?라는 생각을 하면서 뭔가 방법이 있을 것 같아서 찾아봤다.
이 글 아래에 있는 아르헨티나에 있는 Javier Santo Domingo님이 잘 정리한 내용을 참고해서 다시 정리합니다.
Add-on은 동적으로 링크되는 공유 오브젝트라고 보시면 됩니다. 유닉스 계열에서는 .so라이브러리라고 보시면 될 것 같고, 윈도우에서는 .dll 라이브러리라고 생각하시면 되겠습니다.
자세한 것은 송형주 님이 번역하신 Node.js 도움말 번역 – C/C++ Add-on 작성 관련 이나 Rhio.Kim님의 C++ Addon with Node.js를 보시면 좋을 것 같습니다. node.js extensionswith C++ and V8 (Konstantin Käfer)
또한 구글의 V8에 대해 알고 있으면 도움이 됩니다.
또한, node.js Manual & Documentation의 Addons를 참고하시면 됩니다.
윈도우는 DLL지옥이라는 말이 있을 정도로 운영체제가 철저하게 DLL을 기반으로 동작합니다.
일례로 프로세스를 생성할 때도 kernel32.dll안에 있는 함수를 이용해야 합니다.
node.js 확장코드 역시 dll을 기반으로 확장할 수 있습니다.(장점인지 단점인지...)
물론 C코드와 DLL이 어떻게 동작하는지 안다고 가정하고 씁니다. 모를 경우에는 제프리리처의 Windows C/C++를 보시길 권장합니다.
#include <v8.h>
using namespace v8;
#pragma comment(lib, "node.lib")
extern "C" void NODE_EXTERN init (Handle<Object> target)
{
HandleScope scope;
target->Set(String::New("hello"), String::New("world"));
}
(class 'v8::Persistent<T>' needs to have dll-interface to be used by clients of class 'node::ObjectWrap')
1> with
1> [
1> T=v8::Object
1> ]
첫 번째 코드는 단순히 모듈의 hello라는 세터에 대해 "world"라는 문자열을 반환하게 했다.
이번에는 hello라는 함수로 바꾸어 봅시다.
hellonodejs.cpp (이름을 helloaddon 등으로 했어야 하는데.. 바꾸자니 또 뭐하고..)
using namespace v8;
#pragma comment(lib, "node.lib")
Handle<Value> Method(const Arguments& args) {
HandleScope scope;
return scope.Close(String::New("world"));
}
void init(Handle<Object> target) {
NODE_SET_METHOD(target, "hello", Method);
}
NODE_MODULE(hellonodejs, init)
이번에 실행을 해보면 .hello라고 치면 문자열이 나오는 것이 아니라 함수라고 [Function]이라는 반환이 나온다.
함수는 괄호로 이용해서 실행을 해야하지..
자바스크립트의 한계를 넘어서 윈도우 API를 사용할 수 있다는 것입니다.
샘플로 현재 시간을 출력하는 함수를 만들어보겠습니다. 물론 자바스크립트에는 Date라는 객체가 있어서 날짜를 가져올 수 있습니다만,
윈도우 API중에 GetLocalTime이라는 함수를 모듈화 해보겠습니다.
hellonodejs.cpp (아래 굵은 부분이 추가)
윈도우 API 함수의 선언이 포함되어 있는 windows.h를 우선 include하고, Now라는 핸들러 함수를 만들었습니다.
#include <node.h>
using namespace v8;
#pragma comment(lib, "node.lib")
#include <Windows.h>
Handle<Value> Method(const Arguments& args) {
HandleScope scope;
return scope.Close(String::New("world"));
}
Handle<Value> Now(const Arguments& args) {
const int SizeBuf = 25;
SYSTEMTIME st;
GetLocalTime(&st);
char szTime[SizeBuf];
sprintf_s(szTime, SizeBuf, "%d-%02d-%02d %02d:%02d:%02d.%03d",
st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
return scope.Close(String::New(szTime));
}
void init(Handle<Object> target) {
NODE_SET_METHOD(target, "hello", Method);
NODE_SET_METHOD(target, "now", Now);
}
NODE_MODULE(hellonodejs, init)
실행해보면,,,
현재 시간을 가지고 있는 문자열을 찍어줍니다. JSON 형태로 반환하게 하는 것이 좋을지도 모르겠습니다.
이상으로 제가 쓰는 글은 마치고, 윈도우에서 C/C++ 애드온을 방법을 알려준 하비에르씨의 글을 아래 적습니다.
(번역 by 나모)
tistory : C++ Addon with Node.js [PDF]
=> Writing Native Extension for Node
=> waf (The meta build system) : http://code.google.com/p/waf/
slideshare : Writing native bindings to node.js in C++
Olivier Lalonde's blog : How to write your own native Node.js extension
> git clone git://github.com/olalonde/node-notify.git
> npm install notify
node.js 비동기 addon작성
윈도우의 콜백을 node.js에서 사용하기 위해서 addon으로 구현하고 있었다.
문제는 아래와 같이 작성하면, 아에 블록이 되어 버린다는 것이다.
HandleScope scope;
if(!args[0]->IsFunction()) {
return scope.Close(Undefined());
}
Local<Function> cb = Local<Function>::Cast(args[0]);
const unsigned argc = 1;
Local<Value> argv[1] = { Local<Value>::New(String::New("hello world")) };
Sleep(10000); // 뭔가오래걸리는작업
cb->Call(Context::GetCurrent()->Global(), argc, argv);
return scope.Close(Undefined());
}
여러가지 방법을 찾아보았는데 비동기 함수 콜백을 위해서는 libuv의 uv_queue_work를 이용하면 가능했다.
바톤이라는 구조체를 이용해서 오래걸리는 작업(블록이 되는)을 시작, 끝 함수 포인터를 지정해서 큐에 넣는 식이었다.
아래 소스코드에서 AsyncWork, AsyncAfter 가 오래걸리는 작업, 작업 후에 정리하는 함수의 이름이다.
또한 Baton 이라는 구조체가 중간에 매개가 되는 변수이다.
HandleScope scope;
if (!args[0]->IsFunction()) {
return ThrowException(Exception::TypeError(
String::New("Callback function required")));
}
Local<Function> callback = Local<Function>::Cast(args[0]);
Baton* baton = new Baton();
baton->request.data = baton;
baton->callback = Persistent<Function>::New(callback);
uv_queue_work(uv_default_loop(), &baton->request, AsyncWork, AsyncAfter);
return scope.Close(Undefined());
}
include하는 라이브러리중에 #include <uv.h> 가 바로 그것이다!
Writing native bindings to node.js in C++ 슬라이드의 28쪽이나
node.js extensionswith C++ and V8 슬라이드의 여기를 보면된다. (참고로 여기는 좌우 화살표로 슬라이드 조절이 된다)
댓글
잘 봤습니다~
잘 가져왔어요.. 스프링 노트 백업은 해서 html 파일로 작성한 글을 가지고는 있는데 웹상에 나눌 수 없었는데 누군가 갈무리를 하셨군요. 나모의 노트의 나모입니다.
넵 공유해 주셔서 고맙습니다^^
많은 도움이 됬습니다. 공유해주셔서 정말 감사합니다~