25

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

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

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

node-ffi 似乎是访问现有的好选择,但是我是否正确地认为如果我使用 node-ffi 我必须编写一个 C 包装器才能使我的 C++ 可访问?(这是我可以使用 Visual Studio 在 Windows 上获得简单测试用例的唯一方法)。

对于我的源代码已经是 C++ 而不是 C 的情况,在上述两个选项之间进行选择的考虑因素是什么?

4

1 回答 1

30

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

这将使您的 C++ 函数可用于 C 事物,作为动态库方法。

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

var ffi = require('ffi');

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

你可以做很多更酷的事情。看看这里

如果这是一个节点库,只需将您的方法放在 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
};

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

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

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

var num = mylib.fooSync(1);

// or

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

});

至于“更好吗?”的问题。我想是的,对于大多数事情。如果你让你的方法外部 C,它们几乎可以在所有其他语言中工作,其中一些也有 FFI,所以你可以用任何你的目标语言编写上面的简单等价物。这意味着需要维护的代码很少,除了基本的“加载 C++ 库”和“弄乱它的签名以感觉适合语言 X”。它不是特定于节点的。另一个好处是常见的共享库(如 sqlite,在教程示例中给出。)您可能并不关心他们拥有的确切版本,或者想要用更多 C++ 代码包装它,需要编译才能使用它。使用 FFI,您可以仅使用 javascript 包装预编译/安装的库。

于 2013-11-16T09:19:46.590 回答