首页 > 代码库 > Node.js C++ addon编写实战(一)之node-gyp
Node.js C++ addon编写实战(一)之node-gyp
http://deadhorse.me/nodejs/2012/10/08/c_addon_in_nodejs_node_gyp.html
这是一个三篇的系列文章,记录Node.js C++扩展开发中的一些经验与坑。
Node.js C++ addon编写实战(一)之node-gyp
Node.js C++ addon编写实战(二)之对象转换
Node.js C++ addon编写实战(三)之Buffer
补上第四篇:Node.js C++ addon编写实战(四)之兼容v0.11+与nan模块
从node-waf到node-gyp
node进入0.8版本之后,开始替换之前编译C++模块的编译工具,从node-waf向node-gyp转换,暂时是两者都支持,之后会不在支持node-waf编译。因此要写node的C++扩展,首先需要了解如何编写node-gyp的配置文件。
node-gyp的配置文件名字为binding.gyp,它是一个纯JSON对象,相对于node-waf的配置文件来说,写惯了javascript的同学会更加熟悉。
Hello node-gyp
先来看一个最简单的使用示例。
C模块部分提供了一个hello方法,返回一个字符串world:
#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) {
NODE_SET_METHOD(target, "hello", Method);
}
NODE_MODULE(binding, init);
binding.gyp指定C部分源文件路径和最终生成模块的名称,此例中将会生成一个可以被node调用的binding.node文件。
{
‘targets‘: [
{
‘target_name‘: ‘binding‘,
‘sources‘: [ ‘binding.cc‘ ]
}
]
}
js调用代码:
var assert = require(‘assert‘);
var binding = require(‘./build/Release/binding‘);
assert.equal(‘world‘, binding.hello());
console.log(‘binding.hello() =‘, binding.hello());
一个复杂一点的例子
在编写node-hsf的时候,由于涉及到第三方库的引入,以及对mac和linux的兼容,因此编译脚本会相对更加复杂。
{
‘targets‘: [
{
‘target_name‘: ‘hsfProtocol‘,
‘sources‘: [‘hsf_protocol.cc‘],
‘cflags‘: [‘-fexceptions‘, ‘-Wall‘, ‘-D_FILE_OFFSET_BITS=64‘,‘-D_LARGEFILE_SOURCE‘, ‘-O2‘], //编译选项
‘cflags_cc‘: [‘-fexceptions‘, ‘-Wall‘, ‘-D_FILE_OFFSET_BITS=64‘,‘-D_LARGEFILE_SOURCE‘, ‘-O2‘],
‘cflags!‘: [‘-fno-exceptions‘], //关闭的编译选项
‘cflags!_cc‘: [‘-fno-exceptions‘],
‘conditions‘: [
[‘OS=="mac"‘, { //满足此条件后开启
‘xcode_settings‘: {
‘GCC_ENABLE_CPP_EXCEPTIONS‘: ‘YES‘
}
}]
],
‘include_dirs‘: [ //引用第三方库的头文件路径
‘../hsf_protocol/utils‘,
‘../hsf_protocol/objects‘,
‘../hsf_protocol/hessian‘,
‘../hsf_protocol/hsf‘]
}
]
}
注意事项:
1. 如果遇到了exception handling disabled, use -fexceptions to enable错误,需要添加编译选项-fexceptions。如果还是不行,则可能是因为该版本的node-gyp默认启用了-fno-exceptions选项,因此通过cflags!和cflags!_cc中指定关闭掉这个默认开启的选项。
2. conditions内可以根据一些条件来添加选项,例如根据操作系统来添加一些编译条件。
3. 依赖的第三方动态链接库可能无法引入,出现这种情况可以把静态库和node-gyp生成的中间文件一起编译成最终的模块。
#!/bin/bash
HSFPROTOCOL_HOME="`pwd`/hsf_protocol"
SYSTEM=`uname -s`
EXTRA_FLAG="";
if [ $SYSTEM = "Darwin" ] ; then #判断是否是mac操作系统
# for mac
EXTRA_FLAG="-flat_namespace -undefined suppress"
echo ‘building for mac‘
fi
node-gyp configure build
gcc -fcc1-exceptions -fexceptions -O2 -o hsfProtocol.node ./build/Release/obj.target/hsfProtocol/hsf_protocol.o \
$HSFPROTOCOL_HOME/libhsf.a -shared -fPic $EXTRA_FLAG
可以看到在上面脚本中,把node-gyp生成的中间文件hsf_protocol.o与静态库libhsf.a编译成最终的hsfProtocol.node。为了进行跨平台的编译,如果是mac操作系统,则需要多添加-flat_namespace -undefined suppress这几个编译选项。
关于node-gyp的一些其他参考资料和范例和更复杂的用法,请查阅node-gyp in github。