一起读nodejs(四)----插件(addons)
因本人没有c++编译环境,故下面代码没有做测试.
插件(Addons)
插件是动态被连接到共享的对象.他们可以提供一种c和c++类库结合的能力.Api(目前)还是想当复杂,包括几个类库的知识:
V8 javascript 引擎,一个c++类库.用于和javascript连接接口:创建对象,调用方法,等等.在弄的源码目录树中的dpes/v8/include/v8.h文件中做了说明,也可以在线查看.
libuv,c的事件循环库.在任何时间,一个需要等待一个文件描述符变成可读的事件,等待一个定时器,或者等待一个信号来接受都需要使用libux.就是这样,如果你需要i/o操作,你就需要使用libux.
internal node libraries,node核心库,大部分很重要的库都是node::ObjectWrap的类,方便有调用.
others.可以在deps下查看其他可见的库.
node总是静态的编译所有的依赖到可执行文件.当编译你的模块时,你不需要担心的连接到任何地方的libs.
Hello World
作为开始,让我们来制作一个小插件,下面的代码是和c++等价的js代码:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">exports.hello = function() { return 'world'; };</SPAN>
exports.hello = function() { return 'world'; };首先我们来创建一个hello.cc:[cpp] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#include <node.h>
#include <v8.h>
using namespace v8;
Handle<Value> Method(const Arguments& args) {
HandleScope scope;
return scope.Close(String::New("world"));
}
void init(Handle<Object> target) {
target->Set(String::NewSymbol("hello"),
FunctionTemplate::New(Method)->GetFunction());
}
NODE_MODULE(hello, init)</SPAN>
#include <node.h>
#include <v8.h>
using namespace v8;
Handle<Value> Method(const Arguments& args) {
HandleScope scope;
return scope.Close(String::New("world"));
}
void init(Handle<Object> target) {
target->Set(String::NewSymbol("hello"),
FunctionTemplate::New(Method)->GetFunction());
}
NODE_MODULE(hello, init) 注意,所有的模块插件必须导出一个初始化的方法:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">void Initialize (Handle<Object> target);
NODE_MODULE(module_name, Initialize)</SPAN>
void Initialize (Handle<Object> target);
NODE_MODULE(module_name, Initialize) 因为NODE_MODULE不是一个函数,所以它后面没有分号.(参见hello.h).
module_name必须要匹配除去node后缀的文件名.
源代码需要被编译成hello.node,二进制插件.为了这么做我们创建一个叫做binding.gyp的文件,它描述了如何把你的模块编译称类似json格式的配置信息.这个文件将会被node-gyp编译成:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">{
"targets": [
{
"target_name": "hello",
"sources": [ "hello.cc" ]
}
]
}</SPAN>
{
"targets": [
{
"target_name": "hello",
"sources": [ "hello.cc" ]
}
]
} 下一步是生成适合当前平台的build文件,用node-gyp configure来做.
现在你会build目录下发现一个makefile(在unix平台上)或者一个vcxproj文件(在windows上).下一步调用node-gyp build 命令.
现在你已经有了编译后的.node易做图文件.这些易做图文件被放在build/release目录下.
现在你就可以在node项目hello.js中通过require指向刚刚创建的hello.nod二进制模块插件:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">var addon = require('./build/Release/hello');
console.log(addon.hello()); // 'world'</SPAN>
var addon = require('./build/Release/hello');
console.log(addon.hello()); // 'world' 更深入的了解可以参考下面的patterns部分,或者https://github.com/arturadib/node-qt提供了一个产品例子.
插件模型(Addon patterns)
下面的一些插件模型,可以在你开始学习插件模型时提供帮助.可以通过查阅在线的v8 reference来获取关于多样的v8调用的相关帮助,从v8的 Embedder's Guide中获取对一些概念的使用例如:handles,scopes,function,templates等的解释说明.
为了使用这些例子,你需要使用node-gyp去编译他们,创建下面的binding.gyp文件:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">{
"targets": [
{
"target_name": "addon",
"sources": [ "addon.cc" ]
}
]
}</SPAN>
{
"targets": [
{
"target_name": "addon",
"sources": [ "addon.cc" ]
}
]
}在不止一个.cc文件的情况下,只需要简单的添加文件名称到source变量数组中即可,例如:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">"sources": ["addon.cc", "myexample.cc"]</SPAN>
"sources": ["addon.cc", "myexample.cc"]现在你的binding.gyp已经就绪,你可以配置和创建插件了:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">$ node-gyp configure build</SPAN>
$ node-gyp configure build
方法参数(Function arguments)
下面的模型阐述了如何从javascript函数调用中读取参数和返回一个结果.这是大体内容,而亲仅仅只是需要addon.cc而已:[javascript] view plaincopyprint?
<SPAN style="FONT-SIZE: 18px; FONT-FAMILY: FangSong_GB2312">#define BUILDING_NODE_EXTENSION
#include <node.h>
using namespace v8;
Handle<Value> Add(const Arguments& args) {
HandleScope scope;
if (args.Length() < 2) {
ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
return scope.Close(Undefined());
}
if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
ThrowException(Exception::TypeError(String::New("Wrong arguments")));
return scope.Close(Undefined());
}
Local<Number> num = Number::New(args[0]->NumberValue() +
args[1]->NumberValue());
return scope.Close(num);
}
void Init(Handle<Object> target) {
targ
补充:web前端 , JavaScript ,