Addons
扩展插件(Addons)是动态链接的共享对象,这些对象提供了使用C/C++类库的能力。由于涉及了多个类库导致了这类API目前比较繁杂,主要包括下述几个主要类库:
-
V8 JavaScript,C++类库,作为JavaScript的接口类,主要用于创建对象、调用方法等功能。大部分功能在头文件v8.h (在node文件夹下的路径为deps/v8/include/v8.h)中有详细文档。
-
libuv 基于C的事件循环库,当需要等待的文件描述符可读时,等待定时器,或者等到接受信号时,会调用libuv的接口,也可以说,任何I/O操作,都需要调用libuv库
-
内部Node的库,可以通过node::ObjectWrap来调用Node.js内部的库。
-
其他的一些类库同样可以在deps/ 中找到。
Node已将所有依赖关系静态地编译成可执行文件,因此我们在编译自己的组件时不需要担心和这些类库的链接问题。
Hello world
让我们着手编写一个Addon的小例子,来达到如下模块同样的效果:
1
2 1module.exports.hello = function() { return 'world'; };
2
首先,我们需要新建一个hello.cc文件
1
2
3
4
5
6
7
8
9
10
11
12
13 1#include <node.h>
2#include <v8.h>
3using namespace v8;
4Handle<Value> Method(const Arguments& args) {
5 HandleScope scope;
6 return scope.Close(String::New("world"));
7}
8void init(Handle<Object> exports) {
9 exports->Set(String::NewSymbol("hello"),
10 FunctionTemplate::New(Method)->GetFunction());
11}
12NODE_MODULE(hello, init)
13
请注意:所有的Node Addons 必须通过以下初始化代码导出
1
2
3 1void Initialize (Handle<Object> exports);
2NODE_MODULE(module_name, Initialize)
3
NODE_MODULE 结尾没有带上分号,因为它不是一个函数(详细可以看node.h)
module_name 是最终生成的二进制模块文件名称
代码将会被编译成hello.node,Addon的二进制文件,在这之前,需要创建一个叫binding.gyp的json格式文件来配置node-gyp进行编译。
1
2
3
4
5
6
7
8
9 1{
2 "targets": [
3 {
4 "target_name": "hello",
5 "sources": [ "hello.cc" ]
6 }
7 ]
8}
9
执行node-gyp configure生成合适的当前平台的工程建设文件。不需要传统的Makefile或vcxproj。
执行node-gyp build编译项目,生成.node文件,编译生成的目录在 build/Release/
编译成功后,可以在node.js项目中进行调用,创建hello.js文件通过require函数调用刚编译完的hello.node模块。
1
2
3 1var addon = require('./build/Release/hello');
2console.log(addon.hello()); // 'world'
3