Swig を利用して、Ruby プログラムから C++ のテンプレートクラスを呼び出す
<要点>
- C++ のテンプレートクラスでは,ヘッダファイルに,クラス定義を全て書く
- swig を使うときは, swig ファイル中に 「template(IntTriple) Triple<int>;」のように書く。
【関連する外部ページ】 http://www.swig.org/Doc1.3/SWIGPlus.html
Swig を利用して、Ruby プログラムから C++ のテンプレートクラスを呼び出す例
- 作成する Ruby パッケージのライブラリファイル名: MyCPP.so
* Ruby ではMyCPP.so を読み込むために 「require 'MyCPP'」のように実行する - モジュール名: MyCPP
* Ruby では、クラス名の前に「MyCPP::」を付けることになる* モジュール名は大文字で始めることを推奨する.
- Ruby側からみた時のクラス名とメソッド名と、関数名の対応
C++ クラス名 C++ メソッド名 Ruby から見たメソッド名 Triple<int> Triple<int> MyCPP::IntTriple.new Triple<int> set_x MyCPP::IntTriple.set_x Triple<int> set_y MyCPP::IntTriple.set_y Triple<int> set_z MyCPP::IntTriple.set_z Triple<int> x MyCPP::IntTriple.x Triple<int> y MyCPP::IntTriple.y Triple<int> z MyCPP::IntTriple.z - パッケージ名: MyCPP
* パッケージ名は大文字で始めることを推奨する.
- C++ プログラムの作成
例えば、次のように triple.hpp を作成. C++ のテンプレートクラスでは,ヘッダファイルに,クラス定義を全て書くことに注意
template<class T> class Triple { private: T _x; T _y; T _z; public: Triple() {}; ~Triple() {}; void set_x( const T& arg ) { this->_x = arg; return; }; void set_y( const T& arg ) { this->_y = arg; return; }; void set_z( const T& arg ) { this->_z = arg; return; }; T x() { return this->_x; }; T y() { return this->_y; }; T z() { return this->_z; }; };
- triple.i の作成
モジュール名を MyCPP に設定している.
%module MyCPP %{ #include "triple.hpp" %} %include "triple.hpp" %template(IntTriple) Triple<int>;
- swig の実行
rm -f triple_wrap.* swig2.0 -ruby -c++ triple.i
- extconf.rb の作成
「create_makefile('MyCPP')」と記述しているので、MyCPP.so が生成されることになる
require 'mkmf' dir_config('triple') $libs += " -lstdc++ " if have_header('triple.hpp') create_makefile('MyCPP') end
- ビルド
ruby extconf.rb make CC=g++
nm で確認してみる
- インストール
sudo make site-install
- 使ってみる
irb require 'MyCPP' a = MyCPP::IntTriple.new a.set_x(1) a.set_y(2) a.set_z(3) a.x a.y a.z
C++ のヘッダファイルで namespace を使っている場合
Swig では C++ のヘッダファイル内の namespace は無視される(その結果、競合が起きる場合のために競合を避けるための機能もあります)。
- 作成する Ruby パッケージのライブラリファイル名: MyCPP.so
* Ruby ではMyCPP.so を読み込むために 「require 'MyCPP'」のように実行する - モジュール名: MyCPP
* Ruby では、クラス名の前に「MyCPP::」を付けることになる* モジュール名は大文字で始めることを推奨する.
- Ruby側からみた時のクラス名とメソッド名と、関数名の対応
C++ クラス名 C++ メソッド名 Ruby から見たメソッド名 hoge::Triple<int> Triple<int> MyCPP::IntTriple.new hoge::Triple<int> set_x MyCPP::IntTriple.set_x hoge::Triple<int> set_y MyCPP::IntTriple.set_y hoge::Triple<int> set_z MyCPP::IntTriple.set_z hoge::Triple<int> x MyCPP::IntTriple.x hoge::Triple<int> y MyCPP::IntTriple.y hoge::Triple<int> z MyCPP::IntTriple.z - パッケージ名: MyCPP
* パッケージ名は大文字で始めることを推奨する.
- C++ プログラムの作成
例えば、次のように triple.hpp を作成. C++ のテンプレートクラスでは,ヘッダファイルに,クラス定義を全て書くことに注意
namespace hoge { template<class T> class Triple { private: T _x; T _y; T _z; public: Triple() {}; ~Triple() {}; void set_x( const T& arg ) { this->_x = arg; return; }; void set_y( const T& arg ) { this->_y = arg; return; }; void set_z( const T& arg ) { this->_z = arg; return; }; T x() { return this->_x; }; T y() { return this->_y; }; T z() { return this->_z; }; }; }
- triple.i の作成
モジュール名を MyCPP に設定している.
%module MyCPP %{ #include "triple.hpp" %} %include "triple.hpp" %template(IntTriple) hoge::Triple<int>;
- swig の実行
rm -f triple_wrap.* swig2.0 -ruby -c++ triple.i
- extconf.rb の作成
「create_makefile('MyCPP')」と記述しているので、MyCPP.so が生成されることになる
require 'mkmf' dir_config('triple') $libs += " -lstdc++ " if have_header('triple.hpp') create_makefile('MyCPP') end
- ビルド
ruby extconf.rb make CC=g++
nm で確認してみる
- インストール
sudo make site-install
- 使ってみる
irb require 'MyCPP' a = MyCPP::IntTriple.new a.set_x(1) a.set_y(2) a.set_z(3) a.x a.y a.z