July 01, 2009SWIGでiostreamを引数にとる関数のラップ(Rubyの場合)[Computer]
とあるC++プログラムをRubyから使いたいということになりました。こんな時はCまたはC++のプログラムを、スクリプト言語から呼び出せるよう、ほぼ全自動でラッパーを生成してくれるSWIGの出番です。このSWIGはかなり賢いので、そんじゅそこらのプログラムでしたら、2,3行のインターフェイスファイルを書くだけで、スクリプト言語とC/C++の間を取り持ってくれます。 まずはじめに、実装が完成した際のプログラムのコードが、こんなにもエレガントになるということを語らせてください(笑)。以下に例を示します。invoked.hがSWIGでラップされる側、invoker.rbがそれを呼び出すRubyのコードです。 // invoked.h
#include <iostream> struct InvokedCppClass { void stream_op(istream &in, ostream &out){ // read from in and write to out ... }; }; // invoker.rb
require 'invoked.so' invoked = Swig_Wrapped_Module::InvokedCppClass::new open(src_file){|src| open(dist_file, 'w'){|dist| invoked.stream_op(src, dist) } } Rubyの文法と融合しているのが素敵だと思いませんか? 少なくとも僕は満足しています(笑)。 このようにラップをするためには、残念ながらSWIGで水面下でバチャバチャする必要があります。基本方針としては、typemapで呼び出し時に自動的にRubyのIOオブジェクトがiostreamに変換されるようにすることです。そのために、iostreamを生成するのに必要となるstreambufを使ってRubyのIOオブジェクトをラップするクラスを作成しました。この主要な部分をインターフェイスファイルに記述した結果、arg_std_iostream.iのようになりました。 使い方としては以下のようなインターフェイスファイルを作成してSWIGで処理をします。 // invoked.i
%module Swig_Wrapped_Module %{ #include "invoked.h" %} %include arg_std_istream.i 確認した限りではファイルをストリームの元とする際は正常に動作しています。しかしcygwinのRubyにおいて、IO::pipeで作成したストリームでは読み書きするデータ量が多いとハングしてしまう問題を発見しました。おそらくcygwinならびにM$特有の問題だと思われるので、今回のコードが悪さをしているのではないと信じたいです。 またSWIGのRubyは多重継承を完全にはサポートしていないようで、ストリームはistreamまたはostream、すなわち読み書きのどちらか一方に絞る必要がありました。この記事のタイトルを正確に書くならば『...istreamまたはostreamを引数にとる...』ですね。 コメント
コメントする
|
スポンサード リンク
|