上一篇提到 RegisterBuiltinModules()
注册了原生 C++ 模块没有详细展开,这里就从这个函数展开。
将 RegisterBuiltinModules() 层层展开
1 | /* src/node.cc:3066 */ |
首先定义了一个宏 V
为 _register_##modname()
, 可以看出 V
展开后是一个函数调用类似这样: _register_xx()
;
随后,RegisterBuiltinModules()
实际是宏 NODE_BUILTIN_MODULES(V)
来实现的,我们看看它的定义:
1 | /* src/node_internals.h:147 */ |
进一步查看 NODE_BUILTIN_STANDARD_MODULES(V)
的定义:
1 | /* src/node_internals.h:106 */ |
这个宏定义中多次调用宏 V
,还记得这个宏吗,在上面定义的:#define V(modname) _register_##modname();
,那我们把它展开后就是:
1 | /* src/node_internals.h:106 */ |
最终,RegisterBuiltinModules()
展开后大概是这样的:
1 | void RegisterBuiltinModules() { |
经过层层的宏展开,我们看到 RegisterBuiltinModules()
的原貌,就是调用了一些全局注册函数,这样就能理解了。
接下来,我们打算看看这些注册函数是在哪里定义的。 我全局搜索了整个代码目录,也没找到这些函数中的任何一个,看来又是通过宏定义的。
那我们就挑一个原生模块的源码,来看看里面有没有上面注册函数的定义,我挑了模块名为 os
的模块,它的源码位于 src/node_os.cc
:
查看一个原生模块的源码
1 | /* src/node_os.cc */ |
这个 os
模块先是定义了一些函数,代码最后一行是个宏调用,这个宏把模块名 os
和 Initialize
函数做为其参数,我们找到它的定义如下:
1 | /* src/node_internals.h:169 */ |
又是一个宏定义,继续跟下去:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16/* src/node_internals.h:152*/
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_ #
node_module_register(&_module); \
}
这个宏的定义里好像看到了我们要找的代码,我们在这里就可以把 NODE_BUILTIN_MODULE_CONTEXT_AWARE(os, node::os::Initialize)
完全展开了:
1 | // 创建一个 node_module 对象 _module |
到此,我们就明白了 RegisterBuiltinModules()
函数中调用的 _register_os()
是在哪里定义的了,随后查看了所有原生模块的代码,最后一行都是以同样的方式定义相应的 _register_xx()
。
其中 node::node_module
类型就代表一个模块的信息。
所谓注册 os
模块实际是调用了 node_module_register(node_module *)
函数完成的,我们继续来看看 node_module_register()
函数和 node::node_module
:
模块注册实现
1 | /* src/node.h:518*/ |
1 | /* src/node.cc:1094 */ |
到这里就清晰了, 所谓原生模块的注册,实际上就是将一个类型为 node::node_module
的模块对象,添加到不同类别的全局链表中。
上述代码中用3个全局链表:modlist_builtin
modlist_internal
modlist_linked
分别保存不同类型的模块,本文我们说的是 BUILTIN
类型的,也就是第一个。
我把这几个链表的定义位置发出来:
1 | /* src/node.cc:175 */ |
小结
这个原生模块的注册过程就写到这里,逻辑还是比较简单的,只是连续的宏定义让代码不那么直观。
原生模块加载写完后,接下来,会继续写原生模块的加载篇。