node-ffi与用于访问现有C++功能的节点扩展

pan*_*ake 20 c++ node.js node-ffi node.js-addon

我有一些现有的C++代码,可以在独立的C++应用程序中进行数值处理.我现在想在新的node.js应用程序中使用该代码.

研究如何从node.js访问C++代码,有两个选项:

  1. 写一个node.js扩展名
  2. 使用node-ffi

node-ffi似乎是访问现有库的一个很好的选择,但我是否正确地思考如果我使用node-ffi我将不得不编写一个C包装器来使我的C++可访问?(这是我可以通过Visual Studio在Windows上使用简单的测试用例的唯一方法).

对于我的情况,我的源代码已经在C++中,而不是C,在上面两个选项之间选择有哪些注意事项?

kon*_*mer 23

FFI适用于动态C库.这意味着您必须在外部公开动态库.在C++中,您使用extern"C"执行此操作,如下所示:

#ifdef __cplusplus
extern "C" {
#endif

int foo (int param){
  int ret = 0;
  // do C++ things
  return ret;
}

int bar(){
  int ret = 0;
  // do C++ things
  return ret;
}

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

这将使您的C++函数可用作C-things,作为动态库方法.

在您将C++库编译为libmylibrary.dll/.so后,以下是如何在javascript中包装它:

var ffi = require('ffi');

var mylibrary = ffi.Library('libmylibrary', {
  "foo": [ "int", ["int"] ],
  "bar": [ "int", [] ]
});
Run Code Online (Sandbox Code Playgroud)

你可以做很多很酷的事情.看看,这里

如果这是一个节点库,只需将您的方法放在module.exports中.以下是上述C++代码包装的完整示例,包含同步和异步方法:

var ffi = require('ffi');

var mylibrary = ffi.Library('libmylibrary', {
  "foo": [ "int", ["int"] ],
  "bar": [ "int", [] ]
});

module.exports = {
  fooSync : mylibrary.foo,
  foo: mylibrary.foo.async,
  barSync : mylibrary.bar,
  bar: mylibrary.bar.async
};
Run Code Online (Sandbox Code Playgroud)

我没有使用node-ffi-generate,但是为你生成这些包装器看起来很酷.

如果我将此文件保存为mylibrary.js,我可以像这样使用它:

var mylib = require('./mylibrary.js');

var num = mylib.fooSync(1);

// or

mylib.foo(1, function(er, num){

});
Run Code Online (Sandbox Code Playgroud)

至于"它更好吗?"的问题.对大多数事情我都这么认为.如果你的方法是extern C,它们几乎可以用于所有其他语言,其中一些语言也有FFI,所以无论你的目标语言是什么,你都可以编写上述简单的等价语言.除了基本的"加载C++库"之外,这意味着维护的代码非常少,并且"感觉它的签名感觉适合语言X".它不是特定于节点的.另一个好处是常见的共享库(比如sqlite,在教程示例中给出.)您可能并不关心它们具有什么版本,或者想要用更多的C++代码包装它,需要编译它来使用它.使用FFI,您可以使用javascript包装预编译/安装的lib.

  • 但您可能需要考虑性能。如果您确实经常拨打电话,那么 FFI 的速度可能会更慢。这是详细的基准测试:https://bitbucket.org/juraf/node_ffi_vs_addon/src/master/ (2认同)