必备工具:VC 2010 (嫌太大Express版即可),Python
NodeJS完成windows上加载扩展功能很久了,一直懒得去试。过年闲得无聊尝试了一把,顺便试了下gyp编译,确实比node-waf好用得多。
首先从node_source\test\addons\hello-world下把3个文件copy出来,放入新的目录,同时把编译出来的node.lib也放入那个目录
然后修改binding.gyp如下,红色部分为新增内容
{
'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ],
'libraries': ['-lnode.lib']
}
]
}
另外还要改一下binding.cc,同样红色部分为新增内容:
extern "C" {
NODE_MODULE_EXPORT void init(Handle<Object> target);
}
下一步可以使用gyp生成VC项目文件:
python node_source\tools\gyp_addon binding.gyp
接下来要设置一下VC的环境变量,命令行下找到如下路径:Microsoft Visual Studio 10.0\VC\vcvarsall.bat
执行完后会有提示:
Setting environment for using Microsoft Visual Studio 2010 x86 tools.
这样就可以继续下一步操作了,命令行输入:
msbuild binding.sln
一切顺利的话可以在Debug目录下找到我们想要的binding.node,那么测试一下吧,同样的,改一下
test.js:
var binding = require('./out/Release/binding');
改为
var binding = require('./Debug/binding');
在命令行输入node test.js,顺利得到输出:
binding.hello() = world
到这里模块编译就完成了。
然后我开始解释增加NODE_MODULE_EXPORT的原因。
首先加载模块涉及的是Module.js里加载.node扩展时调用的代码:
Module._extensions['.node'] = function(module, filename) {
process.dlopen(filename, module.exports);
};
实际调用了Node.cc中的 Handle<Value> DLOpen(const v8::Arguments& args)
成功加载扩展后会查找导出的init函数绑定到mod->register_func
uv_dlsym(lib, "init", reinterpret_cast<void**>(&mod->register_func));
确定模块版本和node版本一致后调用 mod->register_func(target);
// init
如果没有导出init函数,node会报如下错误: Error: unknown error
at Object..node (module.js:463:11)
至于检查是否导出了init函数,可以用VC提供的dumpbin工具:dumpbin /EXPORTS binding.node|find "init"
如果没有内容输出,就代表没有导出,成功导出的话就可以看到类似输出:
123 7A 00001334 init = @ILT+815(_init)
'libraries': ['-lnode.lib']
那一句是为了在连接时加上node.lib,不然会报很多unresolved external symbol的错误,这里可以把路径直接写为node编译出来的路径,这样就省去了反复copy新的node.lib的麻烦
markdown貌似没找到更改颜色的…我在原文中都标了不同的颜色突出重点 原文连接:http://hi.baidu.com/%E8%99%AB%E7%9A%84%E4%BC%A0%E4%BA%BA/blog/item/fa34afdcf9ab53bfcd1166b7.html