Node.jsからC++の関数やクラスを扱いたいことがある。例えば、C++で書いたコードのGUIをElectronやNw.jsで書きたいときなど。
一般に、NodeからC++のコードを呼ぶ際は、Node-ffiが使われているようだ。しかしながら、チュートリアルを読んでみると、何やら書く気が雲散霧消してしまう面倒さである。
PythonやRubyからC/C++の関数を呼ぶバインディングの作成ツールとしては、SWIGが知られている。実はこのSWIGを使えば、Javascriptのラッパも手軽に書くことができる。
インストール
SWIGの安定版は3.0.12だが、これはNode 7以降に対応していない。Githubの開発版を使おう。なお、ライブラリのビルドにはNode-gypが必要なので、なければnpmからインストールする。
wget https://github.com/swig/swig/archive/master.zip
unzip master.zip
cd swig-master
./autogen.sh
./configure
make
sudo make install
ラッパを書く
練習に、次のコードをNodeから読んでみよう。
complex.hpp:
#include <string>
struct complex
{
complex(double r=0,double i=0);
double re;
double im;
double abs()const;
std::string to_str()const;
};
complex.cpp:
#include <cmath>
#include "complex.hpp"
complex::complex(double r,double i): re(r), im(i) {}
double complex::abs()const{ return std::sqrt(re*re+im*im); }
std::string complex::to_str()const{ return std::to_string(re)+"+"+std::to_string(im)+"i"; }
例えば、このコードが以下のJSから呼べたら素敵ではないだろうか。
complex.js:
const Complex=require('./complex.node').complex;
let z=new Complex();
console.log(z.abs()); // 0と表示してほしい
z.re=3;
z.im=4;
console.log(z.abs()); // 5と表示してほしい
console.log(z.to_str()); //3+4iのような表示を期待
SWIGを使えば、これだけのラッパを書くだけで良い。
complex.i:
%module complex // 外から見えるモジュールを定義
%{
#include "complex.hpp" // この中の関数が外から見える
%}
%include "std_string.i" // これを書いとけばいい感じにstd::stringをJSの文字列にラップしてくれる
%include "complex.hpp"
あとは、ビルド用にbinding.gypを書き、SWIGを実行してビルドするだけ。
binding.gyp:
{ "targets": [ {
"target_name": "complex",
"sources": [ "complex.cpp", "complex_wrap.cxx" ]
} ] }
実行する。
swig -javascript -node -c++ complex.i
node-gyp configure build
できたcomplex.nodeを適当な場所に移して、node complex.js
を実行すると……
0
5
3.000000+4.000000i
簡単!