我正在从嵌入式系统的最新代码库构建NodeJS的自定义二进制文件。我有几个模块,我希望以二进制文件的形式发布 - 或者甚至运行自定义脚本,它被编译成二进制文件,可以通过命令行选项调用。
所以有两个问题:
1)我依稀记得节点允许在构建期间包含自定义模块,但我查看了最新的5.9.0配置脚本,我看不到任何相关内容 - 或者我可能错过了它。
2)有人已经做过类似的事吗?如果是,您提出的最佳做法是什么?
我不是在寻找像Electron或其他二进制捆绑器这样的东西,而是实际构建到节点二进制文件中。
谢谢,
安迪
答案 0 :(得分:0)
所以我想我想出来的速度要快得多。
对于其他任何人,您可以向其添加任何NPM模块,只需将实际源文件添加到node.gyp
配置文件中。
编译它并运行自定义二进制文件。它现在都在那里。
> var cmu = require("cmu");
undefined
> cmu
{ version: [Function] }
> cmu.version()
'It worked!'
> `
答案 1 :(得分:0)
经过一段时间的研究,我不得不说flyandi的答案并不完全正确。您只需将任何 NPM模块添加到node.gyp即可添加任何 NPM模块。
您只能以这种方式添加纯JavaScript模块。为了能够嵌入一个C ++模块(我故意不使用“native”这个词,因为在nodeJS术语中这个词很模糊 - 只需查看源代码)。
总结一下:
要将JS模块嵌入到自定义nodejs中,只需将其添加到node.gyp文件的library_files
部分即可。另请注意,它应放在lib文件夹中,否则您将遇到需要该模块的麻烦。这是因为node.gyp / library_files中列出的名称/路径用于在node_javascript.cc中间文件中编码模块的id,然后在搜索内置模块时使用该文件。
嵌入本机模块要困难得多。到目前为止,我发现的最好方法是将模块构建为静态库而不是动态库,对于基于cmake(-js)的模块,您可以通过将SHARED参数更改为STATIC来实现:
add_library(${PROJECT_NAME} STATIC ${SRC})
而不是:
add_library(${PROJECT_NAME} SHARED ${SRC})
还要更改后缀:
set_target_properties(
${PROJECT_NAME}
PROPERTIES
PREFIX ""
SUFFIX ".lib") /* instead of .node */
然后你可以通过添加以下部分从node.gyp链接它:
'link_settings': {
'libraries' : [
"path/to/my/library.lib",
#...add other static dependencies
],
},
(对于基于node-gyp的项目,如何做到这一点应该很容易谷歌)
这允许您构建模块,但您将无法满足它,因为节点中的require()函数只能用于加载内置JS模块,外部JS模块或外部动态节点模块。但现在我们有了一个内置的C ++模块。好吧,很多节点集成模块都是C ++,但它们总是在/lib
中有一个JS包装器,而那些包装器使用process.binding()
来加载C ++模块。也就是说,process.binding()
对于集成的C ++模块来说是一种require()
函数。
也就是说,我们还需要调用require.binding()
而不是要求加载我们的集成模块。为了能够做到这一点,我们必须首先使我们的模块“内置”。
我们可以通过替换
来做到这一点NODE_MODULE(mymodule, InitAll)
使用
输入模块定义NODE_BUILTIN_MODULE_CONTEXT_AWARE(mymodule, InitAll)
将其注册为内部模块,从现在开始我们可以process.binding()
。
请注意,NODE_BUILTIN_MODULE_CONTEXT_AWARE
中的node.h
未定义为NODE_MODULE
,而是node_internals.h
,因此您必须包含该{1}},或将宏定义复制到您的cpp文件(第一个当然更好,因为nodejs API往往会经常更改......)。
我们需要做的最后一件事是列出我们新集成的模块,以便节点知道初始化它们(包括它们在搜索加载了{{1}的模块时使用的模块列表中})。在node_internals.h中有这个宏:
process.binding()
所以只需将您的模块添加到列表中的方式与其他#define NODE_BUILTIN_STANDARD_MODULES(V) \
V(async_wrap) \
V(buffer) \
V(cares_wrap) \
...
相同。
我可能已经忘记了一些步骤,所以如果你认为我错过了什么,请在评论中提问。
如果你想知道为什么有人甚至想要这样做......你可以提出几个原因,但这对我来说是最重要的:那些包管理器用于将你的项目包装在一个可执行文件中(如pkg或nexe)仅适用于基于node-gyp的模块。如果您和我一样需要使用基于cmake的模块,那么最终的可执行文件将不起作用......