了解编写 Node.js 本机插件的工具
Understanding tools to write a Node.js native addon
我需要从一些现有的 C 代码创建一个 Node.js 本机插件,我发现有多种方法可以做到这一点:使用新的 N-API(或更简单的 C++ 本机插件 API) 或使用节点 FFI。另外,我不熟悉 node-gyp
等工具,我有一些问题可以帮助理解如何将 C 代码集成到我的 Node 应用程序中:
- N-API 和 Node FFI 之间是否有首选方法?我想两者各有优缺点,它们是什么?
- 是否需要使用
node-gyp
编译C代码?如果我已经有可用的库但未使用 node-gyp
(例如 .dylib
)编译并且我想在我的 Node 应用程序中使用它,我该怎么办?
在我看来,1 - N-API 是首选方法。它比 Node FFI 更快,并且是核心节点分布的一部分。 Node FFI 的主要优点(来自我的快速阅读;我还没有使用它)是它允许在不编写 c/c++ 代码的情况下进行调用。使用 N-API 还是 C++ 本机插件 API 更取决于您的偏好。 C++ API 确实删除了 N-API 所需的一些重复编码。但是,如果您不是一开始就使用 C++,那可能不是改变的好理由。
2 - 您不需要编译外部库。只需将它们放入 binding.gyp
文件的库部分,如下所示:
{
'targets': [{
'target_name': 'addon-name',
'cflags!': [ '-fno-exceptions' ],
'cflags_cc!': [ '-fno-exceptions' ],
'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'CLANG_CXX_LIBRARY': 'libc++',
'MACOSX_DEPLOYMENT_TARGET': '10.7',
},
'msvs_settings': {
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
},
'include_dirs': [
'<!@(node -p "require(\'node-addon-api\').include")',
],
'sources': [
'src/addon-name.cc'
],
'conditions': [
['OS in "linux"', {
'include_dirs': [
'<!@(node -p "require(\'node-addon-api\').include")',
'<(module_root_dir)/'
],
'libraries': [
'-ldylib',
'-L<(module_root_dir)/dylib/',
'-Wl,-rpath-link,<(module_root_dir)/dylib/',
'-Wl,-rpath,$$ORIGIN/../../dylib/'
],
}]
]
}]
}
bindings.gyp
的大部分样板文件是由 node-addon-api 包中的转换工具生成的。我包含了我自己的库部分,因为我随包分发了一个库,并弄清楚如何嵌入 $ORIGIN
因为文件的位置来之不易。因此,如果您计划分发该库,那么当它未安装在系统目录中时,这将为加载它提供一个良好的开端。
我需要从一些现有的 C 代码创建一个 Node.js 本机插件,我发现有多种方法可以做到这一点:使用新的 N-API(或更简单的 C++ 本机插件 API) 或使用节点 FFI。另外,我不熟悉 node-gyp
等工具,我有一些问题可以帮助理解如何将 C 代码集成到我的 Node 应用程序中:
- N-API 和 Node FFI 之间是否有首选方法?我想两者各有优缺点,它们是什么?
- 是否需要使用
node-gyp
编译C代码?如果我已经有可用的库但未使用node-gyp
(例如.dylib
)编译并且我想在我的 Node 应用程序中使用它,我该怎么办?
1 - N-API 是首选方法。它比 Node FFI 更快,并且是核心节点分布的一部分。 Node FFI 的主要优点(来自我的快速阅读;我还没有使用它)是它允许在不编写 c/c++ 代码的情况下进行调用。使用 N-API 还是 C++ 本机插件 API 更取决于您的偏好。 C++ API 确实删除了 N-API 所需的一些重复编码。但是,如果您不是一开始就使用 C++,那可能不是改变的好理由。
2 - 您不需要编译外部库。只需将它们放入 binding.gyp
文件的库部分,如下所示:
{
'targets': [{
'target_name': 'addon-name',
'cflags!': [ '-fno-exceptions' ],
'cflags_cc!': [ '-fno-exceptions' ],
'xcode_settings': { 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
'CLANG_CXX_LIBRARY': 'libc++',
'MACOSX_DEPLOYMENT_TARGET': '10.7',
},
'msvs_settings': {
'VCCLCompilerTool': { 'ExceptionHandling': 1 },
},
'include_dirs': [
'<!@(node -p "require(\'node-addon-api\').include")',
],
'sources': [
'src/addon-name.cc'
],
'conditions': [
['OS in "linux"', {
'include_dirs': [
'<!@(node -p "require(\'node-addon-api\').include")',
'<(module_root_dir)/'
],
'libraries': [
'-ldylib',
'-L<(module_root_dir)/dylib/',
'-Wl,-rpath-link,<(module_root_dir)/dylib/',
'-Wl,-rpath,$$ORIGIN/../../dylib/'
],
}]
]
}]
}
bindings.gyp
的大部分样板文件是由 node-addon-api 包中的转换工具生成的。我包含了我自己的库部分,因为我随包分发了一个库,并弄清楚如何嵌入 $ORIGIN
因为文件的位置来之不易。因此,如果您计划分发该库,那么当它未安装在系统目录中时,这将为加载它提供一个良好的开端。