您的位置:首页 > Web前端 > Node.js

node中javascript调用c++实现过程分析

2014-10-21 10:59 549 查看
先做这样的约定,node提供的模块,称为核心模块。用户编写的模块,称为文件模块。Node中那些由纯c/c++编写的模块称为内建模块。Node中buffer crypto evals fs os 等都是部分通过c/c++编写的。

内建模块内部的数据结构

struct node_module_struct {
  intversion;
 void *dso_handle;
 const char *filename;
 node::addon_register_func register_func;
 const char *modname;
};


在内建模块在定义之后,通过NODE_MODULE将模块定义到node命名空间中去:

#define NODE_MODULE(modname, regfunc)                                 \
 extern "C" {                                                       \
   NODE_MODULE_EXPORT node::node_module_struct modname ## _module =  \
   {                                                                \
     NODE_STANDARD_MODULE_STUFF,                                     \
     (node::addon_register_func)regfunc,                             \
     NODE_STRINGIFY(modname)                                         \
   };                                                               \
  }


简单点来讲就是将某个模块方法放到了node_module_struct的实例中的register_func成员中。这里一般是模块初始化方法。

在node_extensions.h中将那些内建模块统一放进了node_module_list的数组中。

NODE_EXT_LIST_START
NODE_EXT_LIST_ITEM(node_buffer)
#if H***E_OPENSSL
NODE_EXT_LIST_ITEM(node_crypto)
#endif
NODE_EXT_LIST_ITEM(node_evals)
NODE_EXT_LIST_ITEM(node_fs)
NODE_EXT_LIST_ITEM(node_http_parser)
NODE_EXT_LIST_ITEM(node_os)
NODE_EXT_LIST_ITEM(node_zlib)
 
// libuv rewrite
NODE_EXT_LIST_ITEM(node_timer_wrap)
NODE_EXT_LIST_ITEM(node_tcp_wrap)
NODE_EXT_LIST_ITEM(node_udp_wrap)
NODE_EXT_LIST_ITEM(node_pipe_wrap)
NODE_EXT_LIST_ITEM(node_cares_wrap)
NODE_EXT_LIST_ITEM(node_tty_wrap)
NODE_EXT_LIST_ITEM(node_process_wrap)
NODE_EXT_LIST_ITEM(node_fs_event_wrap)
NODE_EXT_LIST_ITEM(node_signal_wrap)
 
NODE_EXT_LIST_END




这样之后,就能够从node_module_list中取出我们想要的模块信息了。



在node启动时,会生成全局的process,并调用bind方法来加载内建模块。



static Handle<Value> Binding(constArguments& args) {
 HandleScope scope;
 
 Local<String> module = args[0]->ToString();
  node::Utf8Valuemodule_v(module);
 node_module_struct* modp;
 
  if(binding_cache.IsEmpty()) {
   binding_cache = Persistent<Object>::New(Object::New());
  }
 
 Local<Object> exports;
 
  if(binding_cache->Has(module)) {
   exports = binding_cache->Get(module)->ToObject();
   return scope.Close(exports);
  }
 
  //Append a string to process.moduleLoadList
 char buf[1024];
 snprintf(buf, 1024, "Binding %s", *module_v);
 uint32_t l = module_load_list->Length();
 module_load_list->Set(l, String::New(buf));
 
  if((modp = get_builtin_module(*module_v)) != NULL) {
   exports = Object::New();
   // Internal bindings don't have a "module" object,
   // only exports.
   modp->register_func(exports, Undefined());
   binding_cache->Set(module, exports);
 
  }else if (!strcmp(*module_v, "constants")) {
   exports = Object::New();
   DefineConstants(exports);
   binding_cache->Set(module, exports);
 
  }else if (!strcmp(*module_v, "natives")) {
   exports = Object::New();
   DefineJavaScript(exports);
    binding_cache->Set(module, exports);
 
  }else {
 
   return ThrowException(Exception::Error(String::New("No suchmodule")));
  }
 
 return scope.Close(exports);
}




创建了exports对象,然后调用get_builtin_module方法去获取内建对象,再使用register_func(就是NODE_MODULE中的第二个参数)去填充exports对象,然后缓存exports对象,并返回给调用方完成导出。这里register_func函数是比较重要的,它到底是个什么函数呢?

我们看看node_file.cc中的register_func:

NODE_MODULE(node_fs,node::InitFs)



node::InitFs函数

void InitFs(Handle<Object> target) {
 HandleScope scope;
  //Initialize the stats object
 Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
 stats_constructor_template =Persistent<FunctionTemplate>::New(stat_templ);
 target->Set(String::NewSymbol("Stats"),//由v8引擎完成添加方法
              stats_constructor_template->GetFunction());
 File::Initialize(target);
 
 oncomplete_sym = NODE_PSYMBOL("oncomplete");
 
 StatWatcher::Initialize(target);// 由 v8引擎完成添加方法
}




可以看到这里做的最主要的工作就是给传入的对象target添加各种各样的方法。比如:

NODE_SET_METHOD(target, "close",Close);
 NODE_SET_METHOD(target, "open", Open);
  NODE_SET_METHOD(target, "read",Read);
 NODE_SET_METHOD(target, "fdatasync", Fdatasync);
 NODE_SET_METHOD(target, "fsync", Fsync);
 NODE_SET_METHOD(target, "rename", Rename);
 NODE_SET_METHOD(target, "ftruncate", FTruncate);
 NODE_SET_METHOD(target, "rmdir", RMDir);
 NODE_SET_METHOD(target, "mkdir", MKDir);
 NODE_SET_METHOD(target, "readdir", ReadDir);
 NODE_SET_METHOD(target, "stat", Stat);
 NODE_SET_METHOD(target, "lstat", LStat);
 NODE_SET_METHOD(target, "fstat", FStat);
 NODE_SET_METHOD(target, "link", Link);
 NODE_SET_METHOD(target, "symlink", Symlink);
 NODE_SET_METHOD(target, "readlink", ReadLink);
 NODE_SET_METHOD(target, "unlink", Unlink);
 NODE_SET_METHOD(target, "write", Write);
 
 NODE_SET_METHOD(target, "chmod", Chmod);
 NODE_SET_METHOD(target, "fchmod", FChmod);
 //NODE_SET_METHOD(target, "lchmod", LChmod);
 
 NODE_SET_METHOD(target, "chown", Chown);
 NODE_SET_METHOD(target, "fchown", FChown);
 //NODE_SET_METHOD(target, "lchown", LChown);
 
 NODE_SET_METHOD(target, "utimes", UTimes);
 NODE_SET_METHOD(target, "futimes", FUTimes);




这样完成了c++方法挂载带了exports对象上,调用者就能够轻松调用了。后续的工作应该是要借助v8完成javascript调用c++。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐