title: Node.js 源码剖析 - 原生模块(C++模块)的注册
date: 2018-11-28 21:04:49
tags:
- Node.js- Node.js 源码剖析- 源码剖析
categories:
- Node.js 源码剖析
此文最后于四年前公布在集体站上的,现迁徙至此重发,原链接:https://laogen.site/nodejs/no...
《Node.js 源码剖析》 系列目录页:https://laogen.site/nodejs/no...
上一篇提到 RegisterBuiltinModules()
注册了原生 C++ 模块没有具体开展,这里就从这个函数开展。
<!-- more -->
将 RegisterBuiltinModules() 层层开展
/* src/node.cc:3066 */void RegisterBuiltinModules() {#define V(modname) _register_##modname(); NODE_BUILTIN_MODULES(V)#undef V}
首先定义了一个宏 V
为 _register_##modname()
, 能够看出 V
开展后是一个函数调用相似这样: _register_xx()
;
随后,RegisterBuiltinModules()
理论是宏 NODE_BUILTIN_MODULES(V)
来实现的,咱们看看它的定义:
/* src/node_internals.h:147 */#define NODE_BUILTIN_MODULES(V) \ NODE_BUILTIN_STANDARD_MODULES(V)// ...
进一步查看 NODE_BUILTIN_STANDARD_MODULES(V)
的定义:
/* src/node_internals.h:106 */#define NODE_BUILTIN_STANDARD_MODULES(V) \ V(async_wrap) \ V(buffer) \ V(cares_wrap) \ V(config) \ V(contextify) \ V(domain) \ V(fs) \ V(fs_event_wrap) \ V(heap_utils) \ V(http2) \ V(http_parser) \ V(inspector) \ V(js_stream) \ V(messaging) \ V(module_wrap) \ V(options) \ V(os) \ V(performance) \ V(pipe_wrap) \ V(process_wrap) \ V(serdes) \ V(signal_wrap) \ V(spawn_sync) \ V(stream_pipe) \ V(stream_wrap) \ V(string_decoder) \ V(symbols) \ V(tcp_wrap) \ V(timer_wrap) \ V(trace_events) \ V(tty_wrap) \ V(types) \ V(udp_wrap) \ V(url) \ V(util) \ V(uv) \ V(v8) \ V(worker) \ V(zlib)
这个宏定义中屡次调用宏 V
,还记得这个宏吗,在下面定义的:#define V(modname) _register_##modname();
,那咱们把它开展后就是:
/* src/node_internals.h:106 */#define NODE_BUILTIN_STANDARD_MODULES(V) \ _register_async_wrap(); _register_buffer(); _register_cares_wrap(); _register_config(); _register_contextify(); _register_domain(); _register_fs(); _register_fs_event_wrap(); _register_heap_utils(); _register_http2(); _register_http_parser(); _register_inspector(); _register_js_stream(); _register_messaging(); _register_module_wrap(); _register_options(); _register_os(); _register_performance(); _register_pipe_wrap(); _register_process_wrap(); _register_serdes(); _register_signal_wrap(); _register_spawn_sync(); _register_stream_pipe(); _register_stream_wrap(); _register_string_decoder(); _register_symbols(); _register_tcp_wrap(); _register_timer_wrap(); _register_trace_events(); _register_tty_wrap(); _register_types(); _register_udp_wrap(); _register_url(); _register_util(); _register_uv(); _register_v8(); _register_worker(); _register_zlib();
最终,RegisterBuiltinModules()
开展后大略是这样的:
void RegisterBuiltinModules() { _register_async_wrap(); _register_buffer(); // ... _register_os(); // ...}
通过层层的宏开展,咱们看到 RegisterBuiltinModules()
的原貌,就是调用了一些全局注册函数,这样就能了解了。
接下来,咱们打算看看这些注册函数是在哪里定义的。 我全局搜寻了整个代码目录,也没找到这些函数中的任何一个,看来又是通过宏定义的。
那咱们就挑一个原生模块的源码,来看看外面有没有下面注册函数的定义,我挑了模块名为 os
的模块,它的源码位于 src/node_os.cc
:
查看一个原生模块的源码
/* src/node_os.cc */namespace node {namespace os {// ...static void GetHostname(const FunctionCallbackInfo<Value>& args) { // ...}static void GetOSType(const FunctionCallbackInfo<Value>& args) { // ...}static void GetOSRelease(const FunctionCallbackInfo<Value>& args) { // ...}static void GetCPUInfo(const FunctionCallbackInfo<Value>& args) { // ...}static void GetFreeMemory(const FunctionCallbackInfo<Value>& args) { // ...}static void GetTotalMemory(const FunctionCallbackInfo<Value>& args) { // ...}static void GetUptime(const FunctionCallbackInfo<Value>& args) { // ...}static void GetLoadAvg(const FunctionCallbackInfo<Value>& args) { // ...}static void GetInterfaceAddresses(const FunctionCallbackInfo<Value>& args) { // ...}static void GetHomeDirectory(const FunctionCallbackInfo<Value>& args) { // ...}static void GetUserInfo(const FunctionCallbackInfo<Value>& args) { // ...}static void SetPriority(const FunctionCallbackInfo<Value>& args) { // ...}static void GetPriority(const FunctionCallbackInfo<Value>& args) { // ...}// 这个初始化函数是每个原生模块都会定义的,它的参数也是统一的void Initialize(Local<Object> target, Local<Value> unused, Local<Context> context) { Environment* env = Environment::GetCurrent(context); env->SetMethod(target, "getHostname", GetHostname); env->SetMethod(target, "getLoadAvg", GetLoadAvg); env->SetMethod(target, "getUptime", GetUptime); env->SetMethod(target, "getTotalMem", GetTotalMemory); env->SetMethod(target, "getFreeMem", GetFreeMemory); env->SetMethod(target, "getCPUs", GetCPUInfo); env->SetMethod(target, "getOSType", GetOSType); env->SetMethod(target, "getOSRelease", GetOSRelease); env->SetMethod(target, "getInterfaceAddresses", GetInterfaceAddresses); env->SetMethod(target, "getHomeDirectory", GetHomeDirectory); env->SetMethod(target, "getUserInfo", GetUserInfo); env->SetMethod(target, "setPriority", SetPriority); env->SetMethod(target, "getPriority", GetPriority); target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "isBigEndian"), Boolean::New(env->isolate(), IsBigEndian()));}} // namespace os} // namespace nodeNODE_BUILTIN_MODULE_CONTEXT_AWARE(os, node::os::Initialize)
这个 os
模块先是定义了一些函数,代码最初一行是个宏调用,这个宏把模块名 os
和 Initialize
函数做为其参数,咱们找到它的定义如下:
/* src/node_internals.h:169 */#define NODE_BUILTIN_MODULE_CONTEXT_AWARE(modname, regfunc) \ NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, nullptr, NM_F_BUILTIN)
又是一个宏定义,持续跟上来:
/* src/node_internals.h:152*/#define NODE_MODULE_CONTEXT_AWARE_CPP(modname, regfunc, priv, flags) \ static node::node_module _module = { \ NODE_MODULE_VERSION, \ flags, \ nullptr, \ __FILE__, \ nullptr, \ (node::addon_context_register_func) (regfunc), \ NODE_STRINGIFY(modname), \ priv, \ nullptr \ }; \ void _register_ ## modname() { \ node_module_register(&_module); \ }
这个宏的定义里如同看到了咱们要找的代码,咱们在这里就能够把 NODE_BUILTIN_MODULE_CONTEXT_AWARE(os, node::os::Initialize)
齐全开展了:
// 创立一个 node_module 对象 _modulestatic node::node_module _module = { NODE_MODULE_VERSION, NM_F_BUILTIN, nullptr, __FILE__, nullptr, (node::addon_context_register_func) (node::os::Initialize), NODE_STRINGIFY(os), nullptr, nullptr};// 定义咱们要找的 _register_os() 函数void _register_os() { node_module_register(&_module); }
到此,咱们就明确了 RegisterBuiltinModules()
函数中调用的 _register_os()
是在哪里定义的了,随后查看了所有原生模块的代码,最初一行都是以同样的形式定义相应的 _register_xx()
。
其中 node::node_module
类型就代表一个模块的信息。
所谓注册 os
模块理论是调用了 node_module_register(node_module *)
函数实现的,咱们持续来看看 node_module_register()
函数和 node::node_module
:
模块注册实现
/* src/node.h:518*/struct node_module { int nm_version; unsigned int nm_flags; void* nm_dso_handle; const char* nm_filename; // 上例中 Initialize 函数被赋到 nm_register_func 里 node::addon_register_func nm_register_func; node::addon_context_register_func nm_context_register_func; const char* nm_modname; // 模块的名字 void* nm_priv; struct node_module* nm_link; };
/* src/node.cc:1094 */extern "C" void node_module_register(void* m) { struct node_module* mp = reinterpret_cast<struct node_module*>(m); if (mp->nm_flags & NM_F_BUILTIN) { // 链表操作 mp->nm_link = modlist_builtin; modlist_builtin = mp; } else if (mp->nm_flags & NM_F_INTERNAL) { // 链表操作 mp->nm_link = modlist_internal; modlist_internal = mp; } else if (!node_is_initialized) { // "Linked" modules are included as part of the node project. // Like builtins they are registered *before* node::Init runs. mp->nm_flags = NM_F_LINKED; mp->nm_link = modlist_linked; modlist_linked = mp; } else { uv_key_set(&thread_local_modpending, mp); }}
到这里就清晰了, 所谓原生模块的注册,实际上就是将一个类型为 node::node_module
的模块对象,增加到不同类别的全局链表中。
上述代码中用3个全局链表:modlist_builtin
modlist_internal
modlist_linked
别离保留不同类型的模块,本文咱们说的是 BUILTIN
类型的,也就是第一个。
我把这几个链表的定义地位收回来:
/* src/node.cc:175 */static node_module* modlist_builtin; // 咱们当初只关注 builtin 模块static node_module* modlist_internal;static node_module* modlist_linked;static node_module* modlist_addon;
小结
这个原生模块的注册过程就写到这里,逻辑还是比较简单的,只是间断的宏定义让代码不那么直观。
原生模块加载写完后,接下来,会持续写原生模块的加载篇。
By Maslow (wangfugen@126.com), laf.js 作者。
lafyun.com 开源云开发平台,前端变全栈,无需服务端。