web-dev-qa-db-ja.com

node-ffiと既存のC ++機能にアクセスするためのノード拡張

スタンドアロンのC++アプリケーション内で数値処理を行う既存のC++コードがいくつかあります。そのコードを新しいnode.jsアプリケーション内で使用したいと思います。

Node.jsからC++コードにアクセスする方法を調べると、次の2つのオプションがあります。

  1. Node.js拡張機能を作成する
  2. node-ffi を使用します

node-ffiは既存のライブラリにアクセスするための良いオプションのようですが、node-ffiを使用する場合はCラッパーを作成する必要があると思いますか? C++にアクセスできるようにするには? (これは、Visual Studioを使用してWindowsで動作する簡単なテストケースを取得できる唯一の方法でした)。

ソースコードがすでにCではなくC++にある場合、上記の2つのオプションから選択する際の考慮事項は何ですか?

22
pancake

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-thingsで使用できるようになります。

C++ libを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){

});

「いいの?」という質問も。ほとんどの場合、そう思います。メソッドをexternCにすると、他のほぼすべての言語で機能し、その一部にはFFIも含まれているため、ターゲット言語が何であれ、上記と同等の単純なものを記述します。これは、基本的な「load C++ lib」と「言語Xに適していると感じるために署名をいじくり回す」ことを除いて、維持するコードがほとんどないことを意味します。ノードに固有のものではありません。もう1つのボーナスは、一般的な共有ライブラリ(チュートリアルの例で示されているsqliteなど)です。バージョンが何であるかを正確に気にしない場合や、使用するためにコンパイルする必要があるC++コードでラップしたい場合があります。 FFIを使用すると、プリコンパイル/インストールされたlibをjavascriptだけでラップできます。

25
konsumer